From 9755fe80ee88803f2ecf7e86d7ae6d6fb8e25f55 Mon Sep 17 00:00:00 2001 From: Ali Raheem Date: Wed, 7 Aug 2019 15:59:18 +0100 Subject: [PATCH 01/55] Add fs::read_dir() and ReadDir warning about iterator order + example --- src/libstd/fs.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index f7c32a5c20d3d..2a55c79a93ce4 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -114,6 +114,11 @@ pub struct Metadata(fs_imp::FileAttr); /// information like the entry's path and possibly other metadata can be /// learned. /// +/// #### Note: Iteration Order is Implementation-Defined +/// +/// The order in which this iterator returns entries is platform and filesystem +/// dependent. +/// /// # Errors /// /// This [`io::Result`] will be an [`Err`] if there's some sort of intermittent @@ -1959,6 +1964,11 @@ pub fn remove_dir_all>(path: P) -> io::Result<()> { /// /// [changes]: ../io/index.html#platform-specific-behavior /// +/// #### Note: Iteration Order is Implementation-Defined +/// +/// The order in which this iterator returns entries is platform and filesystem +/// dependent. +/// /// # Errors /// /// This function will return an error in the following situations, but is not @@ -1991,6 +2001,28 @@ pub fn remove_dir_all>(path: P) -> io::Result<()> { /// Ok(()) /// } /// ``` +/// +/// ```rust,no_run +/// use std::{fs, io}; +/// +/// fn main() -> io::Result<()> { +/// // The order read_dir returns entries is not guaranteed. If reproducible +/// // ordering is required the entries should be explicitly sorted. +/// let mut entries = fs::read_dir(".")? +/// .map(|res| res.map(|e| e.path())) +/// .collect::, io::Error>>()?; +/// +/// println!( +/// "Entries before sorting (may or may not be sorted already): {:?}", +/// entries +/// ); +/// +/// entries.sort(); +/// +/// println!("Entries after sorting: {:?}", entries); +/// Ok(()) +/// } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn read_dir>(path: P) -> io::Result { fs_imp::readdir(path.as_ref()).map(ReadDir) From 8068812d042fa1bfb2133332152ee591705fdef7 Mon Sep 17 00:00:00 2001 From: Ali Raheem Date: Thu, 8 Aug 2019 15:33:39 +0100 Subject: [PATCH 02/55] Remove Iteration order heading --- src/libstd/fs.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 2a55c79a93ce4..ad279d7f754a6 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -114,8 +114,6 @@ pub struct Metadata(fs_imp::FileAttr); /// information like the entry's path and possibly other metadata can be /// learned. /// -/// #### Note: Iteration Order is Implementation-Defined -/// /// The order in which this iterator returns entries is platform and filesystem /// dependent. /// @@ -1964,8 +1962,6 @@ pub fn remove_dir_all>(path: P) -> io::Result<()> { /// /// [changes]: ../io/index.html#platform-specific-behavior /// -/// #### Note: Iteration Order is Implementation-Defined -/// /// The order in which this iterator returns entries is platform and filesystem /// dependent. /// From 53c504650dc6e51c45a256f56c92b872082d0642 Mon Sep 17 00:00:00 2001 From: Ali Raheem Date: Thu, 15 Aug 2019 10:53:29 +0100 Subject: [PATCH 03/55] Fix gramitcal error in read_dir example --- src/libstd/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index ad279d7f754a6..42ce044c5abe5 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -2002,7 +2002,7 @@ pub fn remove_dir_all>(path: P) -> io::Result<()> { /// use std::{fs, io}; /// /// fn main() -> io::Result<()> { -/// // The order read_dir returns entries is not guaranteed. If reproducible +/// // The order in which `read_dir` returns entries is not guaranteed. If reproducible /// // ordering is required the entries should be explicitly sorted. /// let mut entries = fs::read_dir(".")? /// .map(|res| res.map(|e| e.path())) From 3c820fef9fafca1f25da37274aea683b9e341339 Mon Sep 17 00:00:00 2001 From: Ali Raheem Date: Mon, 26 Aug 2019 11:24:08 +0100 Subject: [PATCH 04/55] Comment out println in read_dir sorting example --- src/libstd/fs.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 42ce044c5abe5..689c50c6b80fa 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -2008,14 +2008,14 @@ pub fn remove_dir_all>(path: P) -> io::Result<()> { /// .map(|res| res.map(|e| e.path())) /// .collect::, io::Error>>()?; /// -/// println!( -/// "Entries before sorting (may or may not be sorted already): {:?}", -/// entries -/// ); +/// // println!( +/// // "Entries before sorting (may or may not be sorted already): {:?}", +/// // entries +/// // ); /// /// entries.sort(); /// -/// println!("Entries after sorting: {:?}", entries); +/// // println!("Entries after sorting: {:?}", entries); /// Ok(()) /// } /// ``` From 4dd4da97175b1c6cf15fc9505ec8f8afdaf71a24 Mon Sep 17 00:00:00 2001 From: Baoshan Pang Date: Fri, 30 Aug 2019 13:44:38 -0700 Subject: [PATCH 05/55] remove directory libstd/sys/vxworks/backtrace which is not used any more --- src/libstd/sys/vxworks/backtrace/mod.rs | 110 ------------------ .../sys/vxworks/backtrace/printing/dladdr.rs | 35 ------ .../sys/vxworks/backtrace/printing/mod.rs | 33 ------ .../vxworks/backtrace/tracing/backtrace_fn.rs | 39 ------- .../sys/vxworks/backtrace/tracing/gcc_s.rs | 99 ---------------- .../sys/vxworks/backtrace/tracing/mod.rs | 8 -- 6 files changed, 324 deletions(-) delete mode 100644 src/libstd/sys/vxworks/backtrace/mod.rs delete mode 100644 src/libstd/sys/vxworks/backtrace/printing/dladdr.rs delete mode 100644 src/libstd/sys/vxworks/backtrace/printing/mod.rs delete mode 100644 src/libstd/sys/vxworks/backtrace/tracing/backtrace_fn.rs delete mode 100644 src/libstd/sys/vxworks/backtrace/tracing/gcc_s.rs delete mode 100644 src/libstd/sys/vxworks/backtrace/tracing/mod.rs diff --git a/src/libstd/sys/vxworks/backtrace/mod.rs b/src/libstd/sys/vxworks/backtrace/mod.rs deleted file mode 100644 index 0887e5a4df937..0000000000000 --- a/src/libstd/sys/vxworks/backtrace/mod.rs +++ /dev/null @@ -1,110 +0,0 @@ -/// Backtrace support built on libgcc with some extra OS-specific support -/// -/// Some methods of getting a backtrace: -/// -/// * The backtrace() functions on unix. It turns out this doesn't work very -/// well for green threads on macOS, and the address to symbol portion of it -/// suffers problems that are described below. -/// -/// * Using libunwind. This is more difficult than it sounds because libunwind -/// isn't installed everywhere by default. It's also a bit of a hefty library, -/// so possibly not the best option. When testing, libunwind was excellent at -/// getting both accurate backtraces and accurate symbols across platforms. -/// This route was not chosen in favor of the next option, however. -/// -/// * We're already using libgcc_s for exceptions in rust (triggering thread -/// unwinding and running destructors on the stack), and it turns out that it -/// conveniently comes with a function that also gives us a backtrace. All of -/// these functions look like _Unwind_*, but it's not quite the full -/// repertoire of the libunwind API. Due to it already being in use, this was -/// the chosen route of getting a backtrace. -/// -/// After choosing libgcc_s for backtraces, the sad part is that it will only -/// give us a stack trace of instruction pointers. Thankfully these instruction -/// pointers are accurate (they work for green and native threads), but it's -/// then up to us again to figure out how to translate these addresses to -/// symbols. As with before, we have a few options. Before, that, a little bit -/// of an interlude about symbols. This is my very limited knowledge about -/// symbol tables, and this information is likely slightly wrong, but the -/// general idea should be correct. -/// -/// When talking about symbols, it's helpful to know a few things about where -/// symbols are located. Some symbols are located in the dynamic symbol table -/// of the executable which in theory means that they're available for dynamic -/// linking and lookup. Other symbols end up only in the local symbol table of -/// the file. This loosely corresponds to pub and priv functions in Rust. -/// -/// Armed with this knowledge, we know that our solution for address to symbol -/// translation will need to consult both the local and dynamic symbol tables. -/// With that in mind, here's our options of translating an address to -/// a symbol. -/// -/// * Use dladdr(). The original backtrace()-based idea actually uses dladdr() -/// behind the scenes to translate, and this is why backtrace() was not used. -/// Conveniently, this method works fantastically on macOS. It appears dladdr() -/// uses magic to consult the local symbol table, or we're putting everything -/// in the dynamic symbol table anyway. Regardless, for macOS, this is the -/// method used for translation. It's provided by the system and easy to do.o -/// -/// Sadly, all other systems have a dladdr() implementation that does not -/// consult the local symbol table. This means that most functions are blank -/// because they don't have symbols. This means that we need another solution. -/// -/// * Use unw_get_proc_name(). This is part of the libunwind api (not the -/// libgcc_s version of the libunwind api), but involves taking a dependency -/// to libunwind. We may pursue this route in the future if we bundle -/// libunwind, but libunwind was unwieldy enough that it was not chosen at -/// this time to provide this functionality. -/// -/// * Shell out to a utility like `readelf`. Crazy though it may sound, it's a -/// semi-reasonable solution. The stdlib already knows how to spawn processes, -/// so in theory it could invoke readelf, parse the output, and consult the -/// local/dynamic symbol tables from there. This ended up not getting chosen -/// due to the craziness of the idea plus the advent of the next option. -/// -/// * Use `libbacktrace`. It turns out that this is a small library bundled in -/// the gcc repository which provides backtrace and symbol translation -/// functionality. All we really need from it is the backtrace functionality, -/// and we only really need this on everything that's not macOS, so this is the -/// chosen route for now. -/// -/// In summary, the current situation uses libgcc_s to get a trace of stack -/// pointers, and we use dladdr() or libbacktrace to translate these addresses -/// to symbols. This is a bit of a hokey implementation as-is, but it works for -/// all unix platforms we support right now, so it at least gets the job done. - -pub use self::tracing::unwind_backtrace; -pub use self::printing::{foreach_symbol_fileline, resolve_symname}; - -// tracing impls: -mod tracing; -// symbol resolvers: -mod printing; - -#[cfg(not(target_os = "emscripten"))] -pub mod gnu { - use crate::io; - use crate::fs; - - use libc::c_char; - - #[cfg(not(any(target_os = "macos", target_os = "ios")))] - pub fn get_executable_filename() -> io::Result<(Vec, fs::File)> { - Err(io::Error::new(io::ErrorKind::Other, "Not implemented")) - } - - #[cfg(any(target_os = "macos", target_os = "ios"))] - pub fn get_executable_filename() -> io::Result<(Vec, fs::File)> { - use crate::env; - use crate::os::unix::ffi::OsStrExt; - - let filename = env::current_exe()?; - let file = fs::File::open(&filename)?; - let mut filename_cstr: Vec<_> = filename.as_os_str().as_bytes().iter() - .map(|&x| x as c_char).collect(); - filename_cstr.push(0); // Null terminate - Ok((filename_cstr, file)) - } -} - -pub struct BacktraceContext; diff --git a/src/libstd/sys/vxworks/backtrace/printing/dladdr.rs b/src/libstd/sys/vxworks/backtrace/printing/dladdr.rs deleted file mode 100644 index 202164dd3c4d7..0000000000000 --- a/src/libstd/sys/vxworks/backtrace/printing/dladdr.rs +++ /dev/null @@ -1,35 +0,0 @@ -use crate::io; -use crate::intrinsics; -use crate::ffi::CStr; -use crate::sys::backtrace::BacktraceContext; -use crate::sys_common::backtrace::Frame; - -pub fn resolve_symname(frame: Frame, - callback: F, - _: &BacktraceContext) -> io::Result<()> - where F: FnOnce(Option<&str>) -> io::Result<()> -{ - unsafe { - let mut info: Dl_info = intrinsics::init(); - let symname = if dladdr(frame.exact_position as *mut _, &mut info) == 0 || - info.dli_sname.is_null() { - None - } else { - CStr::from_ptr(info.dli_sname).to_str().ok() - }; - callback(symname) - } -} - -#[repr(C)] -struct Dl_info { - dli_fname: *const libc::c_char, - dli_fbase: *mut libc::c_void, - dli_sname: *const libc::c_char, - dli_saddr: *mut libc::c_void, -} - -extern { - #[ link_name = "_rtld_dladdr" ] - fn dladdr(addr: *const libc::c_void, info: *mut Dl_info) -> libc::c_int; -} diff --git a/src/libstd/sys/vxworks/backtrace/printing/mod.rs b/src/libstd/sys/vxworks/backtrace/printing/mod.rs deleted file mode 100644 index d090caede437a..0000000000000 --- a/src/libstd/sys/vxworks/backtrace/printing/mod.rs +++ /dev/null @@ -1,33 +0,0 @@ -mod dladdr; - -use crate::sys::backtrace::BacktraceContext; -use crate::sys_common::backtrace::Frame; -use crate::io; - -#[cfg(target_os = "emscripten")] -pub use self::dladdr::resolve_symname; - -#[cfg(target_os = "emscripten")] -pub fn foreach_symbol_fileline(_: Frame, _: F, _: &BacktraceContext) -> io::Result -where - F: FnMut(&[u8], u32) -> io::Result<()> -{ - Ok(false) -} - -#[cfg(not(target_os = "emscripten"))] -pub use crate::sys_common::gnu::libbacktrace::foreach_symbol_fileline; - -#[cfg(not(target_os = "emscripten"))] -pub fn resolve_symname(frame: Frame, callback: F, bc: &BacktraceContext) -> io::Result<()> -where - F: FnOnce(Option<&str>) -> io::Result<()> -{ - crate::sys_common::gnu::libbacktrace::resolve_symname(frame, |symname| { - if symname.is_some() { - callback(symname) - } else { - dladdr::resolve_symname(frame, callback, bc) - } - }, bc) -} diff --git a/src/libstd/sys/vxworks/backtrace/tracing/backtrace_fn.rs b/src/libstd/sys/vxworks/backtrace/tracing/backtrace_fn.rs deleted file mode 100644 index a628d107ad6fb..0000000000000 --- a/src/libstd/sys/vxworks/backtrace/tracing/backtrace_fn.rs +++ /dev/null @@ -1,39 +0,0 @@ -/// As always - iOS on arm uses SjLj exceptions and -/// _Unwind_Backtrace is even not available there. Still, -/// backtraces could be extracted using a backtrace function, -/// which thanks god is public -/// -/// As mentioned in a huge comment block in `super::super`, backtrace -/// doesn't play well with green threads, so while it is extremely nice and -/// simple to use it should be used only on iOS devices as the only viable -/// option. - -use crate::io; -use crate::ptr; -use crate::sys::backtrace::BacktraceContext; -use crate::sys_common::backtrace::Frame; - -#[inline(never)] // if we know this is a function call, we can skip it when - // tracing -pub fn unwind_backtrace(frames: &mut [Frame]) - -> io::Result<(usize, BacktraceContext)> -{ - const FRAME_LEN: usize = 100; - assert!(FRAME_LEN >= frames.len()); - let mut raw_frames = [ptr::null_mut(); FRAME_LEN]; - let nb_frames = unsafe { - backtrace(raw_frames.as_mut_ptr(), raw_frames.len() as libc::c_int) - } as usize; - for (from, to) in raw_frames.iter().zip(frames.iter_mut()).take(nb_frames) { - *to = Frame { - exact_position: *from as *mut u8, - symbol_addr: *from as *mut u8, - inline_context: 0, - }; - } - Ok((nb_frames as usize, BacktraceContext)) -} - -extern { - fn backtrace(buf: *mut *mut libc::c_void, sz: libc::c_int) -> libc::c_int; -} diff --git a/src/libstd/sys/vxworks/backtrace/tracing/gcc_s.rs b/src/libstd/sys/vxworks/backtrace/tracing/gcc_s.rs deleted file mode 100644 index e6379132bafbe..0000000000000 --- a/src/libstd/sys/vxworks/backtrace/tracing/gcc_s.rs +++ /dev/null @@ -1,99 +0,0 @@ -use crate::error::Error; -use crate::fmt; -use crate::io; -use crate::sys::backtrace::BacktraceContext; -use crate::sys_common::backtrace::Frame; - -use unwind as uw; - -struct Context<'a> { - idx: usize, - frames: &'a mut [Frame], -} - -#[derive(Debug)] -struct UnwindError(uw::_Unwind_Reason_Code); - -impl Error for UnwindError { - fn description(&self) -> &'static str { - "unexpected return value while unwinding" - } -} - -impl fmt::Display for UnwindError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}: {:?}", self.description(), self.0) - } -} - -#[inline(never)] // if we know this is a function call, we can skip it when - // tracing -pub fn unwind_backtrace(frames: &mut [Frame]) - -> io::Result<(usize, BacktraceContext)> -{ - let mut cx = Context { - idx: 0, - frames, - }; - let result_unwind = unsafe { - uw::_Unwind_Backtrace(trace_fn, - &mut cx as *mut Context<'_> - as *mut libc::c_void) - }; - // See libunwind:src/unwind/Backtrace.c for the return values. - // No, there is no doc. - match result_unwind { - // These return codes seem to be benign and need to be ignored for backtraces - // to show up properly on all tested platforms. - uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => { - Ok((cx.idx, BacktraceContext)) - } - _ => { - Err(io::Error::new(io::ErrorKind::Other, - UnwindError(result_unwind))) - } - } -} - -extern fn trace_fn(ctx: *mut uw::_Unwind_Context, - arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code { - let cx = unsafe { &mut *(arg as *mut Context<'_>) }; - if cx.idx >= cx.frames.len() { - return uw::_URC_NORMAL_STOP; - } - - let mut ip_before_insn = 0; - let mut ip = unsafe { - uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void - }; - if !ip.is_null() && ip_before_insn == 0 { - // this is a non-signaling frame, so `ip` refers to the address - // after the calling instruction. account for that. - ip = (ip as usize - 1) as *mut _; - } - - // dladdr() on osx gets whiny when we use FindEnclosingFunction, and - // it appears to work fine without it, so we only use - // FindEnclosingFunction on non-osx platforms. In doing so, we get a - // slightly more accurate stack trace in the process. - // - // This is often because panic involves the last instruction of a - // function being "call std::rt::begin_unwind", with no ret - // instructions after it. This means that the return instruction - // pointer points *outside* of the calling function, and by - // unwinding it we go back to the original function. - let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") { - ip - } else { - unsafe { uw::_Unwind_FindEnclosingFunction(ip) } - }; - - cx.frames[cx.idx] = Frame { - symbol_addr: symaddr as *mut u8, - exact_position: ip as *mut u8, - inline_context: 0, - }; - cx.idx += 1; - - uw::_URC_NO_REASON -} diff --git a/src/libstd/sys/vxworks/backtrace/tracing/mod.rs b/src/libstd/sys/vxworks/backtrace/tracing/mod.rs deleted file mode 100644 index 11863e6454525..0000000000000 --- a/src/libstd/sys/vxworks/backtrace/tracing/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub use self::imp::*; - -#[cfg(not(all(target_os = "ios", target_arch = "arm")))] -#[path = "gcc_s.rs"] -mod imp; -#[cfg(all(target_os = "ios", target_arch = "arm"))] -#[path = "backtrace_fn.rs"] -mod imp; From d61605cef866008a19e33eb596df1d76ff1571f3 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 30 Aug 2019 09:03:58 +1000 Subject: [PATCH 06/55] Don't call `self.parse()` in `Compiler::crate_name()` unless necessary. --- src/librustc_interface/queries.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/librustc_interface/queries.rs b/src/librustc_interface/queries.rs index ed50dadb60099..996e9fae0db56 100644 --- a/src/librustc_interface/queries.rs +++ b/src/librustc_interface/queries.rs @@ -126,17 +126,18 @@ impl Compiler { pub fn crate_name(&self) -> Result<&Query> { self.queries.crate_name.compute(|| { - let parse_result = self.parse()?; - let krate = parse_result.peek(); - let result = match self.crate_name { + Ok(match self.crate_name { Some(ref crate_name) => crate_name.clone(), - None => rustc_codegen_utils::link::find_crate_name( - Some(self.session()), - &krate.attrs, - &self.input - ), - }; - Ok(result) + None => { + let parse_result = self.parse()?; + let krate = parse_result.peek(); + rustc_codegen_utils::link::find_crate_name( + Some(self.session()), + &krate.attrs, + &self.input + ) + } + }) }) } From cd0c21b0e5b68e29c63c3c98db9147cb0e5a3bc8 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 30 Aug 2019 16:24:01 +1000 Subject: [PATCH 07/55] Remove `lower_to_hir()` call from `prepare_output()`. It's a false dependency. The result isn't used and there are no relevant side-effects. --- src/librustc_interface/queries.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc_interface/queries.rs b/src/librustc_interface/queries.rs index 996e9fae0db56..c281bc5360704 100644 --- a/src/librustc_interface/queries.rs +++ b/src/librustc_interface/queries.rs @@ -195,7 +195,6 @@ impl Compiler { pub fn prepare_outputs(&self) -> Result<&Query> { self.queries.prepare_outputs.compute(|| { - self.lower_to_hir()?; let krate = self.expansion()?; let krate = krate.peek(); let crate_name = self.crate_name()?; From 91fd8efd265b60a635aff89d1c2d0a8aea45fdf9 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Mon, 9 Sep 2019 08:02:26 +1000 Subject: [PATCH 08/55] document the unstable iter_order_by library feature --- src/doc/unstable-book/src/iter-order-by.md | 9 +++++++++ src/libcore/iter/traits/iterator.rs | 6 +++--- 2 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 src/doc/unstable-book/src/iter-order-by.md diff --git a/src/doc/unstable-book/src/iter-order-by.md b/src/doc/unstable-book/src/iter-order-by.md new file mode 100644 index 0000000000000..1ed97872c881c --- /dev/null +++ b/src/doc/unstable-book/src/iter-order-by.md @@ -0,0 +1,9 @@ +# `iter_order_by` + +The tracking issue for this feature is: [#64295] + +[#64295]: https://github.com/rust-lang/rust/issues/64295 + +------------------------ + +Add `cmp_by`, `partial_cmp_by` and `eq_by` methods to `Iterator` in the same vein as `max_by` and `min_by`. diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs index c09df3f7f22cb..266f1e6a78102 100644 --- a/src/libcore/iter/traits/iterator.rs +++ b/src/libcore/iter/traits/iterator.rs @@ -2585,7 +2585,7 @@ pub trait Iterator { /// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| (x * x).cmp(&y)), Ordering::Equal); /// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| (2 * x).cmp(&y)), Ordering::Greater); /// ``` - #[unstable(feature = "iter_order_by", issue = "0")] + #[unstable(feature = "iter_order_by", issue = "64295")] fn cmp_by(mut self, other: I, mut cmp: F) -> Ordering where Self: Sized, @@ -2668,7 +2668,7 @@ pub trait Iterator { /// Some(Ordering::Greater) /// ); /// ``` - #[unstable(feature = "iter_order_by", issue = "0")] + #[unstable(feature = "iter_order_by", issue = "64295")] fn partial_cmp_by(mut self, other: I, mut partial_cmp: F) -> Option where Self: Sized, @@ -2733,7 +2733,7 @@ pub trait Iterator { /// /// assert!(xs.iter().eq_by(&ys, |&x, &y| x * x == y)); /// ``` - #[unstable(feature = "iter_order_by", issue = "0")] + #[unstable(feature = "iter_order_by", issue = "64295")] fn eq_by(mut self, other: I, mut eq: F) -> bool where Self: Sized, From 1161aeb2b423da744e687315648a49cc4774220b Mon Sep 17 00:00:00 2001 From: Ali Raheem Date: Mon, 9 Sep 2019 20:38:21 +0100 Subject: [PATCH 09/55] Replace println statements with explanatory comments --- src/libstd/fs.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 689c50c6b80fa..246587b4233cd 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -2002,20 +2002,17 @@ pub fn remove_dir_all>(path: P) -> io::Result<()> { /// use std::{fs, io}; /// /// fn main() -> io::Result<()> { -/// // The order in which `read_dir` returns entries is not guaranteed. If reproducible -/// // ordering is required the entries should be explicitly sorted. /// let mut entries = fs::read_dir(".")? /// .map(|res| res.map(|e| e.path())) /// .collect::, io::Error>>()?; /// -/// // println!( -/// // "Entries before sorting (may or may not be sorted already): {:?}", -/// // entries -/// // ); +/// // The order in which `read_dir` returns entries is not guaranteed. If reproducible +/// // ordering is required the entries should be explicitly sorted. /// /// entries.sort(); /// -/// // println!("Entries after sorting: {:?}", entries); +/// // The entries have now been sorted by their path. +/// /// Ok(()) /// } /// ``` From d264a56068d7fd881b2e082c4d80d81d22c4ce79 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 30 Aug 2019 16:53:34 +1000 Subject: [PATCH 10/55] Move call site of `dep_graph_future()`. `Compiler::register_plugins()` calls `passes::register_plugins()`, which calls `Compiler::dep_graph_future()`. This is the only way in which a `passes` function calls a `Compiler` function. This commit moves the `dep_graph_future()` call out of `passes::register_plugins()` and into `Compiler::register_plugins()`, which is a more sensible spot for it. This will delay the loading of the dep graph slightly -- from the middle of plugin registration to the end of plugin registration -- but plugin registration is fast enough (especially compared to expansion) that the impact should be neglible. --- src/librustc_interface/passes.rs | 4 ---- src/librustc_interface/queries.rs | 14 +++++++++++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 24b44964e4fd2..200da05c57561 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -223,7 +223,6 @@ pub struct PluginInfo { } pub fn register_plugins<'a>( - compiler: &Compiler, sess: &'a Session, cstore: &'a CStore, mut krate: ast::Crate, @@ -261,9 +260,6 @@ pub fn register_plugins<'a>( }); } - // If necessary, compute the dependency graph (in the background). - compiler.dep_graph_future().ok(); - time(sess, "recursion limit", || { middle::recursion_limit::update_limits(sess, &krate); }); diff --git a/src/librustc_interface/queries.rs b/src/librustc_interface/queries.rs index c281bc5360704..e056d3feb66ec 100644 --- a/src/librustc_interface/queries.rs +++ b/src/librustc_interface/queries.rs @@ -114,13 +114,21 @@ impl Compiler { let crate_name = self.crate_name()?.peek().clone(); let krate = self.parse()?.take(); - passes::register_plugins( - self, + let result = passes::register_plugins( self.session(), self.cstore(), krate, &crate_name, - ) + ); + + // Compute the dependency graph (in the background). We want to do + // this as early as possible, to give the DepGraph maximum time to + // load before dep_graph() is called, but it also can't happen + // until after rustc_incremental::prepare_session_directory() is + // called, which happens within passes::register_plugins(). + self.dep_graph_future().ok(); + + result }) } From 04b27efa00799f984b7ebc50d37a2d571db9235f Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 12 Sep 2019 19:59:14 -0400 Subject: [PATCH 11/55] Move to print functions on types instead of impl fmt::Display This will eventually allow us to easily pass in more parameters to the functions without TLS or other such hacks --- src/librustdoc/clean/mod.rs | 14 +- src/librustdoc/html/format.rs | 881 ++++++++++-------- src/librustdoc/html/item_type.rs | 39 +- src/librustdoc/html/render.rs | 127 +-- .../passes/calculate_doc_coverage.rs | 7 +- .../passes/collect_intra_doc_links.rs | 2 +- src/librustdoc/passes/mod.rs | 4 +- src/librustdoc/passes/strip_hidden.rs | 2 +- 8 files changed, 553 insertions(+), 523 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index ae70fdc530be6..10c4231b82eeb 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1849,7 +1849,7 @@ fn get_real_types( cx: &DocContext<'_>, recurse: i32, ) -> FxHashSet { - let arg_s = arg.to_string(); + let arg_s = arg.print().to_string(); let mut res = FxHashSet::default(); if recurse >= 10 { // FIXME: remove this whole recurse thing when the recursion bug is fixed return res; @@ -3573,16 +3573,6 @@ pub enum GenericArg { Const(Constant), } -impl fmt::Display for GenericArg { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - GenericArg::Lifetime(lt) => lt.fmt(f), - GenericArg::Type(ty) => ty.fmt(f), - GenericArg::Const(ct) => ct.fmt(f), - } - } -} - #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum GenericArgs { AngleBracketed { @@ -4274,7 +4264,7 @@ fn resolve_type(cx: &DocContext<'_>, return Generic(kw::SelfUpper.to_string()); } Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => { - return Generic(format!("{:#}", path)); + return Generic(format!("{:#}", path.print())); } Res::SelfTy(..) | Res::Def(DefKind::TyParam, _) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index dcd32192ff384..9baa69d981b52 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -99,10 +99,6 @@ impl Buffer { self.into_inner() } - crate fn with_formatter) -> fmt::Result>(&mut self, t: T) { - self.from_display(display_fn(move |f| (t)(f))); - } - crate fn from_display(&mut self, t: T) { if self.for_html { write!(self, "{}", t); @@ -131,8 +127,6 @@ pub struct AsyncSpace(pub hir::IsAsync); /// Similar to VisSpace, but used for mutability #[derive(Copy, Clone)] pub struct MutableSpace(pub clean::Mutability); -/// Wrapper struct for emitting type parameter bounds. -pub struct GenericBounds<'a>(pub &'a [clean::GenericBound]); pub struct AbiSpace(pub Abi); pub struct DefaultSpace(pub bool); @@ -161,102 +155,89 @@ pub struct WhereClause<'a>{ pub end_newline: bool, } -impl<'a> VisSpace<'a> { - pub fn get(self) -> &'a Option { - let VisSpace(v) = self; v - } -} - -impl UnsafetySpace { - pub fn get(&self) -> hir::Unsafety { - let UnsafetySpace(v) = *self; v - } -} - -impl ConstnessSpace { - pub fn get(&self) -> hir::Constness { - let ConstnessSpace(v) = *self; v - } -} - -fn comma_sep(items: &[T]) -> impl fmt::Display + '_ { +fn comma_sep(items: impl Iterator) -> impl fmt::Display { display_fn(move |f| { - for (i, item) in items.iter().enumerate() { + for (i, item) in items.enumerate() { if i != 0 { write!(f, ", ")?; } - fmt::Display::fmt(item, f)?; + fmt::Display::fmt(&item, f)?; } Ok(()) }) } -impl<'a> fmt::Display for GenericBounds<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +crate fn print_generic_bounds(bounds: &[clean::GenericBound]) -> impl fmt::Display + '_ { + display_fn(move |f| { let mut bounds_dup = FxHashSet::default(); - let &GenericBounds(bounds) = self; - for (i, bound) in bounds.iter().filter(|b| bounds_dup.insert(b.to_string())).enumerate() { + for (i, bound) in bounds.iter().filter(|b| { + bounds_dup.insert(b.print().to_string()) + }).enumerate() { if i > 0 { f.write_str(" + ")?; } - fmt::Display::fmt(bound, f)?; + fmt::Display::fmt(&bound.print(), f)?; } Ok(()) - } + }) } -impl fmt::Display for clean::GenericParamDef { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.kind { - clean::GenericParamDefKind::Lifetime => write!(f, "{}", self.name), - clean::GenericParamDefKind::Type { ref bounds, ref default, .. } => { - f.write_str(&self.name)?; +impl clean::GenericParamDef { + crate fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + match self.kind { + clean::GenericParamDefKind::Lifetime => write!(f, "{}", self.name), + clean::GenericParamDefKind::Type { ref bounds, ref default, .. } => { + f.write_str(&self.name)?; - if !bounds.is_empty() { - if f.alternate() { - write!(f, ": {:#}", GenericBounds(bounds))?; - } else { - write!(f, ": {}", GenericBounds(bounds))?; + if !bounds.is_empty() { + if f.alternate() { + write!(f, ": {:#}", print_generic_bounds(bounds))?; + } else { + write!(f, ": {}", print_generic_bounds(bounds))?; + } + } + + if let Some(ref ty) = default { + if f.alternate() { + write!(f, " = {:#}", ty.print())?; + } else { + write!(f, " = {}", ty.print())?; + } } + + Ok(()) } + clean::GenericParamDefKind::Const { ref ty, .. } => { + f.write_str("const ")?; + f.write_str(&self.name)?; - if let Some(ref ty) = default { if f.alternate() { - write!(f, " = {:#}", ty)?; + write!(f, ": {:#}", ty.print()) } else { - write!(f, " = {}", ty)?; + write!(f, ": {}", ty.print()) } } - - Ok(()) - } - clean::GenericParamDefKind::Const { ref ty, .. } => { - f.write_str("const ")?; - f.write_str(&self.name)?; - - if f.alternate() { - write!(f, ": {:#}", ty) - } else { - write!(f, ": {}", ty) - } } - } + }) } } -impl fmt::Display for clean::Generics { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let real_params = self.params - .iter() - .filter(|p| !p.is_synthetic_type_param()) - .collect::>(); - if real_params.is_empty() { - return Ok(()); - } - if f.alternate() { - write!(f, "<{:#}>", comma_sep(&real_params)) - } else { - write!(f, "<{}>", comma_sep(&real_params)) - } +impl clean::Generics { + crate fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + let real_params = self.params + .iter() + .filter(|p| !p.is_synthetic_type_param()) + .collect::>(); + if real_params.is_empty() { + return Ok(()); + } + if f.alternate() { + write!(f, "<{:#}>", comma_sep(real_params.iter().map(|g| g.print()))) + } else { + write!(f, "<{}>", comma_sep(real_params.iter().map(|g| g.print()))) + } + }) } } @@ -287,24 +268,26 @@ impl<'a> fmt::Display for WhereClause<'a> { &clean::WherePredicate::BoundPredicate { ref ty, ref bounds } => { let bounds = bounds; if f.alternate() { - clause.push_str(&format!("{:#}: {:#}", ty, GenericBounds(bounds))); + clause.push_str(&format!("{:#}: {:#}", + ty.print(), print_generic_bounds(bounds))); } else { - clause.push_str(&format!("{}: {}", ty, GenericBounds(bounds))); + clause.push_str(&format!("{}: {}", + ty.print(), print_generic_bounds(bounds))); } } &clean::WherePredicate::RegionPredicate { ref lifetime, ref bounds } => { clause.push_str(&format!("{}: {}", - lifetime, + lifetime.print(), bounds.iter() - .map(|b| b.to_string()) + .map(|b| b.print().to_string()) .collect::>() .join(" + "))); } &clean::WherePredicate::EqPredicate { ref lhs, ref rhs } => { if f.alternate() { - clause.push_str(&format!("{:#} == {:#}", lhs, rhs)); + clause.push_str(&format!("{:#} == {:#}", lhs.print(), rhs.print())); } else { - clause.push_str(&format!("{} == {}", lhs, rhs)); + clause.push_str(&format!("{} == {}", lhs.print(), rhs.print())); } } } @@ -336,153 +319,164 @@ impl<'a> fmt::Display for WhereClause<'a> { } } -impl fmt::Display for clean::Lifetime { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.get_ref())?; - Ok(()) +impl clean::Lifetime { + crate fn print(&self) -> &str { + self.get_ref() } } -impl fmt::Display for clean::Constant { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self.expr, f) +impl clean::Constant { + crate fn print(&self) -> &str { + &self.expr } } -impl fmt::Display for clean::PolyTrait { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if !self.generic_params.is_empty() { +impl clean::PolyTrait { + fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + if !self.generic_params.is_empty() { + if f.alternate() { + write!(f, "for<{:#}> ", + comma_sep(self.generic_params.iter().map(|g| g.print())))?; + } else { + write!(f, "for<{}> ", + comma_sep(self.generic_params.iter().map(|g| g.print())))?; + } + } if f.alternate() { - write!(f, "for<{:#}> ", comma_sep(&self.generic_params))?; + write!(f, "{:#}", self.trait_.print()) } else { - write!(f, "for<{}> ", comma_sep(&self.generic_params))?; + write!(f, "{}", self.trait_.print()) } - } - if f.alternate() { - write!(f, "{:#}", self.trait_) - } else { - write!(f, "{}", self.trait_) - } + }) } } -impl fmt::Display for clean::GenericBound { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - clean::GenericBound::Outlives(ref lt) => { - write!(f, "{}", *lt) - } - clean::GenericBound::TraitBound(ref ty, modifier) => { - let modifier_str = match modifier { - hir::TraitBoundModifier::None => "", - hir::TraitBoundModifier::Maybe => "?", - }; - if f.alternate() { - write!(f, "{}{:#}", modifier_str, *ty) - } else { - write!(f, "{}{}", modifier_str, *ty) +impl clean::GenericBound { + crate fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + match self { + clean::GenericBound::Outlives(lt) => { + write!(f, "{}", lt.print()) + } + clean::GenericBound::TraitBound(ty, modifier) => { + let modifier_str = match modifier { + hir::TraitBoundModifier::None => "", + hir::TraitBoundModifier::Maybe => "?", + }; + if f.alternate() { + write!(f, "{}{:#}", modifier_str, ty.print()) + } else { + write!(f, "{}{}", modifier_str, ty.print()) + } } } - } + }) } } -impl fmt::Display for clean::GenericArgs { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - clean::GenericArgs::AngleBracketed { ref args, ref bindings } => { - if !args.is_empty() || !bindings.is_empty() { - if f.alternate() { - f.write_str("<")?; - } else { - f.write_str("<")?; - } - let mut comma = false; - for arg in args { - if comma { - f.write_str(", ")?; +impl clean::GenericArgs { + fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + match *self { + clean::GenericArgs::AngleBracketed { ref args, ref bindings } => { + if !args.is_empty() || !bindings.is_empty() { + if f.alternate() { + f.write_str("<")?; + } else { + f.write_str("<")?; + } + let mut comma = false; + for arg in args { + if comma { + f.write_str(", ")?; + } + comma = true; + if f.alternate() { + write!(f, "{:#}", arg.print())?; + } else { + write!(f, "{}", arg.print())?; + } + } + for binding in bindings { + if comma { + f.write_str(", ")?; + } + comma = true; + if f.alternate() { + write!(f, "{:#}", binding.print())?; + } else { + write!(f, "{}", binding.print())?; + } } - comma = true; if f.alternate() { - write!(f, "{:#}", *arg)?; + f.write_str(">")?; } else { - write!(f, "{}", *arg)?; + f.write_str(">")?; } } - for binding in bindings { + } + clean::GenericArgs::Parenthesized { ref inputs, ref output } => { + f.write_str("(")?; + let mut comma = false; + for ty in inputs { if comma { f.write_str(", ")?; } comma = true; if f.alternate() { - write!(f, "{:#}", *binding)?; + write!(f, "{:#}", ty.print())?; } else { - write!(f, "{}", *binding)?; + write!(f, "{}", ty.print())?; } } - if f.alternate() { - f.write_str(">")?; - } else { - f.write_str(">")?; - } - } - } - clean::GenericArgs::Parenthesized { ref inputs, ref output } => { - f.write_str("(")?; - let mut comma = false; - for ty in inputs { - if comma { - f.write_str(", ")?; - } - comma = true; - if f.alternate() { - write!(f, "{:#}", *ty)?; - } else { - write!(f, "{}", *ty)?; - } - } - f.write_str(")")?; - if let Some(ref ty) = *output { - if f.alternate() { - write!(f, " -> {:#}", ty)?; - } else { - write!(f, " -> {}", ty)?; + f.write_str(")")?; + if let Some(ref ty) = *output { + if f.alternate() { + write!(f, " -> {:#}", ty.print())?; + } else { + write!(f, " -> {}", ty.print())?; + } } } } - } - Ok(()) + Ok(()) + }) } } -impl fmt::Display for clean::PathSegment { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.name)?; - if f.alternate() { - write!(f, "{:#}", self.args) - } else { - write!(f, "{}", self.args) - } +impl clean::PathSegment { + crate fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + f.write_str(&self.name)?; + if f.alternate() { + write!(f, "{:#}", self.args.print()) + } else { + write!(f, "{}", self.args.print()) + } + }) } } -impl fmt::Display for clean::Path { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.global { - f.write_str("::")? - } - - for (i, seg) in self.segments.iter().enumerate() { - if i > 0 { +impl clean::Path { + crate fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + if self.global { f.write_str("::")? } - if f.alternate() { - write!(f, "{:#}", seg)?; - } else { - write!(f, "{}", seg)?; + + for (i, seg) in self.segments.iter().enumerate() { + if i > 0 { + f.write_str("::")? + } + if f.alternate() { + write!(f, "{:#}", seg.print())?; + } else { + write!(f, "{}", seg.print())?; + } } - } - Ok(()) + Ok(()) + }) } } @@ -516,7 +510,7 @@ pub fn href(did: DefId) -> Option<(String, ItemType, Vec)> { url.push_str("/index.html"); } _ => { - url.push_str(shortty.css_class()); + url.push_str(shortty.as_str()); url.push_str("."); url.push_str(fqp.last().unwrap()); url.push_str(".html"); @@ -537,7 +531,7 @@ fn resolved_path(w: &mut fmt::Formatter<'_>, did: DefId, path: &clean::Path, } } if w.alternate() { - write!(w, "{}{:#}", &last.name, last.args)?; + write!(w, "{}{:#}", &last.name, last.args.print())?; } else { let path = if use_absolute { if let Some((_, _, fqp)) = href(did) { @@ -550,7 +544,7 @@ fn resolved_path(w: &mut fmt::Formatter<'_>, did: DefId, path: &clean::Path, } else { anchor(did, &last.name).to_string() }; - write!(w, "{}{}", path, last.args)?; + write!(w, "{}{}", path, last.args.print())?; } Ok(()) } @@ -606,7 +600,7 @@ fn tybounds(param_names: &Option>) -> impl fmt::Display Some(ref params) => { for param in params { write!(f, " + ")?; - fmt::Display::fmt(param, f)?; + fmt::Display::fmt(¶m.print(), f)?; } Ok(()) } @@ -646,12 +640,12 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> write!(f, "{}{:#}fn{:#}{:#}", UnsafetySpace(decl.unsafety), AbiSpace(decl.abi), - comma_sep(&decl.generic_params), - decl.decl) + decl.print_generic_params(), + decl.decl.print()) } else { write!(f, "{}{}", UnsafetySpace(decl.unsafety), AbiSpace(decl.abi))?; primitive_link(f, PrimitiveType::Fn, "fn")?; - write!(f, "{}{}", comma_sep(&decl.generic_params), decl.decl) + write!(f, "{}{}", decl.print_generic_params(), decl.decl.print()) } } clean::Tuple(ref typs) => { @@ -660,24 +654,27 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> &[ref one] => { primitive_link(f, PrimitiveType::Tuple, "(")?; // Carry `f.alternate()` into this display w/o branching manually. - fmt::Display::fmt(one, f)?; + fmt::Display::fmt(&one.print(), f)?; primitive_link(f, PrimitiveType::Tuple, ",)") } many => { primitive_link(f, PrimitiveType::Tuple, "(")?; - fmt::Display::fmt(&comma_sep(many), f)?; + for (i, item) in many.iter().enumerate() { + if i != 0 { write!(f, ", ")?; } + fmt::Display::fmt(&item.print(), f)?; + } primitive_link(f, PrimitiveType::Tuple, ")") } } } clean::Slice(ref t) => { primitive_link(f, PrimitiveType::Slice, "[")?; - fmt::Display::fmt(t, f)?; + fmt::Display::fmt(&t.print(), f)?; primitive_link(f, PrimitiveType::Slice, "]") } clean::Array(ref t, ref n) => { primitive_link(f, PrimitiveType::Array, "[")?; - fmt::Display::fmt(t, f)?; + fmt::Display::fmt(&t.print(), f)?; primitive_link(f, PrimitiveType::Array, &format!("; {}]", n)) } clean::Never => primitive_link(f, PrimitiveType::Never, "!"), @@ -691,22 +688,22 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => { if f.alternate() { primitive_link(f, clean::PrimitiveType::RawPointer, - &format!("*{} {:#}", m, t)) + &format!("*{} {:#}", m, t.print())) } else { primitive_link(f, clean::PrimitiveType::RawPointer, - &format!("*{} {}", m, t)) + &format!("*{} {}", m, t.print())) } } _ => { primitive_link(f, clean::PrimitiveType::RawPointer, &format!("*{} ", m))?; - fmt::Display::fmt(t, f) + fmt::Display::fmt(&t.print(), f) } } } clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => { - let lt = match *l { - Some(ref l) => format!("{} ", *l), - _ => String::new(), + let lt = match l { + Some(l) => format!("{} ", l.print()), + _ => String::new() }; let m = MutableSpace(mutability); let amp = if f.alternate() { @@ -720,19 +717,19 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> clean::Generic(_) => { if f.alternate() { primitive_link(f, PrimitiveType::Slice, - &format!("{}{}{}[{:#}]", amp, lt, m, **bt)) + &format!("{}{}{}[{:#}]", amp, lt, m, bt.print())) } else { primitive_link(f, PrimitiveType::Slice, - &format!("{}{}{}[{}]", amp, lt, m, **bt)) + &format!("{}{}{}[{}]", amp, lt, m, bt.print())) } } _ => { primitive_link(f, PrimitiveType::Slice, &format!("{}{}{}[", amp, lt, m))?; if f.alternate() { - write!(f, "{:#}", **bt)?; + write!(f, "{:#}", bt.print())?; } else { - write!(f, "{}", **bt)?; + write!(f, "{}", bt.print())?; } primitive_link(f, PrimitiveType::Slice, "]") } @@ -756,9 +753,9 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> } clean::ImplTrait(ref bounds) => { if f.alternate() { - write!(f, "impl {:#}", GenericBounds(bounds)) + write!(f, "impl {:#}", print_generic_bounds(bounds)) } else { - write!(f, "impl {}", GenericBounds(bounds)) + write!(f, "impl {}", print_generic_bounds(bounds)) } } clean::QPath { ref name, ref self_type, ref trait_ } => { @@ -770,15 +767,15 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> }; if f.alternate() { if should_show_cast { - write!(f, "<{:#} as {:#}>::", self_type, trait_)? + write!(f, "<{:#} as {:#}>::", self_type.print(), trait_.print())? } else { - write!(f, "{:#}::", self_type)? + write!(f, "{:#}::", self_type.print())? } } else { if should_show_cast { - write!(f, "<{} as {}>::", self_type, trait_)? + write!(f, "<{} as {}>::", self_type.print(), trait_.print())? } else { - write!(f, "{}::", self_type)? + write!(f, "{}::", self_type.print())? } }; match *trait_ { @@ -818,55 +815,64 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> } } -impl fmt::Display for clean::Type { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt_type(self, f, false) +impl clean::Type { + crate fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + fmt_type(self, f, false) + }) } } -fn fmt_impl(i: &clean::Impl, - f: &mut fmt::Formatter<'_>, - link_trait: bool, - use_absolute: bool) -> fmt::Result { - if f.alternate() { - write!(f, "impl{:#} ", i.generics)?; - } else { - write!(f, "impl{} ", i.generics)?; +impl clean::Impl { + crate fn print(&self) -> impl fmt::Display + '_ { + self.print_inner(true, false) } - if let Some(ref ty) = i.trait_ { - if i.polarity == Some(clean::ImplPolarity::Negative) { - write!(f, "!")?; - } + fn print_inner( + &self, + link_trait: bool, + use_absolute: bool, + ) -> impl fmt::Display + '_ { + display_fn(move |f| { + if f.alternate() { + write!(f, "impl{:#} ", self.generics.print())?; + } else { + write!(f, "impl{} ", self.generics.print())?; + } - if link_trait { - fmt::Display::fmt(ty, f)?; - } else { - match *ty { - clean::ResolvedPath { param_names: None, ref path, is_generic: false, .. } => { - let last = path.segments.last().unwrap(); - fmt::Display::fmt(&last.name, f)?; - fmt::Display::fmt(&last.args, f)?; + if let Some(ref ty) = self.trait_ { + if self.polarity == Some(clean::ImplPolarity::Negative) { + write!(f, "!")?; } - _ => unreachable!(), - } - } - write!(f, " for ")?; - } - if let Some(ref ty) = i.blanket_impl { - fmt_type(ty, f, use_absolute)?; - } else { - fmt_type(&i.for_, f, use_absolute)?; - } + if link_trait { + fmt::Display::fmt(&ty.print(), f)?; + } else { + match ty { + clean::ResolvedPath { param_names: None, path, is_generic: false, .. } => { + let last = path.segments.last().unwrap(); + fmt::Display::fmt(&last.name, f)?; + fmt::Display::fmt(&last.args.print(), f)?; + } + _ => unreachable!(), + } + } + write!(f, " for ")?; + } - fmt::Display::fmt(&WhereClause { gens: &i.generics, indent: 0, end_newline: true }, f)?; - Ok(()) -} + if let Some(ref ty) = self.blanket_impl { + fmt_type(ty, f, use_absolute)?; + } else { + fmt_type(&self.for_, f, use_absolute)?; + } -impl fmt::Display for clean::Impl { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt_impl(self, f, true, false) + fmt::Display::fmt(&WhereClause { + gens: &self.generics, + indent: 0, + end_newline: true, + }, f)?; + Ok(()) + }) } } @@ -874,162 +880,193 @@ impl fmt::Display for clean::Impl { pub fn fmt_impl_for_trait_page(i: &clean::Impl, f: &mut Buffer, use_absolute: bool) { - f.with_formatter(|f| fmt_impl(i, f, false, use_absolute)) + f.from_display(i.print_inner(false, use_absolute)) } -impl fmt::Display for clean::Arguments { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for (i, input) in self.values.iter().enumerate() { - if !input.name.is_empty() { - write!(f, "{}: ", input.name)?; - } - if f.alternate() { - write!(f, "{:#}", input.type_)?; - } else { - write!(f, "{}", input.type_)?; +impl clean::Arguments { + crate fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + for (i, input) in self.values.iter().enumerate() { + if !input.name.is_empty() { + write!(f, "{}: ", input.name)?; + } + if f.alternate() { + write!(f, "{:#}", input.type_.print())?; + } else { + write!(f, "{}", input.type_.print())?; + } + if i + 1 < self.values.len() { write!(f, ", ")?; } } - if i + 1 < self.values.len() { write!(f, ", ")?; } - } - Ok(()) + Ok(()) + }) } } -impl fmt::Display for clean::FunctionRetTy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - clean::Return(clean::Tuple(ref tys)) if tys.is_empty() => Ok(()), - clean::Return(ref ty) if f.alternate() => write!(f, " -> {:#}", ty), - clean::Return(ref ty) => write!(f, " -> {}", ty), - clean::DefaultReturn => Ok(()), - } +impl clean::FunctionRetTy { + crate fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + match self { + clean::Return(clean::Tuple(tys)) if tys.is_empty() => Ok(()), + clean::Return(ty) if f.alternate() => write!(f, " -> {:#}", ty.print()), + clean::Return(ty) => write!(f, " -> {}", ty.print()), + clean::DefaultReturn => Ok(()), + } + }) } } -impl fmt::Display for clean::FnDecl { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if f.alternate() { - write!(f, "({args:#}){arrow:#}", args = self.inputs, arrow = self.output) - } else { - write!(f, "({args}){arrow}", args = self.inputs, arrow = self.output) - } +impl clean::BareFunctionDecl { + fn print_generic_params(&self) -> impl fmt::Display + '_ { + comma_sep(self.generic_params.iter().map(|g| g.print())) } } -impl<'a> fmt::Display for Function<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let &Function { decl, header_len, indent, asyncness } = self; - let amp = if f.alternate() { "&" } else { "&" }; - let mut args = String::new(); - let mut args_plain = String::new(); - for (i, input) in decl.inputs.values.iter().enumerate() { - if i == 0 { - args.push_str("
"); +impl clean::FnDecl { + crate fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + if f.alternate() { + write!(f, + "({args:#}){arrow:#}", args = self.inputs.print(), arrow = self.output.print()) + } else { + write!(f, + "({args}){arrow}", args = self.inputs.print(), arrow = self.output.print()) } + }) + } +} + + +impl Function<'_> { + crate fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + let &Function { decl, header_len, indent, asyncness } = self; + let amp = if f.alternate() { "&" } else { "&" }; + let mut args = String::new(); + let mut args_plain = String::new(); + for (i, input) in decl.inputs.values.iter().enumerate() { + if i == 0 { + args.push_str("
"); + } - if let Some(selfty) = input.to_self() { - match selfty { - clean::SelfValue => { - args.push_str("self"); - args_plain.push_str("self"); + if let Some(selfty) = input.to_self() { + match selfty { + clean::SelfValue => { + args.push_str("self"); + args_plain.push_str("self"); + } + clean::SelfBorrowed(Some(ref lt), mtbl) => { + args.push_str( + &format!("{}{} {}self", amp, lt.print(), MutableSpace(mtbl))); + args_plain.push_str( + &format!("&{} {}self", lt.print(), MutableSpace(mtbl))); + } + clean::SelfBorrowed(None, mtbl) => { + args.push_str(&format!("{}{}self", amp, MutableSpace(mtbl))); + args_plain.push_str(&format!("&{}self", MutableSpace(mtbl))); + } + clean::SelfExplicit(ref typ) => { + if f.alternate() { + args.push_str(&format!("self: {:#}", typ.print())); + } else { + args.push_str(&format!("self: {}", typ.print())); + } + args_plain.push_str(&format!("self: {:#}", typ.print())); + } } - clean::SelfBorrowed(Some(ref lt), mtbl) => { - args.push_str(&format!("{}{} {}self", amp, *lt, MutableSpace(mtbl))); - args_plain.push_str(&format!("&{} {}self", *lt, MutableSpace(mtbl))); + } else { + if i > 0 { + args.push_str("
"); + args_plain.push_str(" "); } - clean::SelfBorrowed(None, mtbl) => { - args.push_str(&format!("{}{}self", amp, MutableSpace(mtbl))); - args_plain.push_str(&format!("&{}self", MutableSpace(mtbl))); + if !input.name.is_empty() { + args.push_str(&format!("{}: ", input.name)); + args_plain.push_str(&format!("{}: ", input.name)); } - clean::SelfExplicit(ref typ) => { - if f.alternate() { - args.push_str(&format!("self: {:#}", *typ)); - } else { - args.push_str(&format!("self: {}", *typ)); - } - args_plain.push_str(&format!("self: {:#}", *typ)); + + if f.alternate() { + args.push_str(&format!("{:#}", input.type_.print())); + } else { + args.push_str(&input.type_.print().to_string()); } + args_plain.push_str(&format!("{:#}", input.type_.print())); } - } else { - if i > 0 { - args.push_str("
"); - args_plain.push_str(" "); - } - if !input.name.is_empty() { - args.push_str(&format!("{}: ", input.name)); - args_plain.push_str(&format!("{}: ", input.name)); + if i + 1 < decl.inputs.values.len() { + args.push(','); + args_plain.push(','); } - - if f.alternate() { - args.push_str(&format!("{:#}", input.type_)); - } else { - args.push_str(&input.type_.to_string()); - } - args_plain.push_str(&format!("{:#}", input.type_)); } - if i + 1 < decl.inputs.values.len() { - args.push(','); - args_plain.push(','); - } - } - let args_plain = format!("({})", args_plain); + let args_plain = format!("({})", args_plain); - let output = if let hir::IsAsync::Async = asyncness { - Cow::Owned(decl.sugared_async_return_type()) - } else { - Cow::Borrowed(&decl.output) - }; + let output = if let hir::IsAsync::Async = asyncness { + Cow::Owned(decl.sugared_async_return_type()) + } else { + Cow::Borrowed(&decl.output) + }; - let arrow_plain = format!("{:#}", &output); - let arrow = if f.alternate() { - format!("{:#}", &output) - } else { - output.to_string() - }; + let arrow_plain = format!("{:#}", &output.print()); + let arrow = if f.alternate() { + format!("{:#}", &output.print()) + } else { + output.print().to_string() + }; - let declaration_len = header_len + args_plain.len() + arrow_plain.len(); - let output = if declaration_len > 80 { - let full_pad = format!("
{}", " ".repeat(indent + 4)); - let close_pad = format!("
{}", " ".repeat(indent)); - format!("({args}{close}){arrow}", - args = args.replace("
", &full_pad), - close = close_pad, - arrow = arrow) - } else { - format!("({args}){arrow}", args = args.replace("
", ""), arrow = arrow) - }; + let declaration_len = header_len + args_plain.len() + arrow_plain.len(); + let output = if declaration_len > 80 { + let full_pad = format!("
{}", " ".repeat(indent + 4)); + let close_pad = format!("
{}", " ".repeat(indent)); + format!("({args}{close}){arrow}", + args = args.replace("
", &full_pad), + close = close_pad, + arrow = arrow) + } else { + format!("({args}){arrow}", args = args.replace("
", ""), arrow = arrow) + }; - if f.alternate() { - write!(f, "{}", output.replace("
", "\n")) - } else { - write!(f, "{}", output) - } + if f.alternate() { + write!(f, "{}", output.replace("
", "\n")) + } else { + write!(f, "{}", output) + } + }) } } impl<'a> fmt::Display for VisSpace<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self.get() { - Some(clean::Public) => f.write_str("pub "), - Some(clean::Inherited) | None => Ok(()), - Some(clean::Visibility::Crate) => write!(f, "pub(crate) "), - Some(clean::Visibility::Restricted(did, ref path)) => { - f.write_str("pub(")?; - if path.segments.len() != 1 - || (path.segments[0].name != "self" && path.segments[0].name != "super") - { - f.write_str("in ")?; + if let Some(v) = self.0 { + fmt::Display::fmt(&v.print_with_space(), f) + } else { + Ok(()) + } + } +} + +impl clean::Visibility { + fn print_with_space(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + match *self { + clean::Public => f.write_str("pub "), + clean::Inherited => Ok(()), + clean::Visibility::Crate => write!(f, "pub(crate) "), + clean::Visibility::Restricted(did, ref path) => { + f.write_str("pub(")?; + if path.segments.len() != 1 + || (path.segments[0].name != "self" && path.segments[0].name != "super") + { + f.write_str("in ")?; + } + resolved_path(f, did, path, true, false)?; + f.write_str(") ") } - resolved_path(f, did, path, true, false)?; - f.write_str(") ") } - } + }) } } impl fmt::Display for UnsafetySpace { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.get() { + match self.0 { hir::Unsafety::Unsafe => write!(f, "unsafe "), hir::Unsafety::Normal => Ok(()) } @@ -1038,7 +1075,7 @@ impl fmt::Display for UnsafetySpace { impl fmt::Display for ConstnessSpace { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.get() { + match self.0 { hir::Constness::Const => write!(f, "const "), hir::Constness::NotConst => Ok(()) } @@ -1054,66 +1091,72 @@ impl fmt::Display for AsyncSpace { } } -impl fmt::Display for clean::Import { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - clean::Import::Simple(ref name, ref src) => { - if *name == src.path.last_name() { - write!(f, "use {};", *src) - } else { - write!(f, "use {} as {};", *src, *name) +impl clean::Import { + crate fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + match *self { + clean::Import::Simple(ref name, ref src) => { + if *name == src.path.last_name() { + write!(f, "use {};", src.print()) + } else { + write!(f, "use {} as {};", src.print(), *name) + } } - } - clean::Import::Glob(ref src) => { - if src.path.segments.is_empty() { - write!(f, "use *;") - } else { - write!(f, "use {}::*;", *src) + clean::Import::Glob(ref src) => { + if src.path.segments.is_empty() { + write!(f, "use *;") + } else { + write!(f, "use {}::*;", src.print()) + } } } - } + }) } } -impl fmt::Display for clean::ImportSource { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.did { - Some(did) => resolved_path(f, did, &self.path, true, false), - _ => { - for (i, seg) in self.path.segments.iter().enumerate() { - if i > 0 { - write!(f, "::")? +impl clean::ImportSource { + crate fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + match self.did { + Some(did) => resolved_path(f, did, &self.path, true, false), + _ => { + for (i, seg) in self.path.segments.iter().enumerate() { + if i > 0 { + write!(f, "::")? + } + write!(f, "{}", seg.name)?; } - write!(f, "{}", seg.name)?; + Ok(()) } - Ok(()) } - } + }) } } -impl fmt::Display for clean::TypeBinding { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.name)?; - match self.kind { - clean::TypeBindingKind::Equality { ref ty } => { - if f.alternate() { - write!(f, " = {:#}", ty)?; - } else { - write!(f, " = {}", ty)?; - } - } - clean::TypeBindingKind::Constraint { ref bounds } => { - if !bounds.is_empty() { +impl clean::TypeBinding { + crate fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + f.write_str(&self.name)?; + match self.kind { + clean::TypeBindingKind::Equality { ref ty } => { if f.alternate() { - write!(f, ": {:#}", GenericBounds(bounds))?; + write!(f, " = {:#}", ty.print())?; } else { - write!(f, ": {}", GenericBounds(bounds))?; + write!(f, " = {}", ty.print())?; + } + } + clean::TypeBindingKind::Constraint { ref bounds } => { + if !bounds.is_empty() { + if f.alternate() { + write!(f, ": {:#}", print_generic_bounds(bounds))?; + } else { + write!(f, ": {}", print_generic_bounds(bounds))?; + } } } } - } - Ok(()) + Ok(()) + }) } } @@ -1146,6 +1189,18 @@ impl fmt::Display for DefaultSpace { } } +impl clean::GenericArg { + crate fn print(&self) -> impl fmt::Display + '_ { + display_fn(move |f| { + match self { + clean::GenericArg::Lifetime(lt) => fmt::Display::fmt(<.print(), f), + clean::GenericArg::Type(ty) => fmt::Display::fmt(&ty.print(), f), + clean::GenericArg::Const(ct) => fmt::Display::fmt(&ct.print(), f), + } + }) + } +} + crate fn display_fn( f: impl FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result, ) -> impl fmt::Display { diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index cf51a4eb5a5be..5fb9afd6c49a0 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -46,14 +46,6 @@ pub enum ItemType { } -#[derive(Copy, Eq, PartialEq, Clone)] -pub enum NameSpace { - Type, - Value, - Macro, - Keyword, -} - impl<'a> From<&'a clean::Item> for ItemType { fn from(item: &'a clean::Item) -> ItemType { let inner = match item.inner { @@ -120,7 +112,7 @@ impl From for ItemType { } impl ItemType { - pub fn css_class(&self) -> &'static str { + pub fn as_str(&self) -> &'static str { match *self { ItemType::Module => "mod", ItemType::ExternCrate => "externcrate", @@ -151,7 +143,7 @@ impl ItemType { } } - pub fn name_space(&self) -> NameSpace { + pub fn name_space(&self) -> &'static str { match *self { ItemType::Struct | ItemType::Union | @@ -163,7 +155,7 @@ impl ItemType { ItemType::AssocType | ItemType::OpaqueTy | ItemType::TraitAlias | - ItemType::ForeignType => NameSpace::Type, + ItemType::ForeignType => NAMESPACE_TYPE, ItemType::ExternCrate | ItemType::Import | @@ -175,20 +167,20 @@ impl ItemType { ItemType::StructField | ItemType::Variant | ItemType::Constant | - ItemType::AssocConst => NameSpace::Value, + ItemType::AssocConst => NAMESPACE_VALUE, ItemType::Macro | ItemType::ProcAttribute | - ItemType::ProcDerive => NameSpace::Macro, + ItemType::ProcDerive => NAMESPACE_MACRO, - ItemType::Keyword => NameSpace::Keyword, + ItemType::Keyword => NAMESPACE_KEYWORD, } } } impl fmt::Display for ItemType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.css_class().fmt(f) + write!(f, "{}", self.as_str()) } } @@ -196,20 +188,3 @@ pub const NAMESPACE_TYPE: &'static str = "t"; pub const NAMESPACE_VALUE: &'static str = "v"; pub const NAMESPACE_MACRO: &'static str = "m"; pub const NAMESPACE_KEYWORD: &'static str = "k"; - -impl NameSpace { - pub fn to_static_str(&self) -> &'static str { - match *self { - NameSpace::Type => NAMESPACE_TYPE, - NameSpace::Value => NAMESPACE_VALUE, - NameSpace::Macro => NAMESPACE_MACRO, - NameSpace::Keyword => NAMESPACE_KEYWORD, - } - } -} - -impl fmt::Display for NameSpace { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.to_static_str().fmt(f) - } -} diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 9846073cad4bc..7aaf04f34d32f 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -66,7 +66,7 @@ use crate::doctree; use crate::fold::DocFolder; use crate::html::escape::Escape; use crate::html::format::{Buffer, AsyncSpace, ConstnessSpace}; -use crate::html::format::{GenericBounds, WhereClause, href, AbiSpace, DefaultSpace}; +use crate::html::format::{print_generic_bounds, WhereClause, href, AbiSpace, DefaultSpace}; use crate::html::format::{VisSpace, Function, UnsafetySpace, MutableSpace}; use crate::html::format::fmt_impl_for_trait_page; use crate::html::item_type::ItemType; @@ -1203,7 +1203,7 @@ themePicker.onblur = handleThemeButtonsBlur; if !imp.impl_item.def_id.is_local() { continue } have_impls = true; write!(implementors, "{{text:{},synthetic:{},types:{}}},", - as_json(&imp.inner_impl().to_string()), + as_json(&imp.inner_impl().print().to_string()), imp.inner_impl().synthetic, as_json(&collect_paths_for_type(imp.inner_impl().for_.clone()))).unwrap(); } @@ -1222,7 +1222,7 @@ themePicker.onblur = handleThemeButtonsBlur; } cx.shared.ensure_dir(&mydst)?; mydst.push(&format!("{}.{}.js", - remote_item_type.css_class(), + remote_item_type, remote_path[remote_path.len() - 1])); let (mut all_implementors, _, _) = try_err!(collect(&mydst, &krate.name, "implementors", @@ -1665,9 +1665,11 @@ impl ItemEntry { } } -impl fmt::Display for ItemEntry { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.url, Escape(&self.name)) +impl ItemEntry { + crate fn print(&self) -> impl fmt::Display + '_ { + crate::html::format::display_fn(move |f| { + write!(f, "{}", self.url, Escape(&self.name)) + }) } } @@ -1759,7 +1761,7 @@ fn print_entries(f: &mut Buffer, e: &FxHashSet, title: &str, class: & title, Escape(title), class, - e.iter().map(|s| format!("
  • {}
  • ", s)).collect::()); + e.iter().map(|s| format!("
  • {}
  • ", s.print())).collect::()); } } @@ -1939,7 +1941,7 @@ impl Context { title.push_str(it.name.as_ref().unwrap()); } title.push_str(" - Rust"); - let tyname = it.type_().css_class(); + let tyname = it.type_(); let desc = if it.is_crate() { format!("API documentation for the Rust `{}` crate.", self.shared.layout.krate) @@ -1949,7 +1951,7 @@ impl Context { }; let keywords = make_item_keywords(it); let page = layout::Page { - css_class: tyname, + css_class: tyname.as_str(), root_path: &self.root_path(), static_root_path: self.shared.static_root_path.as_deref(), title: &title, @@ -2090,7 +2092,7 @@ impl Context { for item in &m.items { if item.is_stripped() { continue } - let short = item.type_().css_class(); + let short = item.type_(); let myname = match item.name { None => continue, Some(ref s) => s.to_string(), @@ -2285,7 +2287,7 @@ fn print_item(cx: &Context, item: &clean::Item, buf: &mut Buffer) { fn item_path(ty: ItemType, name: &str) -> String { match ty { ItemType::Module => format!("{}index.html", SlashChecker(name)), - _ => format!("{}.{}.html", ty.css_class(), name), + _ => format!("{}.{}.html", ty, name), } } @@ -2586,7 +2588,7 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean: clean::ImportItem(ref import) => { write!(w, "{}{}", - VisSpace(&myitem.visibility), *import); + VisSpace(&myitem.visibility), import.print()); } _ => { @@ -2794,7 +2796,7 @@ fn item_constant(w: &mut Buffer, cx: &Context, it: &clean::Item, c: &clean::Cons {name}: {typ}", vis = VisSpace(&it.visibility), name = it.name.as_ref().unwrap(), - typ = c.type_); + typ = c.type_.print()); document(w, cx, it) } @@ -2806,7 +2808,7 @@ fn item_static(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Static vis = VisSpace(&it.visibility), mutability = MutableSpace(s.mutability), name = it.name.as_ref().unwrap(), - typ = s.type_); + typ = s.type_.print()); document(w, cx, it) } @@ -2819,7 +2821,7 @@ fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Func AsyncSpace(f.header.asyncness), AbiSpace(f.header.abi), it.name.as_ref().unwrap(), - f.generics + f.generics.print() ).len(); write!(w, "{}
    ", render_spotlight_traits(it));
         render_attributes(w, it, false);
    @@ -2832,14 +2834,14 @@ fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Func
                asyncness = AsyncSpace(f.header.asyncness),
                abi = AbiSpace(f.header.abi),
                name = it.name.as_ref().unwrap(),
    -           generics = f.generics,
    +           generics = f.generics.print(),
                where_clause = WhereClause { gens: &f.generics, indent: 0, end_newline: true },
                decl = Function {
                   decl: &f.decl,
                   header_len,
                   indent: 0,
                   asyncness: f.header.asyncness,
    -           });
    +           }.print());
         document(w, cx, it)
     }
     
    @@ -2880,15 +2882,15 @@ fn bounds(t_bounds: &[clean::GenericBound], trait_alias: bool) -> String {
                 if i > 0 {
                     bounds.push_str(" + ");
                 }
    -            bounds.push_str(&(*p).to_string());
    +            bounds.push_str(&p.print().to_string());
             }
         }
         bounds
     }
     
     fn compare_impl<'a, 'b>(lhs: &'a &&Impl, rhs: &'b &&Impl) -> Ordering {
    -    let lhs = format!("{}", lhs.inner_impl());
    -    let rhs = format!("{}", rhs.inner_impl());
    +    let lhs = format!("{}", lhs.inner_impl().print());
    +    let rhs = format!("{}", rhs.inner_impl().print());
     
         // lhs and rhs are formatted as HTML, which may be unnecessary
         name_key(&lhs).cmp(&name_key(&rhs))
    @@ -2915,7 +2917,7 @@ fn item_trait(
                    UnsafetySpace(t.unsafety),
                    if t.is_auto { "auto " } else { "" },
                    it.name.as_ref().unwrap(),
    -               t.generics,
    +               t.generics.print(),
                    bounds);
     
             if !t.generics.where_predicates.is_empty() {
    @@ -3142,7 +3144,7 @@ fn item_trait(
                    let (ref path, _) = cache.external_paths[&it.def_id];
                    path[..path.len() - 1].join("/")
                },
    -           ty = it.type_().css_class(),
    +           ty = it.type_(),
                name = *it.name.as_ref().unwrap());
     }
     
    @@ -3176,7 +3178,7 @@ fn assoc_const(w: &mut Buffer,
                VisSpace(&it.visibility),
                naive_assoc_href(it, link),
                it.name.as_ref().unwrap(),
    -           ty);
    +           ty.print());
     }
     
     fn assoc_type(w: &mut Buffer, it: &clean::Item,
    @@ -3189,10 +3191,10 @@ fn assoc_type(w: &mut Buffer, it: &clean::Item,
                naive_assoc_href(it, link),
                it.name.as_ref().unwrap());
         if !bounds.is_empty() {
    -        write!(w, ": {}", GenericBounds(bounds))
    +        write!(w, ": {}", print_generic_bounds(bounds))
         }
         if let Some(default) = default {
    -        write!(w, " = {}", default)
    +        write!(w, " = {}", default.print())
         }
     }
     
    @@ -3245,7 +3247,7 @@ fn render_assoc_item(w: &mut Buffer,
                 DefaultSpace(meth.is_default()),
                 AbiSpace(header.abi),
                 name,
    -            *g
    +            g.print()
             ).len();
             let (indent, end_newline) = if parent == ItemType::Trait {
                 header_len += 4;
    @@ -3265,13 +3267,13 @@ fn render_assoc_item(w: &mut Buffer,
                    AbiSpace(header.abi),
                    href = href,
                    name = name,
    -               generics = *g,
    +               generics = g.print(),
                    decl = Function {
                        decl: d,
                        header_len,
                        indent,
                        asyncness: header.asyncness,
    -               },
    +               }.print(),
                    where_clause = WhereClause {
                        gens: g,
                        indent,
    @@ -3340,7 +3342,7 @@ fn item_struct(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Struct
                            id = id,
                            ns_id = ns_id,
                            name = field.name.as_ref().unwrap(),
    -                       ty = ty);
    +                       ty = ty.print());
                     document(w, cx, field);
                 }
             }
    @@ -3381,7 +3383,7 @@ fn item_union(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Union)
                        id = id,
                        name = name,
                        shortty = ItemType::StructField,
    -                   ty = ty);
    +                   ty = ty.print());
                 if let Some(stability_class) = field.stability_class() {
                     write!(w, "",
                         stab = stability_class);
    @@ -3399,7 +3401,7 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum) {
             write!(w, "{}enum {}{}{}",
                    VisSpace(&it.visibility),
                    it.name.as_ref().unwrap(),
    -               e.generics,
    +               e.generics.print(),
                    WhereClause { gens: &e.generics, indent: 0, end_newline: true });
             if e.variants.is_empty() && !e.variants_stripped {
                 write!(w, " {{}}");
    @@ -3418,7 +3420,7 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum) {
                                         if i > 0 {
                                             write!(w, ", ")
                                         }
    -                                    write!(w, "{}", *ty);
    +                                    write!(w, "{}", ty.print());
                                     }
                                     write!(w, ")");
                                 }
    @@ -3472,7 +3474,7 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum) {
                             if i > 0 {
                                 write!(w, ", ");
                             }
    -                        write!(w, "{}", *ty);
    +                        write!(w, "{}", ty.print());
                         }
                         write!(w, ")");
                     }
    @@ -3510,7 +3512,7 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum) {
                                    id = id,
                                    ns_id = ns_id,
                                    f = field.name.as_ref().unwrap(),
    -                               t = *ty);
    +                               t = ty.print());
                             document(w, cx, field);
                         }
                     }
    @@ -3590,7 +3592,7 @@ fn render_struct(w: &mut Buffer, it: &clean::Item,
                if structhead {"struct "} else {""},
                it.name.as_ref().unwrap());
         if let Some(g) = g {
    -        write!(w, "{}", g)
    +        write!(w, "{}", g.print())
         }
         match ty {
             doctree::Plain => {
    @@ -3605,7 +3607,7 @@ fn render_struct(w: &mut Buffer, it: &clean::Item,
                                tab,
                                VisSpace(&field.visibility),
                                field.name.as_ref().unwrap(),
    -                           *ty);
    +                           ty.print());
                         has_visible_fields = true;
                     }
                 }
    @@ -3633,7 +3635,7 @@ fn render_struct(w: &mut Buffer, it: &clean::Item,
                             write!(w, "_")
                         }
                         clean::StructFieldItem(ref ty) => {
    -                        write!(w, "{}{}", VisSpace(&field.visibility), *ty)
    +                        write!(w, "{}{}", VisSpace(&field.visibility), ty.print())
                         }
                         _ => unreachable!()
                     }
    @@ -3664,7 +3666,7 @@ fn render_union(w: &mut Buffer, it: &clean::Item,
                if structhead {"union "} else {""},
                it.name.as_ref().unwrap());
         if let Some(g) = g {
    -        write!(w, "{}", g);
    +        write!(w, "{}", g.print());
             write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true });
         }
     
    @@ -3674,7 +3676,7 @@ fn render_union(w: &mut Buffer, it: &clean::Item,
                 write!(w, "    {}{}: {},\n{}",
                        VisSpace(&field.visibility),
                        field.name.as_ref().unwrap(),
    -                   *ty,
    +                   ty.print(),
                        tab);
             }
         }
    @@ -3740,7 +3742,7 @@ fn render_assoc_items(w: &mut Buffer,
                           Methods from {}<Target = {}>\
                           \
                         \
    -                ", trait_, type_);
    +                ", trait_.print(), type_.print());
                     RenderMode::ForDeref { mut_: deref_mut_ }
                 }
             };
    @@ -3885,12 +3887,13 @@ fn spotlight_decl(decl: &clean::FnDecl) -> String {
                             out.push_str(
                                 &format!("

    Important traits for {}

    \ ", - impl_.for_)); - trait_.push_str(&impl_.for_.to_string()); + impl_.for_.print())); + trait_.push_str(&impl_.for_.print().to_string()); } //use the "where" class here to make it small - out.push_str(&format!("{}", impl_)); + out.push_str( + &format!("{}", impl_.print())); let t_did = impl_.trait_.def_id().unwrap(); for it in &impl_.items { if let clean::TypedefItem(ref tydef, _) = it.inner { @@ -3927,7 +3930,7 @@ fn render_impl(w: &mut Buffer, cx: &Context, i: &Impl, link: AssocItemLink<'_>, Some(ref t) => if is_on_foreign_type { get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t) } else { - format!("impl-{}", small_url_encode(&format!("{:#}", t))) + format!("impl-{}", small_url_encode(&format!("{:#}", t.print()))) }, None => "impl".to_string(), }); @@ -3948,7 +3951,7 @@ fn render_impl(w: &mut Buffer, cx: &Context, i: &Impl, link: AssocItemLink<'_>, write!(w, ""); } else { write!(w, "

    {}", - id, i.inner_impl() + id, i.inner_impl().print() ); } write!(w, "", id); @@ -3993,8 +3996,10 @@ fn render_impl(w: &mut Buffer, cx: &Context, i: &Impl, link: AssocItemLink<'_>, // Only render when the method is not static or we allow static methods if render_method_item { let id = cx.derive_id(format!("{}.{}", item_type, name)); - let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space())); - write!(w, "

    ", id, item_type, extra_class); + let ns_id = cx.derive_id(format!("{}.{}", + name, item_type.name_space())); + write!(w, "

    ", + id, item_type, extra_class); write!(w, "{}", spotlight_decl(decl)); write!(w, "", ns_id); render_assoc_item(w, item, link.anchor(&id), ItemType::Impl); @@ -4125,7 +4130,7 @@ fn item_opaque_ty( render_attributes(w, it, false); write!(w, "type {}{}{where_clause} = impl {bounds};

    ", it.name.as_ref().unwrap(), - t.generics, + t.generics.print(), where_clause = WhereClause { gens: &t.generics, indent: 0, end_newline: true }, bounds = bounds(&t.bounds, false)); @@ -4144,7 +4149,7 @@ fn item_trait_alias(w: &mut Buffer, cx: &Context, it: &clean::Item, render_attributes(w, it, false); write!(w, "trait {}{}{} = {};", it.name.as_ref().unwrap(), - t.generics, + t.generics.print(), WhereClause { gens: &t.generics, indent: 0, end_newline: true }, bounds(&t.bounds, true)); @@ -4162,9 +4167,9 @@ fn item_typedef(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Typed render_attributes(w, it, false); write!(w, "type {}{}{where_clause} = {type_};", it.name.as_ref().unwrap(), - t.generics, + t.generics.print(), where_clause = WhereClause { gens: &t.generics, indent: 0, end_newline: true }, - type_ = t.type_); + type_ = t.type_.print()); document(w, cx, it); @@ -4269,7 +4274,7 @@ fn print_sidebar(cx: &Context, it: &clean::Item, buffer: &mut Buffer) { relpath: '{path}'\ }};", name = it.name.as_ref().map(|x| &x[..]).unwrap_or(""), - ty = it.type_().css_class(), + ty = it.type_(), path = relpath); if parentlen == 0 { // There is no sidebar-items.js beyond the crate root path @@ -4370,9 +4375,10 @@ fn sidebar_assoc_items(it: &clean::Item) -> String { if let Some(impls) = inner_impl { out.push_str(""); out.push_str(&format!("Methods from {}<Target={}>", - Escape(&format!("{:#}", - impl_.inner_impl().trait_.as_ref().unwrap())), - Escape(&format!("{:#}", target)))); + Escape(&format!( + "{:#}", impl_.inner_impl().trait_.as_ref().unwrap().print() + )), + Escape(&format!("{:#}", target.print())))); out.push_str(""); let mut ret = impls.iter() .filter(|i| i.inner_impl().trait_.is_none()) @@ -4397,9 +4403,9 @@ fn sidebar_assoc_items(it: &clean::Item) -> String { .filter_map(|i| { let is_negative_impl = is_negative_impl(i.inner_impl()); if let Some(ref i) = i.inner_impl().trait_ { - let i_display = format!("{:#}", i); + let i_display = format!("{:#}", i.print()); let out = Escape(&i_display); - let encoded = small_url_encode(&format!("{:#}", i)); + let encoded = small_url_encode(&format!("{:#}", i.print())); let generated = format!("{}{}", encoded, if is_negative_impl { "!" } else { "" }, @@ -4471,14 +4477,17 @@ fn sidebar_struct(buf: &mut Buffer, it: &clean::Item, s: &clean::Struct) { } fn get_id_for_impl_on_foreign_type(for_: &clean::Type, trait_: &clean::Type) -> String { - small_url_encode(&format!("impl-{:#}-for-{:#}", trait_, for_)) + small_url_encode(&format!("impl-{:#}-for-{:#}", trait_.print(), for_.print())) } fn extract_for_impl_name(item: &clean::Item) -> Option<(String, String)> { match item.inner { clean::ItemEnum::ImplItem(ref i) => { if let Some(ref trait_) = i.trait_ { - Some((format!("{:#}", i.for_), get_id_for_impl_on_foreign_type(&i.for_, trait_))) + Some(( + format!("{:#}", i.for_.print()), + get_id_for_impl_on_foreign_type(&i.for_, trait_), + )) } else { None } diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 4ee09f7096b61..dc1ca8d7668ae 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -142,7 +142,8 @@ impl fold::DocFolder for CoverageCalculator { } clean::ImplItem(ref impl_) => { if let Some(ref tr) = impl_.trait_ { - debug!("impl {:#} for {:#} in {}", tr, impl_.for_, i.source.filename); + debug!("impl {:#} for {:#} in {}", + tr.print(), impl_.for_.print(), i.source.filename); // don't count trait impls, the missing-docs lint doesn't so we shouldn't // either @@ -151,11 +152,11 @@ impl fold::DocFolder for CoverageCalculator { // inherent impls *can* be documented, and those docs show up, but in most // cases it doesn't make sense, as all methods on a type are in one single // impl block - debug!("impl {:#} in {}", impl_.for_, i.source.filename); + debug!("impl {:#} in {}", impl_.for_.print(), i.source.filename); } } _ => { - debug!("counting {} {:?} in {}", i.type_(), i.name, i.source.filename); + debug!("counting {:?} {:?} in {}", i.type_(), i.name, i.source.filename); self.items.entry(i.source.filename.clone()) .or_default() .count_item(has_docs); diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index d6073cdc1e11d..b67f39d328015 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -237,7 +237,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { }); if parent_node.is_some() { - debug!("got parent node for {} {:?}, id {:?}", item.type_(), item.name, item.def_id); + debug!("got parent node for {:?} {:?}, id {:?}", item.type_(), item.name, item.def_id); } let current_item = match item.inner { diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 14f8b16dc3067..d0f2cdad8f3e4 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -153,7 +153,7 @@ impl<'a> DocFolder for Stripper<'a> { // We need to recurse into stripped modules to strip things // like impl methods but when doing so we must not add any // items to the `retained` set. - debug!("Stripper: recursing into stripped {} {:?}", i.type_(), i.name); + debug!("Stripper: recursing into stripped {:?} {:?}", i.type_(), i.name); let old = mem::replace(&mut self.update_retained, false); let ret = self.fold_item_recur(i); self.update_retained = old; @@ -178,7 +178,7 @@ impl<'a> DocFolder for Stripper<'a> { | clean::ForeignTypeItem => { if i.def_id.is_local() { if !self.access_levels.is_exported(i.def_id) { - debug!("Stripper: stripping {} {:?}", i.type_(), i.name); + debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name); return None; } } diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index da8977544f64b..0159e03f6f299 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -39,7 +39,7 @@ struct Stripper<'a> { impl<'a> DocFolder for Stripper<'a> { fn fold_item(&mut self, i: Item) -> Option { if i.attrs.lists(sym::doc).has_word(sym::hidden) { - debug!("strip_hidden: stripping {} {:?}", i.type_(), i.name); + debug!("strip_hidden: stripping {:?} {:?}", i.type_(), i.name); // use a dedicated hidden item for given item type if any match i.inner { clean::StructFieldItem(..) | clean::ModuleItem(..) => { From ec349bef24dc6faf41970bc7de17d22bce6a7cfb Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 12 Sep 2019 22:32:12 -0400 Subject: [PATCH 12/55] Unwrap Visibility fields There's not really any reason to not have the visibility default to inherited, and this saves us the trouble of checking everywhere for whether we have a visibility or not. --- src/librustdoc/clean/auto_trait.rs | 2 +- src/librustdoc/clean/blanket_impl.rs | 2 +- src/librustdoc/clean/inline.rs | 4 ++-- src/librustdoc/clean/mod.rs | 32 ++++++++++++++-------------- src/librustdoc/html/format.rs | 8 ++----- src/librustdoc/html/render.rs | 5 ++--- src/librustdoc/passes/mod.rs | 6 +++--- 7 files changed, 27 insertions(+), 32 deletions(-) diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 516be99ed6aad..18a84cd0eeb76 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -119,7 +119,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { source: Span::empty(), name: None, attrs: Default::default(), - visibility: None, + visibility: Inherited, def_id: self.cx.next_def_id(param_env_def_id.krate), stability: None, deprecation: None, diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 490d4107c51ab..4cd1cc1a1cf50 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -99,7 +99,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { source: self.cx.tcx.def_span(impl_def_id).clean(self.cx), name: None, attrs: Default::default(), - visibility: None, + visibility: Inherited, def_id: self.cx.next_def_id(impl_def_id.krate), stability: None, deprecation: None, diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index cb42ff1c8052f..031e77ff1dbe0 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -131,7 +131,7 @@ pub fn try_inline( name: Some(name.clean(cx)), attrs, inner, - visibility: Some(clean::Public), + visibility: clean::Public, stability: cx.tcx.lookup_stability(did).clean(cx), deprecation: cx.tcx.lookup_deprecation(did).clean(cx), def_id: did, @@ -418,7 +418,7 @@ pub fn build_impl(cx: &DocContext<'_>, did: DefId, attrs: Option>, source: tcx.def_span(did).clean(cx), name: None, attrs, - visibility: Some(clean::Inherited), + visibility: clean::Inherited, stability: tcx.lookup_stability(did).clean(cx), deprecation: tcx.lookup_deprecation(did).clean(cx), def_id: did, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 10c4231b82eeb..197c09ba759e7 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -187,7 +187,7 @@ pub fn krate(mut cx: &mut DocContext<'_>) -> Crate { source: Span::empty(), name: Some(prim.to_url_str().to_string()), attrs: attrs.clone(), - visibility: Some(Public), + visibility: Public, stability: get_stability(cx, def_id), deprecation: get_deprecation(cx, def_id), def_id, @@ -199,7 +199,7 @@ pub fn krate(mut cx: &mut DocContext<'_>) -> Crate { source: Span::empty(), name: Some(kw.clone()), attrs: attrs, - visibility: Some(Public), + visibility: Public, stability: get_stability(cx, def_id), deprecation: get_deprecation(cx, def_id), def_id, @@ -361,7 +361,7 @@ pub struct Item { pub name: Option, pub attrs: Attributes, pub inner: ItemEnum, - pub visibility: Option, + pub visibility: Visibility, pub def_id: DefId, pub stability: Option, pub deprecation: Option, @@ -2311,7 +2311,7 @@ impl Clean for hir::TraitItem { attrs: self.attrs.clean(cx), source: self.span.clean(cx), def_id: local_did, - visibility: None, + visibility: Visibility::Inherited, stability: get_stability(cx, local_did), deprecation: get_deprecation(cx, local_did), inner, @@ -2496,7 +2496,7 @@ impl Clean for ty::AssocItem { let visibility = match self.container { ty::ImplContainer(_) => self.vis.clean(cx), - ty::TraitContainer(_) => None, + ty::TraitContainer(_) => Inherited, }; Item { @@ -3293,9 +3293,9 @@ pub enum Visibility { Restricted(DefId, Path), } -impl Clean> for hir::Visibility { - fn clean(&self, cx: &DocContext<'_>) -> Option { - Some(match self.node { +impl Clean for hir::Visibility { + fn clean(&self, cx: &DocContext<'_>) -> Visibility { + match self.node { hir::VisibilityKind::Public => Visibility::Public, hir::VisibilityKind::Inherited => Visibility::Inherited, hir::VisibilityKind::Crate(_) => Visibility::Crate, @@ -3304,13 +3304,13 @@ impl Clean> for hir::Visibility { let did = register_res(cx, path.res); Visibility::Restricted(did, path) } - }) + } } } -impl Clean> for ty::Visibility { - fn clean(&self, _: &DocContext<'_>) -> Option { - Some(if *self == ty::Visibility::Public { Public } else { Inherited }) +impl Clean for ty::Visibility { + fn clean(&self, _: &DocContext<'_>) -> Visibility { + if *self == ty::Visibility::Public { Public } else { Inherited } } } @@ -3427,7 +3427,7 @@ impl Clean for doctree::Variant<'_> { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - visibility: None, + visibility: Inherited, stability: cx.stability(self.id).clean(cx), deprecation: cx.deprecation(self.id).clean(cx), def_id: cx.tcx.hir().local_def_id(self.id), @@ -3470,7 +3470,7 @@ impl Clean for ty::VariantDef { name: Some(self.ident.clean(cx)), attrs: inline::load_attrs(cx, self.def_id).clean(cx), source: cx.tcx.def_span(self.def_id).clean(cx), - visibility: Some(Inherited), + visibility: Inherited, def_id: self.def_id, inner: VariantItem(Variant { kind }), stability: get_stability(cx, self.def_id), @@ -4333,7 +4333,7 @@ impl Clean for doctree::Macro<'_> { name: Some(name.clone()), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - visibility: Some(Public), + visibility: Public, stability: cx.stability(self.hid).clean(cx), deprecation: cx.deprecation(self.hid).clean(cx), def_id: self.def_id, @@ -4361,7 +4361,7 @@ impl Clean for doctree::ProcMacro<'_> { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - visibility: Some(Public), + visibility: Public, stability: cx.stability(self.id).clean(cx), deprecation: cx.deprecation(self.id).clean(cx), def_id: cx.tcx.hir().local_def_id(self.id), diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 9baa69d981b52..3c62977bd77d3 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -111,7 +111,7 @@ impl Buffer { /// Helper to render an optional visibility with a space after it (if the /// visibility is preset) #[derive(Copy, Clone)] -pub struct VisSpace<'a>(pub &'a Option); +pub struct VisSpace<'a>(pub &'a clean::Visibility); /// Similarly to VisSpace, this structure is used to render a function style with a /// space after it. #[derive(Copy, Clone)] @@ -1034,11 +1034,7 @@ impl Function<'_> { impl<'a> fmt::Display for VisSpace<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(v) = self.0 { - fmt::Display::fmt(&v.print_with_space(), f) - } else { - Ok(()) - } + fmt::Display::fmt(&self.0.print_with_space(), f) } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 7aaf04f34d32f..32fa2daa026f7 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1511,7 +1511,7 @@ impl DocFolder for Cache { self.paths.insert(item.def_id, (stack, ItemType::Enum)); } - clean::PrimitiveItem(..) if item.visibility.is_some() => { + clean::PrimitiveItem(..) => { self.add_aliases(&item); self.paths.insert(item.def_id, (self.stack.clone(), item.type_())); @@ -4306,8 +4306,7 @@ fn get_methods( ) -> Vec { i.items.iter().filter_map(|item| { match item.name { - // Maybe check with clean::Visibility::Public as well? - Some(ref name) if !name.is_empty() && item.visibility.is_some() && item.is_method() => { + Some(ref name) if !name.is_empty() && item.is_method() => { if !for_deref || should_render_item(item, deref_mut) { Some(format!("{}", get_next_url(used_links, format!("method.{}", name)), diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index d0f2cdad8f3e4..f6560218a78c8 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -185,13 +185,13 @@ impl<'a> DocFolder for Stripper<'a> { } clean::StructFieldItem(..) => { - if i.visibility != Some(clean::Public) { + if i.visibility != clean::Public { return StripItem(i).strip(); } } clean::ModuleItem(..) => { - if i.def_id.is_local() && i.visibility != Some(clean::Public) { + if i.def_id.is_local() && i.visibility != clean::Public { debug!("Stripper: stripping module {:?}", i.name); let old = mem::replace(&mut self.update_retained, false); let ret = StripItem(self.fold_item_recur(i).unwrap()).strip(); @@ -299,7 +299,7 @@ impl DocFolder for ImportStripper { fn fold_item(&mut self, i: Item) -> Option { match i.inner { clean::ExternCrateItem(..) | clean::ImportItem(..) - if i.visibility != Some(clean::Public) => + if i.visibility != clean::Public => { None } From 8a9dab3a203ef26c6f8477bd388f2394747d598e Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 13 Sep 2019 08:36:00 -0400 Subject: [PATCH 13/55] Remove *Space wrappers in favor of direct impls or functions --- src/librustdoc/html/format.rs | 111 +++++++++++++--------------------- src/librustdoc/html/render.rs | 82 ++++++++++++------------- 2 files changed, 84 insertions(+), 109 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 3c62977bd77d3..fafd43cb60b69 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -108,28 +108,6 @@ impl Buffer { } } -/// Helper to render an optional visibility with a space after it (if the -/// visibility is preset) -#[derive(Copy, Clone)] -pub struct VisSpace<'a>(pub &'a clean::Visibility); -/// Similarly to VisSpace, this structure is used to render a function style with a -/// space after it. -#[derive(Copy, Clone)] -pub struct UnsafetySpace(pub hir::Unsafety); -/// Similarly to VisSpace, this structure is used to render a function constness -/// with a space after it. -#[derive(Copy, Clone)] -pub struct ConstnessSpace(pub hir::Constness); -/// Similarly to VisSpace, this structure is used to render a function asyncness -/// with a space after it. -#[derive(Copy, Clone)] -pub struct AsyncSpace(pub hir::IsAsync); -/// Similar to VisSpace, but used for mutability -#[derive(Copy, Clone)] -pub struct MutableSpace(pub clean::Mutability); -pub struct AbiSpace(pub Abi); -pub struct DefaultSpace(pub bool); - /// Wrapper struct for properly emitting a function or method declaration. pub struct Function<'a> { /// The declaration to emit. @@ -638,12 +616,13 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> clean::BareFunction(ref decl) => { if f.alternate() { write!(f, "{}{:#}fn{:#}{:#}", - UnsafetySpace(decl.unsafety), - AbiSpace(decl.abi), + decl.unsafety.print_with_space(), + print_abi_with_space(decl.abi), decl.print_generic_params(), decl.decl.print()) } else { - write!(f, "{}{}", UnsafetySpace(decl.unsafety), AbiSpace(decl.abi))?; + write!(f, "{}{}", + decl.unsafety.print_with_space(), print_abi_with_space(decl.abi))?; primitive_link(f, PrimitiveType::Fn, "fn")?; write!(f, "{}{}", decl.print_generic_params(), decl.decl.print()) } @@ -705,7 +684,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> Some(l) => format!("{} ", l.print()), _ => String::new() }; - let m = MutableSpace(mutability); + let m = mutability.print_with_space(); let amp = if f.alternate() { "&".to_string() } else { @@ -956,13 +935,13 @@ impl Function<'_> { } clean::SelfBorrowed(Some(ref lt), mtbl) => { args.push_str( - &format!("{}{} {}self", amp, lt.print(), MutableSpace(mtbl))); + &format!("{}{} {}self", amp, lt.print(), mtbl.print_with_space())); args_plain.push_str( - &format!("&{} {}self", lt.print(), MutableSpace(mtbl))); + &format!("&{} {}self", lt.print(), mtbl.print_with_space())); } clean::SelfBorrowed(None, mtbl) => { - args.push_str(&format!("{}{}self", amp, MutableSpace(mtbl))); - args_plain.push_str(&format!("&{}self", MutableSpace(mtbl))); + args.push_str(&format!("{}{}self", amp, mtbl.print_with_space())); + args_plain.push_str(&format!("&{}self", mtbl.print_with_space())); } clean::SelfExplicit(ref typ) => { if f.alternate() { @@ -1032,14 +1011,8 @@ impl Function<'_> { } } -impl<'a> fmt::Display for VisSpace<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self.0.print_with_space(), f) - } -} - impl clean::Visibility { - fn print_with_space(&self) -> impl fmt::Display + '_ { + crate fn print_with_space(&self) -> impl fmt::Display + '_ { display_fn(move |f| { match *self { clean::Public => f.write_str("pub "), @@ -1060,29 +1033,33 @@ impl clean::Visibility { } } -impl fmt::Display for UnsafetySpace { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 { - hir::Unsafety::Unsafe => write!(f, "unsafe "), - hir::Unsafety::Normal => Ok(()) +crate trait PrintWithSpace { + fn print_with_space(&self) -> &str; +} + +impl PrintWithSpace for hir::Unsafety { + fn print_with_space(&self) -> &str { + match self { + hir::Unsafety::Unsafe => "unsafe ", + hir::Unsafety::Normal => "" } } } -impl fmt::Display for ConstnessSpace { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 { - hir::Constness::Const => write!(f, "const "), - hir::Constness::NotConst => Ok(()) +impl PrintWithSpace for hir::Constness { + fn print_with_space(&self) -> &str { + match self { + hir::Constness::Const => "const ", + hir::Constness::NotConst => "" } } } -impl fmt::Display for AsyncSpace { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 { - hir::IsAsync::Async => write!(f, "async "), - hir::IsAsync::NotAsync => Ok(()), +impl PrintWithSpace for hir::IsAsync { + fn print_with_space(&self) -> &str { + match self { + hir::IsAsync::Async => "async ", + hir::IsAsync::NotAsync => "", } } } @@ -1156,32 +1133,30 @@ impl clean::TypeBinding { } } -impl fmt::Display for MutableSpace { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - MutableSpace(clean::Immutable) => Ok(()), - MutableSpace(clean::Mutable) => write!(f, "mut "), +impl clean::Mutability { + crate fn print_with_space(&self) -> &str { + match self { + clean::Immutable => "", + clean::Mutable => "mut ", } } } -impl fmt::Display for AbiSpace { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +crate fn print_abi_with_space(abi: Abi) -> impl fmt::Display { + display_fn(move |f| { let quot = if f.alternate() { "\"" } else { """ }; - match self.0 { + match abi { Abi::Rust => Ok(()), abi => write!(f, "extern {0}{1}{0} ", quot, abi.name()), } - } + }) } -impl fmt::Display for DefaultSpace { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.0 { - write!(f, "default ") - } else { - Ok(()) - } +crate fn print_default_space<'a>(v: bool) -> &'a str { + if v { + "default " + } else { + "" } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 32fa2daa026f7..0b3cf5ea1e226 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -65,9 +65,9 @@ use crate::docfs::{DocFS, ErrorStorage, PathError}; use crate::doctree; use crate::fold::DocFolder; use crate::html::escape::Escape; -use crate::html::format::{Buffer, AsyncSpace, ConstnessSpace}; -use crate::html::format::{print_generic_bounds, WhereClause, href, AbiSpace, DefaultSpace}; -use crate::html::format::{VisSpace, Function, UnsafetySpace, MutableSpace}; +use crate::html::format::{Buffer, PrintWithSpace, print_abi_with_space}; +use crate::html::format::{print_generic_bounds, WhereClause, href, print_default_space}; +use crate::html::format::{Function}; use crate::html::format::fmt_impl_for_trait_page; use crate::html::item_type::ItemType; use crate::html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine, ErrorCodes, IdMap}; @@ -2573,13 +2573,13 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean: match *src { Some(ref src) => { write!(w, "{}extern crate {} as {};", - VisSpace(&myitem.visibility), + myitem.visibility.print_with_space(), anchor(myitem.def_id, src), name) } None => { write!(w, "{}extern crate {};", - VisSpace(&myitem.visibility), + myitem.visibility.print_with_space(), anchor(myitem.def_id, name)) } } @@ -2588,7 +2588,7 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean: clean::ImportItem(ref import) => { write!(w, "{}{}", - VisSpace(&myitem.visibility), import.print()); + myitem.visibility.print_with_space(), import.print()); } _ => { @@ -2794,7 +2794,7 @@ fn item_constant(w: &mut Buffer, cx: &Context, it: &clean::Item, c: &clean::Cons render_attributes(w, it, false); write!(w, "{vis}const \ {name}: {typ}", - vis = VisSpace(&it.visibility), + vis = it.visibility.print_with_space(), name = it.name.as_ref().unwrap(), typ = c.type_.print()); document(w, cx, it) @@ -2805,8 +2805,8 @@ fn item_static(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Static render_attributes(w, it, false); write!(w, "{vis}static {mutability}\ {name}: {typ}", - vis = VisSpace(&it.visibility), - mutability = MutableSpace(s.mutability), + vis = it.visibility.print_with_space(), + mutability = s.mutability.print_with_space(), name = it.name.as_ref().unwrap(), typ = s.type_.print()); document(w, cx, it) @@ -2815,11 +2815,11 @@ fn item_static(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Static fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Function) { let header_len = format!( "{}{}{}{}{:#}fn {}{:#}", - VisSpace(&it.visibility), - ConstnessSpace(f.header.constness), - UnsafetySpace(f.header.unsafety), - AsyncSpace(f.header.asyncness), - AbiSpace(f.header.abi), + it.visibility.print_with_space(), + f.header.constness.print_with_space(), + f.header.unsafety.print_with_space(), + f.header.asyncness.print_with_space(), + print_abi_with_space(f.header.abi), it.name.as_ref().unwrap(), f.generics.print() ).len(); @@ -2828,11 +2828,11 @@ fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Func write!(w, "{vis}{constness}{unsafety}{asyncness}{abi}fn \ {name}{generics}{decl}{where_clause}", - vis = VisSpace(&it.visibility), - constness = ConstnessSpace(f.header.constness), - unsafety = UnsafetySpace(f.header.unsafety), - asyncness = AsyncSpace(f.header.asyncness), - abi = AbiSpace(f.header.abi), + vis = it.visibility.print_with_space(), + constness = f.header.constness.print_with_space(), + unsafety = f.header.unsafety.print_with_space(), + asyncness = f.header.asyncness.print_with_space(), + abi = print_abi_with_space(f.header.abi), name = it.name.as_ref().unwrap(), generics = f.generics.print(), where_clause = WhereClause { gens: &f.generics, indent: 0, end_newline: true }, @@ -2913,8 +2913,8 @@ fn item_trait( write!(w, "
    ");
             render_attributes(w, it, true);
             write!(w, "{}{}{}trait {}{}{}",
    -               VisSpace(&it.visibility),
    -               UnsafetySpace(t.unsafety),
    +               it.visibility.print_with_space(),
    +               t.unsafety.print_with_space(),
                    if t.is_auto { "auto " } else { "" },
                    it.name.as_ref().unwrap(),
                    t.generics.print(),
    @@ -3175,7 +3175,7 @@ fn assoc_const(w: &mut Buffer,
                    extra: &str) {
         write!(w, "{}{}const {}: {}",
                extra,
    -           VisSpace(&it.visibility),
    +           it.visibility.print_with_space(),
                naive_assoc_href(it, link),
                it.name.as_ref().unwrap(),
                ty.print());
    @@ -3240,12 +3240,12 @@ fn render_assoc_item(w: &mut Buffer,
             };
             let mut header_len = format!(
                 "{}{}{}{}{}{:#}fn {}{:#}",
    -            VisSpace(&meth.visibility),
    -            ConstnessSpace(header.constness),
    -            UnsafetySpace(header.unsafety),
    -            AsyncSpace(header.asyncness),
    -            DefaultSpace(meth.is_default()),
    -            AbiSpace(header.abi),
    +            meth.visibility.print_with_space(),
    +            header.constness.print_with_space(),
    +            header.unsafety.print_with_space(),
    +            header.asyncness.print_with_space(),
    +            print_default_space(meth.is_default()),
    +            print_abi_with_space(header.abi),
                 name,
                 g.print()
             ).len();
    @@ -3259,12 +3259,12 @@ fn render_assoc_item(w: &mut Buffer,
             write!(w, "{}{}{}{}{}{}{}fn {name}\
                        {generics}{decl}{where_clause}",
                    if parent == ItemType::Trait { "    " } else { "" },
    -               VisSpace(&meth.visibility),
    -               ConstnessSpace(header.constness),
    -               UnsafetySpace(header.unsafety),
    -               AsyncSpace(header.asyncness),
    -               DefaultSpace(meth.is_default()),
    -               AbiSpace(header.abi),
    +               meth.visibility.print_with_space(),
    +               header.constness.print_with_space(),
    +               header.unsafety.print_with_space(),
    +               header.asyncness.print_with_space(),
    +               print_default_space(meth.is_default()),
    +               print_abi_with_space(header.abi),
                    href = href,
                    name = name,
                    generics = g.print(),
    @@ -3399,7 +3399,7 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum) {
             write!(w, "
    ");
             render_attributes(w, it, true);
             write!(w, "{}enum {}{}{}",
    -               VisSpace(&it.visibility),
    +               it.visibility.print_with_space(),
                    it.name.as_ref().unwrap(),
                    e.generics.print(),
                    WhereClause { gens: &e.generics, indent: 0, end_newline: true });
    @@ -3588,7 +3588,7 @@ fn render_struct(w: &mut Buffer, it: &clean::Item,
                      tab: &str,
                      structhead: bool) {
         write!(w, "{}{}{}",
    -           VisSpace(&it.visibility),
    +           it.visibility.print_with_space(),
                if structhead {"struct "} else {""},
                it.name.as_ref().unwrap());
         if let Some(g) = g {
    @@ -3605,7 +3605,7 @@ fn render_struct(w: &mut Buffer, it: &clean::Item,
                     if let clean::StructFieldItem(ref ty) = field.inner {
                         write!(w, "\n{}    {}{}: {},",
                                tab,
    -                           VisSpace(&field.visibility),
    +                           field.visibility.print_with_space(),
                                field.name.as_ref().unwrap(),
                                ty.print());
                         has_visible_fields = true;
    @@ -3635,7 +3635,7 @@ fn render_struct(w: &mut Buffer, it: &clean::Item,
                             write!(w, "_")
                         }
                         clean::StructFieldItem(ref ty) => {
    -                        write!(w, "{}{}", VisSpace(&field.visibility), ty.print())
    +                        write!(w, "{}{}", field.visibility.print_with_space(), ty.print())
                         }
                         _ => unreachable!()
                     }
    @@ -3662,7 +3662,7 @@ fn render_union(w: &mut Buffer, it: &clean::Item,
                     tab: &str,
                     structhead: bool) {
         write!(w, "{}{}{}",
    -           VisSpace(&it.visibility),
    +           it.visibility.print_with_space(),
                if structhead {"union "} else {""},
                it.name.as_ref().unwrap());
         if let Some(g) = g {
    @@ -3674,7 +3674,7 @@ fn render_union(w: &mut Buffer, it: &clean::Item,
         for field in fields {
             if let clean::StructFieldItem(ref ty) = field.inner {
                 write!(w, "    {}{}: {},\n{}",
    -                   VisSpace(&field.visibility),
    +                   field.visibility.print_with_space(),
                        field.name.as_ref().unwrap(),
                        ty.print(),
                        tab);
    @@ -4186,7 +4186,7 @@ fn item_foreign_type(w: &mut Buffer, cx: &Context, it: &clean::Item) {
         write!(
             w,
             "    {}type {};\n}}
    ", - VisSpace(&it.visibility), + it.visibility.print_with_space(), it.name.as_ref().unwrap(), ); From 3f144e119ec958b2a6ac3db3568b1bd2b3ba488a Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 13 Sep 2019 08:41:27 -0400 Subject: [PATCH 14/55] Move Toc printing from fmt::Display --- src/librustdoc/html/markdown.rs | 2 +- src/librustdoc/html/toc.rs | 37 ++++++++++++++------------------- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 1a4fa38ff8db0..9ff1e1d31197d 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -752,7 +752,7 @@ impl MarkdownWithToc<'_> { html::push_html(&mut s, p); } - format!("{}", toc.into_toc(), s) + format!("{}", toc.into_toc().print(), s) } } diff --git a/src/librustdoc/html/toc.rs b/src/librustdoc/html/toc.rs index 2da7aceae8bf4..0fb2f8dd7962a 100644 --- a/src/librustdoc/html/toc.rs +++ b/src/librustdoc/html/toc.rs @@ -1,10 +1,7 @@ //! Table-of-contents creation. -use std::fmt; -use std::string::String; - /// A (recursive) table of contents -#[derive(PartialEq)] +#[derive(Debug, PartialEq)] pub struct Toc { /// The levels are strictly decreasing, i.e. /// @@ -28,7 +25,7 @@ impl Toc { } } -#[derive(PartialEq)] +#[derive(Debug, PartialEq)] pub struct TocEntry { level: u32, sec_number: String, @@ -165,25 +162,23 @@ impl TocBuilder { } } -impl fmt::Debug for Toc { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, f) - } -} - -impl fmt::Display for Toc { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "
      ")?; +impl Toc { + fn print_inner(&self, v: &mut String) { + v.push_str("
        "); for entry in &self.entries { - // recursively format this table of contents (the - // `{children}` is the key). - write!(fmt, - "\n
      • {num} {name}{children}
      • ", + // recursively format this table of contents + v.push_str(&format!("\n
      • {num} {name}", id = entry.id, - num = entry.sec_number, name = entry.name, - children = entry.children)? + num = entry.sec_number, name = entry.name)); + entry.children.print_inner(&mut *v); + v.push_str("
      • "); } - write!(fmt, "
      ") + v.push_str("
    "); + } + crate fn print(&self) -> String { + let mut v = String::new(); + self.print_inner(&mut v); + v } } From aa4055cd6c92095c1996dd6eb31b08cced604e88 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 13 Sep 2019 08:42:58 -0400 Subject: [PATCH 15/55] Simplify render_spotlight_traits --- src/librustdoc/html/render.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 0b3cf5ea1e226..8d5bd0d2e16e1 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -3858,19 +3858,15 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool) -> bool { } fn render_spotlight_traits(item: &clean::Item) -> String { - let mut out = String::new(); - match item.inner { clean::FunctionItem(clean::Function { ref decl, .. }) | clean::TyMethodItem(clean::TyMethod { ref decl, .. }) | clean::MethodItem(clean::Method { ref decl, .. }) | clean::ForeignFunctionItem(clean::Function { ref decl, .. }) => { - out = spotlight_decl(decl); + spotlight_decl(decl) } - _ => {} + _ => String::new() } - - out } fn spotlight_decl(decl: &clean::FnDecl) -> String { From e0e0c3787ca64d8c2540d703ca1e2f26607c5717 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 13 Sep 2019 09:26:11 -0400 Subject: [PATCH 16/55] Replace SlashChecker with ensure_trailing_slash --- src/librustdoc/html/layout.rs | 4 ++-- src/librustdoc/html/render.rs | 22 ++++++++++------------ 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 56074f4ab1192..6414241727a72 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; use crate::externalfiles::ExternalHtml; -use crate::html::render::SlashChecker; +use crate::html::render::ensure_trailing_slash; use crate::html::format::{Buffer, Print}; #[derive(Clone)] @@ -180,7 +180,7 @@ pub fn render( css_class = page.css_class, logo = { let p = format!("{}{}", page.root_path, layout.krate); - let p = SlashChecker(&p); + let p = ensure_trailing_slash(&p); if layout.logo.is_empty() { format!("\
    \ diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 8d5bd0d2e16e1..9064dc8b44db4 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -33,7 +33,7 @@ use std::cmp::Ordering; use std::collections::{BTreeMap, VecDeque}; use std::default::Default; use std::error; -use std::fmt::{self, Display, Formatter, Write as FmtWrite}; +use std::fmt::{self, Formatter, Write as FmtWrite}; use std::ffi::OsStr; use std::fs::{self, File}; use std::io::prelude::*; @@ -82,16 +82,14 @@ mod tests; /// A pair of name and its optional document. pub type NameDoc = (String, Option); -pub struct SlashChecker<'a>(pub &'a str); - -impl<'a> Display for SlashChecker<'a> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - if !self.0.ends_with("/") && !self.0.is_empty() { - write!(f, "{}/", self.0) +crate fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ { + crate::html::format::display_fn(move |f| { + if !v.ends_with("/") && !v.is_empty() { + write!(f, "{}/", v) } else { - write!(f, "{}", self.0) + write!(f, "{}", v) } - } + }) } #[derive(Debug)] @@ -106,7 +104,7 @@ impl error::Error for Error { } } -impl Display for Error { +impl std::fmt::Display for Error { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let file = self.file.display().to_string(); if file.is_empty() { @@ -1162,7 +1160,7 @@ themePicker.onblur = handleThemeButtonsBlur; .iter() .map(|s| { format!("
  • {}
  • ", - SlashChecker(s), s) + ensure_trailing_slash(s), s) }) .collect::()); let v = layout::render(&cx.shared.layout, @@ -2286,7 +2284,7 @@ fn print_item(cx: &Context, item: &clean::Item, buf: &mut Buffer) { fn item_path(ty: ItemType, name: &str) -> String { match ty { - ItemType::Module => format!("{}index.html", SlashChecker(name)), + ItemType::Module => format!("{}index.html", ensure_trailing_slash(name)), _ => format!("{}.{}.html", ty, name), } } From 98c94f6f771c0e3894a65e82572c5dca1c43167d Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 13 Sep 2019 09:51:32 -0400 Subject: [PATCH 17/55] Move edition field out of Context --- src/librustdoc/html/render.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 9064dc8b44db4..1ecb2293fc22c 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -164,8 +164,6 @@ struct Context { /// publicly reused items to redirect to the right location. pub render_redirect_pages: bool, pub codes: ErrorCodes, - /// The default edition used to parse doctests. - pub edition: Edition, /// The map used to ensure all generated 'id=' attributes are unique. id_map: Rc>, pub shared: Arc, @@ -208,6 +206,8 @@ crate struct SharedContext { pub generate_redirect_pages: bool, /// The fs handle we are working with. pub fs: DocFS, + /// The default edition used to parse doctests. + pub edition: Edition, } impl SharedContext { @@ -539,6 +539,7 @@ pub fn run(mut krate: clean::Crate, static_root_path, generate_redirect_pages, fs: DocFS::new(&errors), + edition, }; // If user passed in `--playground-url` arg, we fill in crate name here @@ -585,7 +586,6 @@ pub fn run(mut krate: clean::Crate, dst, render_redirect_pages: false, codes: ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()), - edition, id_map: Rc::new(RefCell::new(id_map)), shared: Arc::new(scx), playground, @@ -1134,7 +1134,7 @@ themePicker.onblur = handleThemeButtonsBlur; md_opts.output = cx.dst.clone(); md_opts.external_html = (*cx.shared).layout.external_html.clone(); - crate::markdown::render(index_page, md_opts, diag, cx.edition); + crate::markdown::render(index_page, md_opts, diag, cx.shared.edition); } else { let dst = cx.dst.join("index.html"); let page = layout::Page { @@ -2353,7 +2353,7 @@ fn render_markdown( if is_hidden { " hidden" } else { "" }, prefix, Markdown(md_text, &links, &mut ids, - cx.codes, cx.edition, &cx.playground).to_string()) + cx.codes, cx.shared.edition, &cx.playground).to_string()) } fn document_short( @@ -2710,7 +2710,8 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec { if let Some(note) = note { let mut ids = cx.id_map.borrow_mut(); - let html = MarkdownHtml(¬e, &mut ids, error_codes, cx.edition, &cx.playground); + let html = MarkdownHtml( + ¬e, &mut ids, error_codes, cx.shared.edition, &cx.playground); message.push_str(&format!(": {}", html.to_string())); } stability.push(format!("
    {}
    ", message)); @@ -2763,7 +2764,7 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec { &unstable_reason, &mut ids, error_codes, - cx.edition, + cx.shared.edition, &cx.playground, ).to_string() ); @@ -3960,7 +3961,7 @@ fn render_impl(w: &mut Buffer, cx: &Context, i: &Impl, link: AssocItemLink<'_>, let mut ids = cx.id_map.borrow_mut(); write!(w, "
    {}
    ", Markdown(&*dox, &i.impl_item.links(), &mut ids, - cx.codes, cx.edition, &cx.playground).to_string()); + cx.codes, cx.shared.edition, &cx.playground).to_string()); } } From c26518086eed253924f2f9b91f2dd812084e4b31 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 13 Sep 2019 10:34:04 -0400 Subject: [PATCH 18/55] Move error codes to shared context --- src/librustdoc/html/render.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 1ecb2293fc22c..fb751041644ee 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -163,7 +163,6 @@ struct Context { /// real location of an item. This is used to allow external links to /// publicly reused items to redirect to the right location. pub render_redirect_pages: bool, - pub codes: ErrorCodes, /// The map used to ensure all generated 'id=' attributes are unique. id_map: Rc>, pub shared: Arc, @@ -208,6 +207,7 @@ crate struct SharedContext { pub fs: DocFS, /// The default edition used to parse doctests. pub edition: Edition, + pub codes: ErrorCodes, } impl SharedContext { @@ -540,6 +540,7 @@ pub fn run(mut krate: clean::Crate, generate_redirect_pages, fs: DocFS::new(&errors), edition, + codes: ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()), }; // If user passed in `--playground-url` arg, we fill in crate name here @@ -585,7 +586,6 @@ pub fn run(mut krate: clean::Crate, current: Vec::new(), dst, render_redirect_pages: false, - codes: ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()), id_map: Rc::new(RefCell::new(id_map)), shared: Arc::new(scx), playground, @@ -2353,7 +2353,7 @@ fn render_markdown( if is_hidden { " hidden" } else { "" }, prefix, Markdown(md_text, &links, &mut ids, - cx.codes, cx.shared.edition, &cx.playground).to_string()) + cx.shared.codes, cx.shared.edition, &cx.playground).to_string()) } fn document_short( @@ -3961,7 +3961,7 @@ fn render_impl(w: &mut Buffer, cx: &Context, i: &Impl, link: AssocItemLink<'_>, let mut ids = cx.id_map.borrow_mut(); write!(w, "
    {}
    ", Markdown(&*dox, &i.impl_item.links(), &mut ids, - cx.codes, cx.shared.edition, &cx.playground).to_string()); + cx.shared.codes, cx.shared.edition, &cx.playground).to_string()); } } From f4bb5a7c1a3183f1af14695a48258331b0360860 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 13 Sep 2019 10:40:22 -0400 Subject: [PATCH 19/55] Move playground to shared context --- src/librustdoc/html/render.rs | 73 ++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index fb751041644ee..9d5cddd6d47a7 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -166,7 +166,6 @@ struct Context { /// The map used to ensure all generated 'id=' attributes are unique. id_map: Rc>, pub shared: Arc, - playground: Option, } crate struct SharedContext { @@ -208,6 +207,7 @@ crate struct SharedContext { /// The default edition used to parse doctests. pub edition: Edition, pub codes: ErrorCodes, + playground: Option, } impl SharedContext { @@ -518,31 +518,6 @@ pub fn run(mut krate: clean::Crate, _ => PathBuf::new(), }; let mut errors = Arc::new(ErrorStorage::new()); - let mut scx = SharedContext { - collapsed: krate.collapsed, - src_root, - include_sources: true, - local_sources: Default::default(), - issue_tracker_base_url: None, - layout: layout::Layout { - logo: String::new(), - favicon: String::new(), - external_html, - krate: krate.name.clone(), - css_file_extension: extension_css, - generate_search_filter, - }, - created_dirs: Default::default(), - sort_modules_alphabetically, - themes, - resource_suffix, - static_root_path, - generate_redirect_pages, - fs: DocFS::new(&errors), - edition, - codes: ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()), - }; - // If user passed in `--playground-url` arg, we fill in crate name here let mut playground = None; if let Some(url) = playground_url { @@ -551,6 +526,16 @@ pub fn run(mut krate: clean::Crate, url, }); } + let mut layout = layout::Layout { + logo: String::new(), + favicon: String::new(), + external_html, + krate: krate.name.clone(), + css_file_extension: extension_css, + generate_search_filter, + }; + let mut issue_tracker_base_url = None; + let mut include_sources = true; // Crawl the crate attributes looking for attributes which control how we're // going to emit HTML @@ -558,10 +543,10 @@ pub fn run(mut krate: clean::Crate, for attr in attrs.lists(sym::doc) { match (attr.name_or_empty(), attr.value_str()) { (sym::html_favicon_url, Some(s)) => { - scx.layout.favicon = s.to_string(); + layout.favicon = s.to_string(); } (sym::html_logo_url, Some(s)) => { - scx.layout.logo = s.to_string(); + layout.logo = s.to_string(); } (sym::html_playground_url, Some(s)) => { playground = Some(markdown::Playground { @@ -570,15 +555,34 @@ pub fn run(mut krate: clean::Crate, }); } (sym::issue_tracker_base_url, Some(s)) => { - scx.issue_tracker_base_url = Some(s.to_string()); + issue_tracker_base_url = Some(s.to_string()); } (sym::html_no_source, None) if attr.is_word() => { - scx.include_sources = false; + include_sources = false; } _ => {} } } } + let mut scx = SharedContext { + collapsed: krate.collapsed, + src_root, + include_sources, + local_sources: Default::default(), + issue_tracker_base_url, + layout, + created_dirs: Default::default(), + sort_modules_alphabetically, + themes, + resource_suffix, + static_root_path, + generate_redirect_pages, + fs: DocFS::new(&errors), + edition, + codes: ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()), + playground, + }; + let dst = output; scx.ensure_dir(&dst)?; krate = sources::render(&dst, &mut scx, krate)?; @@ -588,7 +592,6 @@ pub fn run(mut krate: clean::Crate, render_redirect_pages: false, id_map: Rc::new(RefCell::new(id_map)), shared: Arc::new(scx), - playground, }; // Crawl the crate to build various caches used for the output @@ -2353,7 +2356,7 @@ fn render_markdown( if is_hidden { " hidden" } else { "" }, prefix, Markdown(md_text, &links, &mut ids, - cx.shared.codes, cx.shared.edition, &cx.playground).to_string()) + cx.shared.codes, cx.shared.edition, &cx.shared.playground).to_string()) } fn document_short( @@ -2711,7 +2714,7 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec { if let Some(note) = note { let mut ids = cx.id_map.borrow_mut(); let html = MarkdownHtml( - ¬e, &mut ids, error_codes, cx.shared.edition, &cx.playground); + ¬e, &mut ids, error_codes, cx.shared.edition, &cx.shared.playground); message.push_str(&format!(": {}", html.to_string())); } stability.push(format!("
    {}
    ", message)); @@ -2765,7 +2768,7 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec { &mut ids, error_codes, cx.shared.edition, - &cx.playground, + &cx.shared.playground, ).to_string() ); } @@ -3961,7 +3964,7 @@ fn render_impl(w: &mut Buffer, cx: &Context, i: &Impl, link: AssocItemLink<'_>, let mut ids = cx.id_map.borrow_mut(); write!(w, "
    {}
    ", Markdown(&*dox, &i.impl_item.links(), &mut ids, - cx.shared.codes, cx.shared.edition, &cx.playground).to_string()); + cx.shared.codes, cx.shared.edition, &cx.shared.playground).to_string()); } } From f5ed0fd1c0175679c7f72ee0e6f8f5532f94a69f Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 13 Sep 2019 11:22:12 -0400 Subject: [PATCH 20/55] Move `Cache` generation to separate module --- src/librustdoc/html/render.rs | 668 +-------------------------- src/librustdoc/html/render/cache.rs | 675 ++++++++++++++++++++++++++++ 2 files changed, 689 insertions(+), 654 deletions(-) create mode 100644 src/librustdoc/html/render/cache.rs diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 9d5cddd6d47a7..ff7134ab7c0d5 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -25,8 +25,6 @@ //! These threads are not parallelized (they haven't been a bottleneck yet), and //! both occur before the crate is rendered. -pub use self::ExternalLocation::*; - use std::borrow::Cow; use std::cell::{Cell, RefCell}; use std::cmp::Ordering; @@ -38,7 +36,6 @@ use std::ffi::OsStr; use std::fs::{self, File}; use std::io::prelude::*; use std::io::{self, BufReader}; -use std::mem; use std::path::{PathBuf, Path, Component}; use std::str; use std::sync::Arc; @@ -52,7 +49,7 @@ use syntax::ext::base::MacroKind; use syntax::source_map::FileName; use syntax::feature_gate::UnstableFeatures; use syntax::symbol::{Symbol, sym}; -use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId}; +use rustc::hir::def_id::DefId; use rustc::middle::privacy::AccessLevels; use rustc::middle::stability; use rustc::hir; @@ -63,7 +60,6 @@ use crate::clean::{self, AttributesExt, Deprecation, GetDefId, SelfTy, Mutabilit use crate::config::RenderOptions; use crate::docfs::{DocFS, ErrorStorage, PathError}; use crate::doctree; -use crate::fold::DocFolder; use crate::html::escape::Escape; use crate::html::format::{Buffer, PrintWithSpace, print_abi_with_space}; use crate::html::format::{print_generic_bounds, WhereClause, href, print_default_space}; @@ -79,6 +75,11 @@ use minifier; #[cfg(test)] mod tests; +mod cache; + +use cache::Cache; +crate use cache::ExternalLocation::{self, *}; + /// A pair of name and its optional document. pub type NameDoc = (String, Option); @@ -234,16 +235,6 @@ impl SharedContext { } } -/// Indicates where an external crate can be found. -pub enum ExternalLocation { - /// Remote URL root of the external crate - Remote(String), - /// This external crate can be found in the local doc/ folder - Local, - /// The external crate could not be found. - Unknown, -} - /// Metadata about implementations for a type or trait. #[derive(Clone, Debug)] pub struct Impl { @@ -263,106 +254,6 @@ impl Impl { } } -/// This cache is used to store information about the `clean::Crate` being -/// rendered in order to provide more useful documentation. This contains -/// information like all implementors of a trait, all traits a type implements, -/// documentation for all known traits, etc. -/// -/// This structure purposefully does not implement `Clone` because it's intended -/// to be a fairly large and expensive structure to clone. Instead this adheres -/// to `Send` so it may be stored in a `Arc` instance and shared among the various -/// rendering threads. -#[derive(Default)] -pub struct Cache { - /// Maps a type ID to all known implementations for that type. This is only - /// recognized for intra-crate `ResolvedPath` types, and is used to print - /// out extra documentation on the page of an enum/struct. - /// - /// The values of the map are a list of implementations and documentation - /// found on that implementation. - pub impls: FxHashMap>, - - /// Maintains a mapping of local crate `NodeId`s to the fully qualified name - /// and "short type description" of that node. This is used when generating - /// URLs when a type is being linked to. External paths are not located in - /// this map because the `External` type itself has all the information - /// necessary. - pub paths: FxHashMap, ItemType)>, - - /// Similar to `paths`, but only holds external paths. This is only used for - /// generating explicit hyperlinks to other crates. - pub external_paths: FxHashMap, ItemType)>, - - /// Maps local `DefId`s of exported types to fully qualified paths. - /// Unlike 'paths', this mapping ignores any renames that occur - /// due to 'use' statements. - /// - /// This map is used when writing out the special 'implementors' - /// javascript file. By using the exact path that the type - /// is declared with, we ensure that each path will be identical - /// to the path used if the corresponding type is inlined. By - /// doing this, we can detect duplicate impls on a trait page, and only display - /// the impl for the inlined type. - pub exact_paths: FxHashMap>, - - /// This map contains information about all known traits of this crate. - /// Implementations of a crate should inherit the documentation of the - /// parent trait if no extra documentation is specified, and default methods - /// should show up in documentation about trait implementations. - pub traits: FxHashMap, - - /// When rendering traits, it's often useful to be able to list all - /// implementors of the trait, and this mapping is exactly, that: a mapping - /// of trait ids to the list of known implementors of the trait - pub implementors: FxHashMap>, - - /// Cache of where external crate documentation can be found. - pub extern_locations: FxHashMap, - - /// Cache of where documentation for primitives can be found. - pub primitive_locations: FxHashMap, - - // Note that external items for which `doc(hidden)` applies to are shown as - // non-reachable while local items aren't. This is because we're reusing - // the access levels from the privacy check pass. - pub access_levels: AccessLevels, - - /// The version of the crate being documented, if given from the `--crate-version` flag. - pub crate_version: Option, - - // Private fields only used when initially crawling a crate to build a cache - - stack: Vec, - parent_stack: Vec, - parent_is_trait_impl: bool, - search_index: Vec, - stripped_mod: bool, - deref_trait_did: Option, - deref_mut_trait_did: Option, - owned_box_did: Option, - masked_crates: FxHashSet, - - // In rare case where a structure is defined in one module but implemented - // in another, if the implementing module is parsed before defining module, - // then the fully qualified name of the structure isn't presented in `paths` - // yet when its implementation methods are being indexed. Caches such methods - // and their parent id here and indexes them at the end of crate parsing. - orphan_impl_items: Vec<(DefId, clean::Item)>, - - // Similarly to `orphan_impl_items`, sometimes trait impls are picked up - // even though the trait itself is not exported. This can happen if a trait - // was defined in function/expression scope, since the impl will be picked - // up by `collect-trait-impls` but the trait won't be scraped out in the HIR - // crawl. In order to prevent crashes when looking for spotlight traits or - // when gathering trait documentation on a type, hold impls here while - // folding and add them to the cache later on if we find the trait. - orphan_trait_impls: Vec<(DefId, FxHashSet, Impl)>, - - /// Aliases added through `#[doc(alias = "...")]`. Since a few items can have the same alias, - /// we need the alias element to have an array of items. - aliases: FxHashMap>, -} - /// Temporary storage for data obtained during `RustdocVisitor::clean()`. /// Later on moved into `CACHE_KEY`. #[derive(Default)] @@ -594,89 +485,13 @@ pub fn run(mut krate: clean::Crate, shared: Arc::new(scx), }; - // Crawl the crate to build various caches used for the output - let RenderInfo { - inlined: _, - external_paths, - exact_paths, - access_levels, - deref_trait_did, - deref_mut_trait_did, - owned_box_did, - } = renderinfo; - - let external_paths = external_paths.into_iter() - .map(|(k, (v, t))| (k, (v, ItemType::from(t)))) - .collect(); - - let mut cache = Cache { - impls: Default::default(), - external_paths, - exact_paths, - paths: Default::default(), - implementors: Default::default(), - stack: Vec::new(), - parent_stack: Vec::new(), - search_index: Vec::new(), - parent_is_trait_impl: false, - extern_locations: Default::default(), - primitive_locations: Default::default(), - stripped_mod: false, - access_levels, - crate_version: krate.version.take(), - orphan_impl_items: Vec::new(), - orphan_trait_impls: Vec::new(), - traits: krate.external_traits.replace(Default::default()), - deref_trait_did, - deref_mut_trait_did, - owned_box_did, - masked_crates: mem::take(&mut krate.masked_crates), - aliases: Default::default(), - }; - - // Cache where all our extern crates are located - for &(n, ref e) in &krate.externs { - let src_root = match e.src { - FileName::Real(ref p) => match p.parent() { - Some(p) => p.to_path_buf(), - None => PathBuf::new(), - }, - _ => PathBuf::new(), - }; - let extern_url = extern_html_root_urls.get(&e.name).map(|u| &**u); - cache.extern_locations.insert(n, (e.name.clone(), src_root, - extern_location(e, extern_url, &cx.dst))); - - let did = DefId { krate: n, index: CRATE_DEF_INDEX }; - cache.external_paths.insert(did, (vec![e.name.to_string()], ItemType::Module)); - } - - // Cache where all known primitives have their documentation located. - // - // Favor linking to as local extern as possible, so iterate all crates in - // reverse topological order. - for &(_, ref e) in krate.externs.iter().rev() { - for &(def_id, prim, _) in &e.primitives { - cache.primitive_locations.insert(prim, def_id); - } - } - for &(def_id, prim, _) in &krate.primitives { - cache.primitive_locations.insert(prim, def_id); - } - - cache.stack.push(krate.name.clone()); - krate = cache.fold_crate(krate); - - for (trait_did, dids, impl_) in cache.orphan_trait_impls.drain(..) { - if cache.traits.contains_key(&trait_did) { - for did in dids { - cache.impls.entry(did).or_insert(vec![]).push(impl_.clone()); - } - } - } - - // Build our search index - let index = build_index(&krate, &mut cache); + let (new_crate, index, cache) = Cache::from_krate( + renderinfo, + &extern_html_root_urls, + &cx.dst, + krate, + ); + krate = new_crate; // Freeze the cache now that the index has been built. Put an Arc into TLS // for future parallelization opportunities @@ -701,76 +516,6 @@ pub fn run(mut krate: clean::Crate, } } -/// Builds the search index from the collected metadata -fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { - let mut nodeid_to_pathid = FxHashMap::default(); - let mut crate_items = Vec::with_capacity(cache.search_index.len()); - let mut crate_paths = Vec::::new(); - - let Cache { ref mut search_index, - ref orphan_impl_items, - ref mut paths, .. } = *cache; - - // Attach all orphan items to the type's definition if the type - // has since been learned. - for &(did, ref item) in orphan_impl_items { - if let Some(&(ref fqp, _)) = paths.get(&did) { - search_index.push(IndexItem { - ty: item.type_(), - name: item.name.clone().unwrap(), - path: fqp[..fqp.len() - 1].join("::"), - desc: shorten(plain_summary_line(item.doc_value())), - parent: Some(did), - parent_idx: None, - search_type: get_index_search_type(&item), - }); - } - } - - // Reduce `NodeId` in paths into smaller sequential numbers, - // and prune the paths that do not appear in the index. - let mut lastpath = String::new(); - let mut lastpathid = 0usize; - - for item in search_index { - item.parent_idx = item.parent.map(|nodeid| { - if nodeid_to_pathid.contains_key(&nodeid) { - *nodeid_to_pathid.get(&nodeid).unwrap() - } else { - let pathid = lastpathid; - nodeid_to_pathid.insert(nodeid, pathid); - lastpathid += 1; - - let &(ref fqp, short) = paths.get(&nodeid).unwrap(); - crate_paths.push(((short as usize), fqp.last().unwrap().clone()).to_json()); - pathid - } - }); - - // Omit the parent path if it is same to that of the prior item. - if lastpath == item.path { - item.path.clear(); - } else { - lastpath = item.path.clone(); - } - crate_items.push(item.to_json()); - } - - let crate_doc = krate.module.as_ref().map(|module| { - shorten(plain_summary_line(module.doc_value())) - }).unwrap_or(String::new()); - - let mut crate_data = BTreeMap::new(); - crate_data.insert("doc".to_owned(), Json::String(crate_doc)); - crate_data.insert("i".to_owned(), Json::Array(crate_items)); - crate_data.insert("p".to_owned(), Json::Array(crate_paths)); - - // Collect the index into a string - format!("searchIndex[{}] = {};", - as_json(&krate.name), - Json::Object(crate_data)) -} - fn write_shared( cx: &Context, krate: &clean::Crate, @@ -1327,327 +1072,6 @@ fn minify_replacer( } } -/// Attempts to find where an external crate is located, given that we're -/// rendering in to the specified source destination. -fn extern_location(e: &clean::ExternalCrate, extern_url: Option<&str>, dst: &Path) - -> ExternalLocation -{ - // See if there's documentation generated into the local directory - let local_location = dst.join(&e.name); - if local_location.is_dir() { - return Local; - } - - if let Some(url) = extern_url { - let mut url = url.to_string(); - if !url.ends_with("/") { - url.push('/'); - } - return Remote(url); - } - - // Failing that, see if there's an attribute specifying where to find this - // external crate - e.attrs.lists(sym::doc) - .filter(|a| a.check_name(sym::html_root_url)) - .filter_map(|a| a.value_str()) - .map(|url| { - let mut url = url.to_string(); - if !url.ends_with("/") { - url.push('/') - } - Remote(url) - }).next().unwrap_or(Unknown) // Well, at least we tried. -} - -impl DocFolder for Cache { - fn fold_item(&mut self, item: clean::Item) -> Option { - if item.def_id.is_local() { - debug!("folding {} \"{:?}\", id {:?}", item.type_(), item.name, item.def_id); - } - - // If this is a stripped module, - // we don't want it or its children in the search index. - let orig_stripped_mod = match item.inner { - clean::StrippedItem(box clean::ModuleItem(..)) => { - mem::replace(&mut self.stripped_mod, true) - } - _ => self.stripped_mod, - }; - - // If the impl is from a masked crate or references something from a - // masked crate then remove it completely. - if let clean::ImplItem(ref i) = item.inner { - if self.masked_crates.contains(&item.def_id.krate) || - i.trait_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate)) || - i.for_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate)) { - return None; - } - } - - // Propagate a trait method's documentation to all implementors of the - // trait. - if let clean::TraitItem(ref t) = item.inner { - self.traits.entry(item.def_id).or_insert_with(|| t.clone()); - } - - // Collect all the implementors of traits. - if let clean::ImplItem(ref i) = item.inner { - if let Some(did) = i.trait_.def_id() { - if i.blanket_impl.is_none() { - self.implementors.entry(did).or_default().push(Impl { - impl_item: item.clone(), - }); - } - } - } - - // Index this method for searching later on. - if let Some(ref s) = item.name { - let (parent, is_inherent_impl_item) = match item.inner { - clean::StrippedItem(..) => ((None, None), false), - clean::AssocConstItem(..) | - clean::TypedefItem(_, true) if self.parent_is_trait_impl => { - // skip associated items in trait impls - ((None, None), false) - } - clean::AssocTypeItem(..) | - clean::TyMethodItem(..) | - clean::StructFieldItem(..) | - clean::VariantItem(..) => { - ((Some(*self.parent_stack.last().unwrap()), - Some(&self.stack[..self.stack.len() - 1])), - false) - } - clean::MethodItem(..) | clean::AssocConstItem(..) => { - if self.parent_stack.is_empty() { - ((None, None), false) - } else { - let last = self.parent_stack.last().unwrap(); - let did = *last; - let path = match self.paths.get(&did) { - // The current stack not necessarily has correlation - // for where the type was defined. On the other - // hand, `paths` always has the right - // information if present. - Some(&(ref fqp, ItemType::Trait)) | - Some(&(ref fqp, ItemType::Struct)) | - Some(&(ref fqp, ItemType::Union)) | - Some(&(ref fqp, ItemType::Enum)) => - Some(&fqp[..fqp.len() - 1]), - Some(..) => Some(&*self.stack), - None => None - }; - ((Some(*last), path), true) - } - } - _ => ((None, Some(&*self.stack)), false) - }; - - match parent { - (parent, Some(path)) if is_inherent_impl_item || (!self.stripped_mod) => { - debug_assert!(!item.is_stripped()); - - // A crate has a module at its root, containing all items, - // which should not be indexed. The crate-item itself is - // inserted later on when serializing the search-index. - if item.def_id.index != CRATE_DEF_INDEX { - self.search_index.push(IndexItem { - ty: item.type_(), - name: s.to_string(), - path: path.join("::"), - desc: shorten(plain_summary_line(item.doc_value())), - parent, - parent_idx: None, - search_type: get_index_search_type(&item), - }); - } - } - (Some(parent), None) if is_inherent_impl_item => { - // We have a parent, but we don't know where they're - // defined yet. Wait for later to index this item. - self.orphan_impl_items.push((parent, item.clone())); - } - _ => {} - } - } - - // Keep track of the fully qualified path for this item. - let pushed = match item.name { - Some(ref n) if !n.is_empty() => { - self.stack.push(n.to_string()); - true - } - _ => false, - }; - - match item.inner { - clean::StructItem(..) | clean::EnumItem(..) | - clean::TypedefItem(..) | clean::TraitItem(..) | - clean::FunctionItem(..) | clean::ModuleItem(..) | - clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) | - clean::ConstantItem(..) | clean::StaticItem(..) | - clean::UnionItem(..) | clean::ForeignTypeItem | - clean::MacroItem(..) | clean::ProcMacroItem(..) - if !self.stripped_mod => { - // Re-exported items mean that the same id can show up twice - // in the rustdoc ast that we're looking at. We know, - // however, that a re-exported item doesn't show up in the - // `public_items` map, so we can skip inserting into the - // paths map if there was already an entry present and we're - // not a public item. - if !self.paths.contains_key(&item.def_id) || - self.access_levels.is_public(item.def_id) - { - self.paths.insert(item.def_id, - (self.stack.clone(), item.type_())); - } - self.add_aliases(&item); - } - // Link variants to their parent enum because pages aren't emitted - // for each variant. - clean::VariantItem(..) if !self.stripped_mod => { - let mut stack = self.stack.clone(); - stack.pop(); - self.paths.insert(item.def_id, (stack, ItemType::Enum)); - } - - clean::PrimitiveItem(..) => { - self.add_aliases(&item); - self.paths.insert(item.def_id, (self.stack.clone(), - item.type_())); - } - - _ => {} - } - - // Maintain the parent stack - let orig_parent_is_trait_impl = self.parent_is_trait_impl; - let parent_pushed = match item.inner { - clean::TraitItem(..) | clean::EnumItem(..) | clean::ForeignTypeItem | - clean::StructItem(..) | clean::UnionItem(..) => { - self.parent_stack.push(item.def_id); - self.parent_is_trait_impl = false; - true - } - clean::ImplItem(ref i) => { - self.parent_is_trait_impl = i.trait_.is_some(); - match i.for_ { - clean::ResolvedPath{ did, .. } => { - self.parent_stack.push(did); - true - } - ref t => { - let prim_did = t.primitive_type().and_then(|t| { - self.primitive_locations.get(&t).cloned() - }); - match prim_did { - Some(did) => { - self.parent_stack.push(did); - true - } - None => false, - } - } - } - } - _ => false - }; - - // Once we've recursively found all the generics, hoard off all the - // implementations elsewhere. - let ret = self.fold_item_recur(item).and_then(|item| { - if let clean::Item { inner: clean::ImplItem(_), .. } = item { - // Figure out the id of this impl. This may map to a - // primitive rather than always to a struct/enum. - // Note: matching twice to restrict the lifetime of the `i` borrow. - let mut dids = FxHashSet::default(); - if let clean::Item { inner: clean::ImplItem(ref i), .. } = item { - match i.for_ { - clean::ResolvedPath { did, .. } | - clean::BorrowedRef { - type_: box clean::ResolvedPath { did, .. }, .. - } => { - dids.insert(did); - } - ref t => { - let did = t.primitive_type().and_then(|t| { - self.primitive_locations.get(&t).cloned() - }); - - if let Some(did) = did { - dids.insert(did); - } - } - } - - if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) { - for bound in generics { - if let Some(did) = bound.def_id() { - dids.insert(did); - } - } - } - } else { - unreachable!() - }; - let impl_item = Impl { - impl_item: item, - }; - if impl_item.trait_did().map_or(true, |d| self.traits.contains_key(&d)) { - for did in dids { - self.impls.entry(did).or_insert(vec![]).push(impl_item.clone()); - } - } else { - let trait_did = impl_item.trait_did().unwrap(); - self.orphan_trait_impls.push((trait_did, dids, impl_item)); - } - None - } else { - Some(item) - } - }); - - if pushed { self.stack.pop().unwrap(); } - if parent_pushed { self.parent_stack.pop().unwrap(); } - self.stripped_mod = orig_stripped_mod; - self.parent_is_trait_impl = orig_parent_is_trait_impl; - ret - } -} - -impl Cache { - fn add_aliases(&mut self, item: &clean::Item) { - if item.def_id.index == CRATE_DEF_INDEX { - return - } - if let Some(ref item_name) = item.name { - let path = self.paths.get(&item.def_id) - .map(|p| p.0[..p.0.len() - 1].join("::")) - .unwrap_or("std".to_owned()); - for alias in item.attrs.lists(sym::doc) - .filter(|a| a.check_name(sym::alias)) - .filter_map(|a| a.value_str() - .map(|s| s.to_string().replace("\"", ""))) - .filter(|v| !v.is_empty()) - .collect::>() - .into_iter() { - self.aliases.entry(alias) - .or_insert(Vec::with_capacity(1)) - .push(IndexItem { - ty: item.type_(), - name: item_name.to_string(), - path: path.clone(), - desc: shorten(plain_summary_line(item.doc_value())), - parent: None, - parent_idx: None, - search_type: get_index_search_type(&item), - }); - } - } - } -} - #[derive(Debug, Eq, PartialEq, Hash)] struct ItemEntry { url: String, @@ -4805,37 +4229,6 @@ fn make_item_keywords(it: &clean::Item) -> String { format!("{}, {}", BASIC_KEYWORDS, it.name.as_ref().unwrap()) } -fn get_index_search_type(item: &clean::Item) -> Option { - let (all_types, ret_types) = match item.inner { - clean::FunctionItem(ref f) => (&f.all_types, &f.ret_types), - clean::MethodItem(ref m) => (&m.all_types, &m.ret_types), - clean::TyMethodItem(ref m) => (&m.all_types, &m.ret_types), - _ => return None, - }; - - let inputs = all_types.iter().map(|arg| { - get_index_type(&arg) - }).filter(|a| a.name.is_some()).collect(); - let output = ret_types.iter().map(|arg| { - get_index_type(&arg) - }).filter(|a| a.name.is_some()).collect::>(); - let output = if output.is_empty() { - None - } else { - Some(output) - }; - - Some(IndexItemFunctionType { inputs, output }) -} - -fn get_index_type(clean_type: &clean::Type) -> Type { - let t = Type { - name: get_index_type_name(clean_type, true).map(|s| s.to_ascii_lowercase()), - generics: get_generics(clean_type), - }; - t -} - /// Returns a list of all paths used in the type. /// This is used to help deduplicate imported impls /// for reexported types. If any of the contained @@ -4893,39 +4286,6 @@ fn collect_paths_for_type(first_ty: clean::Type) -> Vec { out } -fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option { - match *clean_type { - clean::ResolvedPath { ref path, .. } => { - let segments = &path.segments; - let path_segment = segments.into_iter().last().unwrap_or_else(|| panic!( - "get_index_type_name(clean_type: {:?}, accept_generic: {:?}) had length zero path", - clean_type, accept_generic - )); - Some(path_segment.name.clone()) - } - clean::Generic(ref s) if accept_generic => Some(s.clone()), - clean::Primitive(ref p) => Some(format!("{:?}", p)), - clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_, accept_generic), - // FIXME: add all from clean::Type. - _ => None - } -} - -fn get_generics(clean_type: &clean::Type) -> Option> { - clean_type.generics() - .and_then(|types| { - let r = types.iter() - .filter_map(|t| get_index_type_name(t, false)) - .map(|s| s.to_ascii_lowercase()) - .collect::>(); - if r.is_empty() { - None - } else { - Some(r) - } - }) -} - -pub fn cache() -> Arc { +crate fn cache() -> Arc { CACHE_KEY.with(|c| c.borrow().clone()) } diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs new file mode 100644 index 0000000000000..e9f0955c54126 --- /dev/null +++ b/src/librustdoc/html/render/cache.rs @@ -0,0 +1,675 @@ +use crate::clean::{self, GetDefId, AttributesExt}; +use crate::fold::DocFolder; +use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId}; +use rustc::middle::privacy::AccessLevels; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use std::mem; +use std::path::{Path, PathBuf}; +use std::collections::BTreeMap; +use syntax::source_map::FileName; +use syntax::symbol::sym; +use serialize::json::{ToJson, Json, as_json}; + +use super::{ItemType, IndexItem, IndexItemFunctionType, Impl, shorten, plain_summary_line}; +use super::{Type, RenderInfo}; + +/// Indicates where an external crate can be found. +pub enum ExternalLocation { + /// Remote URL root of the external crate + Remote(String), + /// This external crate can be found in the local doc/ folder + Local, + /// The external crate could not be found. + Unknown, +} + +/// This cache is used to store information about the `clean::Crate` being +/// rendered in order to provide more useful documentation. This contains +/// information like all implementors of a trait, all traits a type implements, +/// documentation for all known traits, etc. +/// +/// This structure purposefully does not implement `Clone` because it's intended +/// to be a fairly large and expensive structure to clone. Instead this adheres +/// to `Send` so it may be stored in a `Arc` instance and shared among the various +/// rendering threads. +#[derive(Default)] +crate struct Cache { + /// Maps a type ID to all known implementations for that type. This is only + /// recognized for intra-crate `ResolvedPath` types, and is used to print + /// out extra documentation on the page of an enum/struct. + /// + /// The values of the map are a list of implementations and documentation + /// found on that implementation. + pub impls: FxHashMap>, + + /// Maintains a mapping of local crate `NodeId`s to the fully qualified name + /// and "short type description" of that node. This is used when generating + /// URLs when a type is being linked to. External paths are not located in + /// this map because the `External` type itself has all the information + /// necessary. + pub paths: FxHashMap, ItemType)>, + + /// Similar to `paths`, but only holds external paths. This is only used for + /// generating explicit hyperlinks to other crates. + pub external_paths: FxHashMap, ItemType)>, + + /// Maps local `DefId`s of exported types to fully qualified paths. + /// Unlike 'paths', this mapping ignores any renames that occur + /// due to 'use' statements. + /// + /// This map is used when writing out the special 'implementors' + /// javascript file. By using the exact path that the type + /// is declared with, we ensure that each path will be identical + /// to the path used if the corresponding type is inlined. By + /// doing this, we can detect duplicate impls on a trait page, and only display + /// the impl for the inlined type. + pub exact_paths: FxHashMap>, + + /// This map contains information about all known traits of this crate. + /// Implementations of a crate should inherit the documentation of the + /// parent trait if no extra documentation is specified, and default methods + /// should show up in documentation about trait implementations. + pub traits: FxHashMap, + + /// When rendering traits, it's often useful to be able to list all + /// implementors of the trait, and this mapping is exactly, that: a mapping + /// of trait ids to the list of known implementors of the trait + pub implementors: FxHashMap>, + + /// Cache of where external crate documentation can be found. + pub extern_locations: FxHashMap, + + /// Cache of where documentation for primitives can be found. + pub primitive_locations: FxHashMap, + + // Note that external items for which `doc(hidden)` applies to are shown as + // non-reachable while local items aren't. This is because we're reusing + // the access levels from the privacy check pass. + pub access_levels: AccessLevels, + + /// The version of the crate being documented, if given from the `--crate-version` flag. + pub crate_version: Option, + + // Private fields only used when initially crawling a crate to build a cache + + stack: Vec, + parent_stack: Vec, + parent_is_trait_impl: bool, + search_index: Vec, + stripped_mod: bool, + pub deref_trait_did: Option, + pub deref_mut_trait_did: Option, + pub owned_box_did: Option, + masked_crates: FxHashSet, + + // In rare case where a structure is defined in one module but implemented + // in another, if the implementing module is parsed before defining module, + // then the fully qualified name of the structure isn't presented in `paths` + // yet when its implementation methods are being indexed. Caches such methods + // and their parent id here and indexes them at the end of crate parsing. + orphan_impl_items: Vec<(DefId, clean::Item)>, + + // Similarly to `orphan_impl_items`, sometimes trait impls are picked up + // even though the trait itself is not exported. This can happen if a trait + // was defined in function/expression scope, since the impl will be picked + // up by `collect-trait-impls` but the trait won't be scraped out in the HIR + // crawl. In order to prevent crashes when looking for spotlight traits or + // when gathering trait documentation on a type, hold impls here while + // folding and add them to the cache later on if we find the trait. + orphan_trait_impls: Vec<(DefId, FxHashSet, Impl)>, + + /// Aliases added through `#[doc(alias = "...")]`. Since a few items can have the same alias, + /// we need the alias element to have an array of items. + pub(super) aliases: FxHashMap>, +} + +impl Cache { + pub fn from_krate( + renderinfo: RenderInfo, + extern_html_root_urls: &BTreeMap, + dst: &Path, + mut krate: clean::Crate, + ) -> (clean::Crate, String, Cache) { + // Crawl the crate to build various caches used for the output + let RenderInfo { + inlined: _, + external_paths, + exact_paths, + access_levels, + deref_trait_did, + deref_mut_trait_did, + owned_box_did, + } = renderinfo; + + let external_paths = external_paths.into_iter() + .map(|(k, (v, t))| (k, (v, ItemType::from(t)))) + .collect(); + + let mut cache = Cache { + impls: Default::default(), + external_paths, + exact_paths, + paths: Default::default(), + implementors: Default::default(), + stack: Vec::new(), + parent_stack: Vec::new(), + search_index: Vec::new(), + parent_is_trait_impl: false, + extern_locations: Default::default(), + primitive_locations: Default::default(), + stripped_mod: false, + access_levels, + crate_version: krate.version.take(), + orphan_impl_items: Vec::new(), + orphan_trait_impls: Vec::new(), + traits: krate.external_traits.replace(Default::default()), + deref_trait_did, + deref_mut_trait_did, + owned_box_did, + masked_crates: mem::take(&mut krate.masked_crates), + aliases: Default::default(), + }; + + // Cache where all our extern crates are located + for &(n, ref e) in &krate.externs { + let src_root = match e.src { + FileName::Real(ref p) => match p.parent() { + Some(p) => p.to_path_buf(), + None => PathBuf::new(), + }, + _ => PathBuf::new(), + }; + let extern_url = extern_html_root_urls.get(&e.name).map(|u| &**u); + cache.extern_locations.insert(n, (e.name.clone(), src_root, + extern_location(e, extern_url, &dst))); + + let did = DefId { krate: n, index: CRATE_DEF_INDEX }; + cache.external_paths.insert(did, (vec![e.name.to_string()], ItemType::Module)); + } + + // Cache where all known primitives have their documentation located. + // + // Favor linking to as local extern as possible, so iterate all crates in + // reverse topological order. + for &(_, ref e) in krate.externs.iter().rev() { + for &(def_id, prim, _) in &e.primitives { + cache.primitive_locations.insert(prim, def_id); + } + } + for &(def_id, prim, _) in &krate.primitives { + cache.primitive_locations.insert(prim, def_id); + } + + cache.stack.push(krate.name.clone()); + krate = cache.fold_crate(krate); + + for (trait_did, dids, impl_) in cache.orphan_trait_impls.drain(..) { + if cache.traits.contains_key(&trait_did) { + for did in dids { + cache.impls.entry(did).or_insert(vec![]).push(impl_.clone()); + } + } + } + + // Build our search index + let index = build_index(&krate, &mut cache); + + (krate, index, cache) + } +} + +impl DocFolder for Cache { + fn fold_item(&mut self, item: clean::Item) -> Option { + if item.def_id.is_local() { + debug!("folding {} \"{:?}\", id {:?}", item.type_(), item.name, item.def_id); + } + + // If this is a stripped module, + // we don't want it or its children in the search index. + let orig_stripped_mod = match item.inner { + clean::StrippedItem(box clean::ModuleItem(..)) => { + mem::replace(&mut self.stripped_mod, true) + } + _ => self.stripped_mod, + }; + + // If the impl is from a masked crate or references something from a + // masked crate then remove it completely. + if let clean::ImplItem(ref i) = item.inner { + if self.masked_crates.contains(&item.def_id.krate) || + i.trait_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate)) || + i.for_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate)) { + return None; + } + } + + // Propagate a trait method's documentation to all implementors of the + // trait. + if let clean::TraitItem(ref t) = item.inner { + self.traits.entry(item.def_id).or_insert_with(|| t.clone()); + } + + // Collect all the implementors of traits. + if let clean::ImplItem(ref i) = item.inner { + if let Some(did) = i.trait_.def_id() { + if i.blanket_impl.is_none() { + self.implementors.entry(did).or_default().push(Impl { + impl_item: item.clone(), + }); + } + } + } + + // Index this method for searching later on. + if let Some(ref s) = item.name { + let (parent, is_inherent_impl_item) = match item.inner { + clean::StrippedItem(..) => ((None, None), false), + clean::AssocConstItem(..) | + clean::TypedefItem(_, true) if self.parent_is_trait_impl => { + // skip associated items in trait impls + ((None, None), false) + } + clean::AssocTypeItem(..) | + clean::TyMethodItem(..) | + clean::StructFieldItem(..) | + clean::VariantItem(..) => { + ((Some(*self.parent_stack.last().unwrap()), + Some(&self.stack[..self.stack.len() - 1])), + false) + } + clean::MethodItem(..) | clean::AssocConstItem(..) => { + if self.parent_stack.is_empty() { + ((None, None), false) + } else { + let last = self.parent_stack.last().unwrap(); + let did = *last; + let path = match self.paths.get(&did) { + // The current stack not necessarily has correlation + // for where the type was defined. On the other + // hand, `paths` always has the right + // information if present. + Some(&(ref fqp, ItemType::Trait)) | + Some(&(ref fqp, ItemType::Struct)) | + Some(&(ref fqp, ItemType::Union)) | + Some(&(ref fqp, ItemType::Enum)) => + Some(&fqp[..fqp.len() - 1]), + Some(..) => Some(&*self.stack), + None => None + }; + ((Some(*last), path), true) + } + } + _ => ((None, Some(&*self.stack)), false) + }; + + match parent { + (parent, Some(path)) if is_inherent_impl_item || (!self.stripped_mod) => { + debug_assert!(!item.is_stripped()); + + // A crate has a module at its root, containing all items, + // which should not be indexed. The crate-item itself is + // inserted later on when serializing the search-index. + if item.def_id.index != CRATE_DEF_INDEX { + self.search_index.push(IndexItem { + ty: item.type_(), + name: s.to_string(), + path: path.join("::"), + desc: shorten(plain_summary_line(item.doc_value())), + parent, + parent_idx: None, + search_type: get_index_search_type(&item), + }); + } + } + (Some(parent), None) if is_inherent_impl_item => { + // We have a parent, but we don't know where they're + // defined yet. Wait for later to index this item. + self.orphan_impl_items.push((parent, item.clone())); + } + _ => {} + } + } + + // Keep track of the fully qualified path for this item. + let pushed = match item.name { + Some(ref n) if !n.is_empty() => { + self.stack.push(n.to_string()); + true + } + _ => false, + }; + + match item.inner { + clean::StructItem(..) | clean::EnumItem(..) | + clean::TypedefItem(..) | clean::TraitItem(..) | + clean::FunctionItem(..) | clean::ModuleItem(..) | + clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) | + clean::ConstantItem(..) | clean::StaticItem(..) | + clean::UnionItem(..) | clean::ForeignTypeItem | + clean::MacroItem(..) | clean::ProcMacroItem(..) + if !self.stripped_mod => { + // Re-exported items mean that the same id can show up twice + // in the rustdoc ast that we're looking at. We know, + // however, that a re-exported item doesn't show up in the + // `public_items` map, so we can skip inserting into the + // paths map if there was already an entry present and we're + // not a public item. + if !self.paths.contains_key(&item.def_id) || + self.access_levels.is_public(item.def_id) + { + self.paths.insert(item.def_id, + (self.stack.clone(), item.type_())); + } + self.add_aliases(&item); + } + // Link variants to their parent enum because pages aren't emitted + // for each variant. + clean::VariantItem(..) if !self.stripped_mod => { + let mut stack = self.stack.clone(); + stack.pop(); + self.paths.insert(item.def_id, (stack, ItemType::Enum)); + } + + clean::PrimitiveItem(..) => { + self.add_aliases(&item); + self.paths.insert(item.def_id, (self.stack.clone(), + item.type_())); + } + + _ => {} + } + + // Maintain the parent stack + let orig_parent_is_trait_impl = self.parent_is_trait_impl; + let parent_pushed = match item.inner { + clean::TraitItem(..) | clean::EnumItem(..) | clean::ForeignTypeItem | + clean::StructItem(..) | clean::UnionItem(..) => { + self.parent_stack.push(item.def_id); + self.parent_is_trait_impl = false; + true + } + clean::ImplItem(ref i) => { + self.parent_is_trait_impl = i.trait_.is_some(); + match i.for_ { + clean::ResolvedPath{ did, .. } => { + self.parent_stack.push(did); + true + } + ref t => { + let prim_did = t.primitive_type().and_then(|t| { + self.primitive_locations.get(&t).cloned() + }); + match prim_did { + Some(did) => { + self.parent_stack.push(did); + true + } + None => false, + } + } + } + } + _ => false + }; + + // Once we've recursively found all the generics, hoard off all the + // implementations elsewhere. + let ret = self.fold_item_recur(item).and_then(|item| { + if let clean::Item { inner: clean::ImplItem(_), .. } = item { + // Figure out the id of this impl. This may map to a + // primitive rather than always to a struct/enum. + // Note: matching twice to restrict the lifetime of the `i` borrow. + let mut dids = FxHashSet::default(); + if let clean::Item { inner: clean::ImplItem(ref i), .. } = item { + match i.for_ { + clean::ResolvedPath { did, .. } | + clean::BorrowedRef { + type_: box clean::ResolvedPath { did, .. }, .. + } => { + dids.insert(did); + } + ref t => { + let did = t.primitive_type().and_then(|t| { + self.primitive_locations.get(&t).cloned() + }); + + if let Some(did) = did { + dids.insert(did); + } + } + } + + if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) { + for bound in generics { + if let Some(did) = bound.def_id() { + dids.insert(did); + } + } + } + } else { + unreachable!() + }; + let impl_item = Impl { + impl_item: item, + }; + if impl_item.trait_did().map_or(true, |d| self.traits.contains_key(&d)) { + for did in dids { + self.impls.entry(did).or_insert(vec![]).push(impl_item.clone()); + } + } else { + let trait_did = impl_item.trait_did().unwrap(); + self.orphan_trait_impls.push((trait_did, dids, impl_item)); + } + None + } else { + Some(item) + } + }); + + if pushed { self.stack.pop().unwrap(); } + if parent_pushed { self.parent_stack.pop().unwrap(); } + self.stripped_mod = orig_stripped_mod; + self.parent_is_trait_impl = orig_parent_is_trait_impl; + ret + } +} + +impl Cache { + fn add_aliases(&mut self, item: &clean::Item) { + if item.def_id.index == CRATE_DEF_INDEX { + return + } + if let Some(ref item_name) = item.name { + let path = self.paths.get(&item.def_id) + .map(|p| p.0[..p.0.len() - 1].join("::")) + .unwrap_or("std".to_owned()); + for alias in item.attrs.lists(sym::doc) + .filter(|a| a.check_name(sym::alias)) + .filter_map(|a| a.value_str() + .map(|s| s.to_string().replace("\"", ""))) + .filter(|v| !v.is_empty()) + .collect::>() + .into_iter() { + self.aliases.entry(alias) + .or_insert(Vec::with_capacity(1)) + .push(IndexItem { + ty: item.type_(), + name: item_name.to_string(), + path: path.clone(), + desc: shorten(plain_summary_line(item.doc_value())), + parent: None, + parent_idx: None, + search_type: get_index_search_type(&item), + }); + } + } + } +} + +/// Attempts to find where an external crate is located, given that we're +/// rendering in to the specified source destination. +fn extern_location(e: &clean::ExternalCrate, extern_url: Option<&str>, dst: &Path) + -> ExternalLocation +{ + use ExternalLocation::*; + // See if there's documentation generated into the local directory + let local_location = dst.join(&e.name); + if local_location.is_dir() { + return Local; + } + + if let Some(url) = extern_url { + let mut url = url.to_string(); + if !url.ends_with("/") { + url.push('/'); + } + return Remote(url); + } + + // Failing that, see if there's an attribute specifying where to find this + // external crate + e.attrs.lists(sym::doc) + .filter(|a| a.check_name(sym::html_root_url)) + .filter_map(|a| a.value_str()) + .map(|url| { + let mut url = url.to_string(); + if !url.ends_with("/") { + url.push('/') + } + Remote(url) + }).next().unwrap_or(Unknown) // Well, at least we tried. +} + +/// Builds the search index from the collected metadata +fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { + let mut nodeid_to_pathid = FxHashMap::default(); + let mut crate_items = Vec::with_capacity(cache.search_index.len()); + let mut crate_paths = Vec::::new(); + + let Cache { ref mut search_index, + ref orphan_impl_items, + ref mut paths, .. } = *cache; + + // Attach all orphan items to the type's definition if the type + // has since been learned. + for &(did, ref item) in orphan_impl_items { + if let Some(&(ref fqp, _)) = paths.get(&did) { + search_index.push(IndexItem { + ty: item.type_(), + name: item.name.clone().unwrap(), + path: fqp[..fqp.len() - 1].join("::"), + desc: shorten(plain_summary_line(item.doc_value())), + parent: Some(did), + parent_idx: None, + search_type: get_index_search_type(&item), + }); + } + } + + // Reduce `NodeId` in paths into smaller sequential numbers, + // and prune the paths that do not appear in the index. + let mut lastpath = String::new(); + let mut lastpathid = 0usize; + + for item in search_index { + item.parent_idx = item.parent.map(|nodeid| { + if nodeid_to_pathid.contains_key(&nodeid) { + *nodeid_to_pathid.get(&nodeid).unwrap() + } else { + let pathid = lastpathid; + nodeid_to_pathid.insert(nodeid, pathid); + lastpathid += 1; + + let &(ref fqp, short) = paths.get(&nodeid).unwrap(); + crate_paths.push(((short as usize), fqp.last().unwrap().clone()).to_json()); + pathid + } + }); + + // Omit the parent path if it is same to that of the prior item. + if lastpath == item.path { + item.path.clear(); + } else { + lastpath = item.path.clone(); + } + crate_items.push(item.to_json()); + } + + let crate_doc = krate.module.as_ref().map(|module| { + shorten(plain_summary_line(module.doc_value())) + }).unwrap_or(String::new()); + + let mut crate_data = BTreeMap::new(); + crate_data.insert("doc".to_owned(), Json::String(crate_doc)); + crate_data.insert("i".to_owned(), Json::Array(crate_items)); + crate_data.insert("p".to_owned(), Json::Array(crate_paths)); + + // Collect the index into a string + format!("searchIndex[{}] = {};", + as_json(&krate.name), + Json::Object(crate_data)) +} + +fn get_index_search_type(item: &clean::Item) -> Option { + let (all_types, ret_types) = match item.inner { + clean::FunctionItem(ref f) => (&f.all_types, &f.ret_types), + clean::MethodItem(ref m) => (&m.all_types, &m.ret_types), + clean::TyMethodItem(ref m) => (&m.all_types, &m.ret_types), + _ => return None, + }; + + let inputs = all_types.iter().map(|arg| { + get_index_type(&arg) + }).filter(|a| a.name.is_some()).collect(); + let output = ret_types.iter().map(|arg| { + get_index_type(&arg) + }).filter(|a| a.name.is_some()).collect::>(); + let output = if output.is_empty() { + None + } else { + Some(output) + }; + + Some(IndexItemFunctionType { inputs, output }) +} + +fn get_index_type(clean_type: &clean::Type) -> Type { + let t = Type { + name: get_index_type_name(clean_type, true).map(|s| s.to_ascii_lowercase()), + generics: get_generics(clean_type), + }; + t +} + +fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option { + match *clean_type { + clean::ResolvedPath { ref path, .. } => { + let segments = &path.segments; + let path_segment = segments.into_iter().last().unwrap_or_else(|| panic!( + "get_index_type_name(clean_type: {:?}, accept_generic: {:?}) had length zero path", + clean_type, accept_generic + )); + Some(path_segment.name.clone()) + } + clean::Generic(ref s) if accept_generic => Some(s.clone()), + clean::Primitive(ref p) => Some(format!("{:?}", p)), + clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_, accept_generic), + // FIXME: add all from clean::Type. + _ => None + } +} + +fn get_generics(clean_type: &clean::Type) -> Option> { + clean_type.generics() + .and_then(|types| { + let r = types.iter() + .filter_map(|t| get_index_type_name(t, false)) + .map(|s| s.to_ascii_lowercase()) + .collect::>(); + if r.is_empty() { + None + } else { + Some(r) + } + }) +} From 6e0b0d4d7094d8d63a3c11325ae8c53c9928aab7 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 13 Sep 2019 11:40:51 -0400 Subject: [PATCH 21/55] Move cache into Context, avoid TLS This doesn't move everything over as cache() is pretty annoying to remove fully, but it gets the ball rolling. --- src/librustdoc/html/render.rs | 55 +++++++++++++++++------------------ 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index ff7134ab7c0d5..dc9e7131c89de 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -167,6 +167,7 @@ struct Context { /// The map used to ensure all generated 'id=' attributes are unique. id_map: Rc>, pub shared: Arc, + pub cache: Arc, } crate struct SharedContext { @@ -477,31 +478,31 @@ pub fn run(mut krate: clean::Crate, let dst = output; scx.ensure_dir(&dst)?; krate = sources::render(&dst, &mut scx, krate)?; + let (new_crate, index, cache) = Cache::from_krate( + renderinfo, + &extern_html_root_urls, + &dst, + krate, + ); + krate = new_crate; + let cache = Arc::new(cache); let mut cx = Context { current: Vec::new(), dst, render_redirect_pages: false, id_map: Rc::new(RefCell::new(id_map)), shared: Arc::new(scx), + cache: cache.clone(), }; - let (new_crate, index, cache) = Cache::from_krate( - renderinfo, - &extern_html_root_urls, - &cx.dst, - krate, - ); - krate = new_crate; - // Freeze the cache now that the index has been built. Put an Arc into TLS // for future parallelization opportunities - let cache = Arc::new(cache); CACHE_KEY.with(|v| *v.borrow_mut() = cache.clone()); CURRENT_DEPTH.with(|s| s.set(0)); // Write shared runs within a flock; disable thread dispatching of IO temporarily. Arc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(true); - write_shared(&cx, &krate, &*cache, index, &md_opts, diag)?; + write_shared(&cx, &krate, index, &md_opts, diag)?; Arc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(false); // And finally render the whole crate's documentation @@ -519,7 +520,6 @@ pub fn run(mut krate: clean::Crate, fn write_shared( cx: &Context, krate: &clean::Crate, - cache: &Cache, search_index: String, options: &RenderOptions, diag: &errors::Handler, @@ -750,7 +750,7 @@ themePicker.onblur = handleThemeButtonsBlur; { let (mut all_aliases, _, _) = try_err!(collect(&dst, &krate.name, "ALIASES", false), &dst); let mut output = String::with_capacity(100); - for (alias, items) in &cache.aliases { + for (alias, items) in &cx.cache.aliases { if items.is_empty() { continue } @@ -920,7 +920,7 @@ themePicker.onblur = handleThemeButtonsBlur; // Update the list of all implementors for traits let dst = cx.dst.join("implementors"); - for (&did, imps) in &cache.implementors { + for (&did, imps) in &cx.cache.implementors { // Private modules can leak through to this phase of rustdoc, which // could contain implementations for otherwise private types. In some // rare cases we could find an implementation for an item which wasn't @@ -928,9 +928,9 @@ themePicker.onblur = handleThemeButtonsBlur; // // FIXME: this is a vague explanation for why this can't be a `get`, in // theory it should be... - let &(ref remote_path, remote_item_type) = match cache.paths.get(&did) { + let &(ref remote_path, remote_item_type) = match cx.cache.paths.get(&did) { Some(p) => p, - None => match cache.external_paths.get(&did) { + None => match cx.cache.external_paths.get(&did) { Some(p) => p, None => continue, } @@ -958,7 +958,7 @@ themePicker.onblur = handleThemeButtonsBlur; // Only create a js file if we have impls to add to it. If the trait is // documented locally though we always create the file to avoid dead // links. - if !have_impls && !cache.paths.contains_key(&did) { + if !have_impls && !cx.cache.paths.contains_key(&did) { continue; } @@ -1309,7 +1309,7 @@ impl Context { extra_scripts: &[], static_extra_scripts: &[], }; - let sidebar = if let Some(ref version) = cache().crate_version { + let sidebar = if let Some(ref version) = self.cache.crate_version { format!("

    Crate {}

    \
    \

    Version {}

    \ @@ -1399,7 +1399,7 @@ impl Context { &self.shared.themes) } else { let mut url = self.root_path(); - if let Some(&(ref names, ty)) = cache().paths.get(&it.def_id) { + if let Some(&(ref names, ty)) = self.cache.paths.get(&it.def_id) { for name in &names[..names.len() - 1] { url.push_str(name); url.push_str("/"); @@ -1549,7 +1549,6 @@ impl Context { fn src_href(&self, item: &clean::Item) -> Option { let mut root = self.root_path(); - let cache = cache(); let mut path = String::new(); // We can safely ignore macros from other libraries @@ -1565,7 +1564,7 @@ impl Context { return None; } } else { - let (krate, src_root) = match *cache.extern_locations.get(&item.def_id.krate)? { + let (krate, src_root) = match *self.cache.extern_locations.get(&item.def_id.krate)? { (ref name, ref src, Local) => (name, src), (ref name, ref src, Remote(ref s)) => { root = s.to_string(); @@ -2475,11 +2474,9 @@ fn item_trait( // If there are methods directly on this trait object, render them here. render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All); - let cache = cache(); - let mut synthetic_types = Vec::new(); - if let Some(implementors) = cache.implementors.get(&it.def_id) { + if let Some(implementors) = cx.cache.implementors.get(&it.def_id) { // The DefId is for the first Type found with that name. The bool is // if any Types with the same name but different DefId have been found. let mut implementor_dups: FxHashMap<&str, (DefId, bool)> = FxHashMap::default(); @@ -2502,7 +2499,7 @@ fn item_trait( let (local, foreign) = implementors.iter() .partition::, _>(|i| i.inner_impl().for_.def_id() - .map_or(true, |d| cache.paths.contains_key(&d))); + .map_or(true, |d| cx.cache.paths.contains_key(&d))); let (mut synthetic, mut concrete): (Vec<&&Impl>, Vec<&&Impl>) = local.iter() @@ -2567,7 +2564,7 @@ fn item_trait( path = if it.def_id.is_local() { cx.current.join("/") } else { - let (ref path, _) = cache.external_paths[&it.def_id]; + let (ref path, _) = cx.cache.external_paths[&it.def_id]; path[..path.len() - 1].join("/") }, ty = it.type_(), @@ -3144,7 +3141,7 @@ fn render_assoc_items(w: &mut Buffer, containing_item: &clean::Item, it: DefId, what: AssocItemRender<'_>) { - let c = cache(); + let c = &cx.cache; let v = match c.impls.get(&it) { Some(v) => v, None => return, @@ -3250,7 +3247,7 @@ fn render_deref_methods(w: &mut Buffer, cx: &Context, impl_: &Impl, render_assoc_items(w, cx, container_item, did, what) } else { if let Some(prim) = target.primitive_type() { - if let Some(&did) = cache().primitive_locations.get(&prim) { + if let Some(&did) = cx.cache.primitive_locations.get(&prim) { render_assoc_items(w, cx, container_item, did, what); } } @@ -3500,7 +3497,7 @@ fn render_impl(w: &mut Buffer, cx: &Context, i: &Impl, link: AssocItemLink<'_>, } } - let traits = &cache().traits; + let traits = &cx.cache.traits; let trait_ = i.trait_did().map(|did| &traits[&did]); write!(w, "
    "); @@ -3642,7 +3639,7 @@ fn print_sidebar(cx: &Context, it: &clean::Item, buffer: &mut Buffer) { } if it.is_crate() { - if let Some(ref version) = cache().crate_version { + if let Some(ref version) = cx.cache.crate_version { write!(buffer, "
    \

    Version {}

    \ From 0ad789aa5b0950608b2d71b8388c3d167fcc22b1 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 13 Sep 2019 14:11:10 -0400 Subject: [PATCH 22/55] Stylistic fix -- remove double impl --- src/librustdoc/html/render.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index dc9e7131c89de..2623f8d227e14 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -222,9 +222,7 @@ impl SharedContext { Ok(()) } -} -impl SharedContext { /// Based on whether the `collapse-docs` pass was run, return either the `doc_value` or the /// `collapsed_doc_value` of the given item. pub fn maybe_collapsed_doc_value<'a>(&self, item: &'a clean::Item) -> Option> { From 25211894386a34db1639fbd69680e8f7b35ee1a4 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 30 Aug 2019 17:27:35 +1000 Subject: [PATCH 23/55] Add a comment to `Compiler::compile()`. `Compiler::compile()` is different to all the other `Compiler` methods because it lacks a `Queries` entry. It only has one call site, which is in a test that doesn't need its specific characteristics. This patch replaces that call with a call to `Compile::link()`, which is similar enough for the test's purposes. It also notes that the method is an illustrative example of how `Compiler` can be used. --- src/librustc_interface/queries.rs | 9 +++++++-- src/test/run-make-fulldeps/issue-19371/foo.rs | 3 ++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/librustc_interface/queries.rs b/src/librustc_interface/queries.rs index e056d3feb66ec..ff5cd8b8c695d 100644 --- a/src/librustc_interface/queries.rs +++ b/src/librustc_interface/queries.rs @@ -275,6 +275,11 @@ impl Compiler { }) } + // This method is different to all the other methods in `Compiler` because + // it lacks a `Queries` entry. It's also not currently used. It does serve + // as an example of how `Compiler` can be used, with additional steps added + // between some passes. And see `rustc_driver::run_compiler` for a more + // complex example. pub fn compile(&self) -> Result<()> { self.prepare_outputs()?; @@ -286,12 +291,12 @@ impl Compiler { self.global_ctxt()?; - // Drop AST after creating GlobalCtxt to free memory + // Drop AST after creating GlobalCtxt to free memory. mem::drop(self.expansion()?.take()); self.ongoing_codegen()?; - // Drop GlobalCtxt after starting codegen to free memory + // Drop GlobalCtxt after starting codegen to free memory. mem::drop(self.global_ctxt()?.take()); self.link().map(|_| ()) diff --git a/src/test/run-make-fulldeps/issue-19371/foo.rs b/src/test/run-make-fulldeps/issue-19371/foo.rs index afc92638fda97..e290f7fa6b13a 100644 --- a/src/test/run-make-fulldeps/issue-19371/foo.rs +++ b/src/test/run-make-fulldeps/issue-19371/foo.rs @@ -62,6 +62,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) { }; interface::run_compiler(config, |compiler| { - compiler.compile().ok(); + // This runs all the passes prior to linking, too. + compiler.link().ok(); }); } From 645cdca9ba2fd3e47dedeecbb580d490fa9ef85b Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 22 Sep 2019 17:42:17 +0300 Subject: [PATCH 24/55] reduce visibility of a bunch of stuff in ext::tt --- src/librustc_resolve/macros.rs | 4 +- src/libsyntax/ext/tt/macro_check.rs | 2 +- src/libsyntax/ext/tt/macro_parser.rs | 16 ++++---- src/libsyntax/ext/tt/macro_rules.rs | 14 ++++--- src/libsyntax/ext/tt/quoted.rs | 57 +++++++++++----------------- src/libsyntax/lib.rs | 13 ++++--- src/libsyntax/tokenstream.rs | 2 +- 7 files changed, 50 insertions(+), 58 deletions(-) diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 3900a3dbb3872..73ad0670659b5 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -18,7 +18,7 @@ use syntax::ext::base::{self, InvocationRes, Indeterminate, SpecialDerives}; use syntax::ext::base::{MacroKind, SyntaxExtension}; use syntax::ext::expand::{AstFragment, AstFragmentKind, Invocation, InvocationKind}; use syntax::ext::hygiene::{self, ExpnId, ExpnData, ExpnKind}; -use syntax::ext::tt::macro_rules; +use syntax::ext::compile_declarative_macro; use syntax::feature_gate::{emit_feature_err, is_builtin_attr_name}; use syntax::feature_gate::GateIssue; use syntax::symbol::{Symbol, kw, sym}; @@ -843,7 +843,7 @@ impl<'a> Resolver<'a> { /// Compile the macro into a `SyntaxExtension` and possibly replace it with a pre-defined /// extension partially or entirely for built-in macros and legacy plugin macros. crate fn compile_macro(&mut self, item: &ast::Item, edition: Edition) -> SyntaxExtension { - let mut result = macro_rules::compile( + let mut result = compile_declarative_macro( &self.session.parse_sess, self.session.features_untracked(), item, edition ); diff --git a/src/libsyntax/ext/tt/macro_check.rs b/src/libsyntax/ext/tt/macro_check.rs index 5af97199902e6..a1734689595f0 100644 --- a/src/libsyntax/ext/tt/macro_check.rs +++ b/src/libsyntax/ext/tt/macro_check.rs @@ -196,7 +196,7 @@ struct MacroState<'a> { /// - `node_id` is used to emit lints /// - `span` is used when no spans are available /// - `lhses` and `rhses` should have the same length and represent the macro definition -pub fn check_meta_variables( +crate fn check_meta_variables( sess: &ParseSess, node_id: NodeId, span: Span, diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index dbf14daa30e75..a34a0344f2740 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -70,8 +70,8 @@ //! eof: [a $( a )* a b ·] //! ``` -pub use NamedMatch::*; -pub use ParseResult::*; +crate use NamedMatch::*; +crate use ParseResult::*; use TokenTreeOrTokenTreeSlice::*; use crate::ast::{Ident, Name}; @@ -267,7 +267,7 @@ impl<'root, 'tt> DerefMut for MatcherPosHandle<'root, 'tt> { } /// Represents the possible results of an attempted parse. -pub enum ParseResult { +crate enum ParseResult { /// Parsed successfully. Success(T), /// Arm failed to match. If the second parameter is `token::Eof`, it indicates an unexpected @@ -279,10 +279,10 @@ pub enum ParseResult { /// A `ParseResult` where the `Success` variant contains a mapping of `Ident`s to `NamedMatch`es. /// This represents the mapping of metavars to the token trees they bind to. -pub type NamedParseResult = ParseResult>; +crate type NamedParseResult = ParseResult>; /// Count how many metavars are named in the given matcher `ms`. -pub fn count_names(ms: &[TokenTree]) -> usize { +crate fn count_names(ms: &[TokenTree]) -> usize { ms.iter().fold(0, |count, elt| { count + match *elt { TokenTree::Sequence(_, ref seq) => seq.num_captures, @@ -352,7 +352,7 @@ fn initial_matcher_pos<'root, 'tt>(ms: &'tt [TokenTree], open: Span) -> MatcherP /// only on the nesting depth of `ast::TTSeq`s in the originating /// token tree it was derived from. #[derive(Debug, Clone)] -pub enum NamedMatch { +crate enum NamedMatch { MatchedSeq(Lrc, DelimSpan), MatchedNonterminal(Lrc), } @@ -415,7 +415,7 @@ fn nameize>( /// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For /// other tokens, this is "unexpected token...". -pub fn parse_failure_msg(tok: &Token) -> String { +crate fn parse_failure_msg(tok: &Token) -> String { match tok.kind { token::Eof => "unexpected end of macro invocation".to_string(), _ => format!( @@ -648,7 +648,7 @@ fn inner_parse_loop<'root, 'tt>( /// - `directory`: Information about the file locations (needed for the black-box parser) /// - `recurse_into_modules`: Whether or not to recurse into modules (needed for the black-box /// parser) -pub fn parse( +crate fn parse( sess: &ParseSess, tts: TokenStream, ms: &[TokenTree], diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index b27e9c543377a..90dfa6e7ac8a4 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -35,7 +35,7 @@ const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \ `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, \ `literal`, `path`, `meta`, `tt`, `item` and `vis`"; -pub struct ParserAnyMacro<'a> { +crate struct ParserAnyMacro<'a> { parser: Parser<'a>, /// Span of the expansion site of the macro this parser is for @@ -45,7 +45,11 @@ pub struct ParserAnyMacro<'a> { arm_span: Span, } -pub fn annotate_err_with_kind(err: &mut DiagnosticBuilder<'_>, kind: AstFragmentKind, span: Span) { +crate fn annotate_err_with_kind( + err: &mut DiagnosticBuilder<'_>, + kind: AstFragmentKind, + span: Span, +) { match kind { AstFragmentKind::Ty => { err.span_label(span, "this macro call doesn't expand to a type"); @@ -58,7 +62,7 @@ pub fn annotate_err_with_kind(err: &mut DiagnosticBuilder<'_>, kind: AstFragment } impl<'a> ParserAnyMacro<'a> { - pub fn make(mut self: Box>, kind: AstFragmentKind) -> AstFragment { + crate fn make(mut self: Box>, kind: AstFragmentKind) -> AstFragment { let ParserAnyMacro { site_span, macro_ident, ref mut parser, arm_span } = *self; let fragment = panictry!(parser.parse_ast_fragment(kind, true).map_err(|mut e| { if parser.token == token::Eof && e.message().ends_with(", found ``") { @@ -284,8 +288,8 @@ fn generic_extension<'cx>( // // Holy self-referential! -/// Converts a `macro_rules!` invocation into a syntax extension. -pub fn compile( +/// Converts a macro item into a syntax extension. +pub fn compile_declarative_macro( sess: &ParseSess, features: &Features, def: &ast::Item, diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs index cad94a0e4c120..d161e6638bf75 100644 --- a/src/libsyntax/ext/tt/quoted.rs +++ b/src/libsyntax/ext/tt/quoted.rs @@ -16,14 +16,14 @@ use std::iter::Peekable; /// Contains the sub-token-trees of a "delimited" token tree, such as the contents of `(`. Note /// that the delimiter itself might be `NoDelim`. #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)] -pub struct Delimited { - pub delim: token::DelimToken, - pub tts: Vec, +crate struct Delimited { + crate delim: token::DelimToken, + crate tts: Vec, } impl Delimited { /// Returns a `self::TokenTree` with a `Span` corresponding to the opening delimiter. - pub fn open_tt(&self, span: Span) -> TokenTree { + crate fn open_tt(&self, span: Span) -> TokenTree { let open_span = if span.is_dummy() { span } else { @@ -33,7 +33,7 @@ impl Delimited { } /// Returns a `self::TokenTree` with a `Span` corresponding to the closing delimiter. - pub fn close_tt(&self, span: Span) -> TokenTree { + crate fn close_tt(&self, span: Span) -> TokenTree { let close_span = if span.is_dummy() { span } else { @@ -44,25 +44,25 @@ impl Delimited { } #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)] -pub struct SequenceRepetition { +crate struct SequenceRepetition { /// The sequence of token trees - pub tts: Vec, + crate tts: Vec, /// The optional separator - pub separator: Option, + crate separator: Option, /// Whether the sequence can be repeated zero (*), or one or more times (+) - pub kleene: KleeneToken, + crate kleene: KleeneToken, /// The number of `Match`s that appear in the sequence (and subsequences) - pub num_captures: usize, + crate num_captures: usize, } #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)] -pub struct KleeneToken { - pub span: Span, - pub op: KleeneOp, +crate struct KleeneToken { + crate span: Span, + crate op: KleeneOp, } impl KleeneToken { - pub fn new(op: KleeneOp, span: Span) -> KleeneToken { + crate fn new(op: KleeneOp, span: Span) -> KleeneToken { KleeneToken { span, op } } } @@ -70,7 +70,7 @@ impl KleeneToken { /// A Kleene-style [repetition operator](http://en.wikipedia.org/wiki/Kleene_star) /// for token sequences. #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] -pub enum KleeneOp { +crate enum KleeneOp { /// Kleene star (`*`) for zero or more repetitions ZeroOrMore, /// Kleene plus (`+`) for one or more repetitions @@ -82,7 +82,7 @@ pub enum KleeneOp { /// Similar to `tokenstream::TokenTree`, except that `$i`, `$i:ident`, and `$(...)` /// are "first-class" token trees. Useful for parsing macros. #[derive(Debug, Clone, PartialEq, RustcEncodable, RustcDecodable)] -pub enum TokenTree { +crate enum TokenTree { Token(Token), Delimited(DelimSpan, Lrc), /// A kleene-style repetition sequence @@ -99,7 +99,7 @@ pub enum TokenTree { impl TokenTree { /// Return the number of tokens in the tree. - pub fn len(&self) -> usize { + crate fn len(&self) -> usize { match *self { TokenTree::Delimited(_, ref delimed) => match delimed.delim { token::NoDelim => delimed.tts.len(), @@ -110,21 +110,8 @@ impl TokenTree { } } - /// Returns `true` if the given token tree contains no other tokens. This is vacuously true for - /// single tokens or metavar/decls, but may be false for delimited trees or sequences. - pub fn is_empty(&self) -> bool { - match *self { - TokenTree::Delimited(_, ref delimed) => match delimed.delim { - token::NoDelim => delimed.tts.is_empty(), - _ => false, - }, - TokenTree::Sequence(_, ref seq) => seq.tts.is_empty(), - _ => true, - } - } - /// Returns `true` if the given token tree is delimited. - pub fn is_delimited(&self) -> bool { + crate fn is_delimited(&self) -> bool { match *self { TokenTree::Delimited(..) => true, _ => false, @@ -132,7 +119,7 @@ impl TokenTree { } /// Returns `true` if the given token tree is a token of the given kind. - pub fn is_token(&self, expected_kind: &TokenKind) -> bool { + crate fn is_token(&self, expected_kind: &TokenKind) -> bool { match self { TokenTree::Token(Token { kind: actual_kind, .. }) => actual_kind == expected_kind, _ => false, @@ -140,7 +127,7 @@ impl TokenTree { } /// Gets the `index`-th sub-token-tree. This only makes sense for delimited trees and sequences. - pub fn get_tt(&self, index: usize) -> TokenTree { + crate fn get_tt(&self, index: usize) -> TokenTree { match (self, index) { (&TokenTree::Delimited(_, ref delimed), _) if delimed.delim == token::NoDelim => { delimed.tts[index].clone() @@ -160,7 +147,7 @@ impl TokenTree { } /// Retrieves the `TokenTree`'s span. - pub fn span(&self) -> Span { + crate fn span(&self) -> Span { match *self { TokenTree::Token(Token { span, .. }) | TokenTree::MetaVar(span, _) @@ -195,7 +182,7 @@ impl TokenTree { /// # Returns /// /// A collection of `self::TokenTree`. There may also be some errors emitted to `sess`. -pub fn parse( +crate fn parse( input: tokenstream::TokenStream, expect_matchers: bool, sess: &ParseSess, diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index aaf6f3e537eb6..c06f43021021a 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -162,18 +162,19 @@ pub mod ext { mod proc_macro_server; pub use syntax_pos::hygiene; + pub use tt::macro_rules::compile_declarative_macro; pub mod allocator; pub mod base; pub mod build; pub mod expand; pub mod proc_macro; - pub mod tt { - pub mod transcribe; - pub mod macro_check; - pub mod macro_parser; - pub mod macro_rules; - pub mod quoted; + crate mod tt { + crate mod transcribe; + crate mod macro_check; + crate mod macro_parser; + crate mod macro_rules; + crate mod quoted; } } diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index d702038f54ec3..15fc4b02041b7 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -64,7 +64,7 @@ where impl TokenTree { /// Use this token tree as a matcher to parse given tts. - pub fn parse(cx: &base::ExtCtxt<'_>, mtch: &[quoted::TokenTree], tts: TokenStream) + crate fn parse(cx: &base::ExtCtxt<'_>, mtch: &[quoted::TokenTree], tts: TokenStream) -> macro_parser::NamedParseResult { // `None` is because we're not interpolating let directory = Directory { From 827a5b2ea8dc66bfdf817f52011f470f00bc6fee Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 22 Sep 2019 18:19:51 +0300 Subject: [PATCH 25/55] rename libsyntax::ext::tt to mbe mbe stands for macro-by-example --- src/libsyntax/ext/{tt => mbe}/macro_check.rs | 0 src/libsyntax/ext/{tt => mbe}/macro_parser.rs | 0 src/libsyntax/ext/{tt => mbe}/macro_rules.rs | 0 src/libsyntax/ext/{tt => mbe}/quoted.rs | 0 src/libsyntax/ext/{tt => mbe}/transcribe.rs | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename src/libsyntax/ext/{tt => mbe}/macro_check.rs (100%) rename src/libsyntax/ext/{tt => mbe}/macro_parser.rs (100%) rename src/libsyntax/ext/{tt => mbe}/macro_rules.rs (100%) rename src/libsyntax/ext/{tt => mbe}/quoted.rs (100%) rename src/libsyntax/ext/{tt => mbe}/transcribe.rs (100%) diff --git a/src/libsyntax/ext/tt/macro_check.rs b/src/libsyntax/ext/mbe/macro_check.rs similarity index 100% rename from src/libsyntax/ext/tt/macro_check.rs rename to src/libsyntax/ext/mbe/macro_check.rs diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/mbe/macro_parser.rs similarity index 100% rename from src/libsyntax/ext/tt/macro_parser.rs rename to src/libsyntax/ext/mbe/macro_parser.rs diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/mbe/macro_rules.rs similarity index 100% rename from src/libsyntax/ext/tt/macro_rules.rs rename to src/libsyntax/ext/mbe/macro_rules.rs diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/mbe/quoted.rs similarity index 100% rename from src/libsyntax/ext/tt/quoted.rs rename to src/libsyntax/ext/mbe/quoted.rs diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/mbe/transcribe.rs similarity index 100% rename from src/libsyntax/ext/tt/transcribe.rs rename to src/libsyntax/ext/mbe/transcribe.rs From 49f849cdb7910162f15ac6ac26a98ba22009dc9a Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 22 Sep 2019 18:25:29 +0300 Subject: [PATCH 26/55] rename tt -> mbe, part 2 --- src/libsyntax/ext/expand.rs | 6 +++--- src/libsyntax/ext/mbe/macro_check.rs | 2 +- src/libsyntax/ext/mbe/macro_parser.rs | 2 +- src/libsyntax/ext/mbe/macro_rules.rs | 12 ++++++------ src/libsyntax/ext/mbe/quoted.rs | 2 +- src/libsyntax/ext/mbe/transcribe.rs | 4 ++-- src/libsyntax/lib.rs | 4 ++-- src/libsyntax/tokenstream.rs | 2 +- 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index b80c530731dfc..2cd802f22d306 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -6,7 +6,7 @@ use crate::config::StripUnconfigured; use crate::ext::base::*; use crate::ext::proc_macro::{collect_derives, MarkAttrs}; use crate::ext::hygiene::{ExpnId, SyntaxContext, ExpnData, ExpnKind}; -use crate::ext::tt::macro_rules::annotate_err_with_kind; +use crate::ext::mbe::macro_rules::annotate_err_with_kind; use crate::ext::placeholders::{placeholder, PlaceholderExpander}; use crate::feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feature_err}; use crate::mut_visit::*; @@ -115,8 +115,8 @@ macro_rules! ast_fragments { } } - impl<'a> MacResult for crate::ext::tt::macro_rules::ParserAnyMacro<'a> { - $(fn $make_ast(self: Box>) + impl<'a> MacResult for crate::ext::mbe::macro_rules::ParserAnyMacro<'a> { + $(fn $make_ast(self: Box>) -> Option<$AstTy> { Some(self.make(AstFragmentKind::$Kind).$make_ast()) })* diff --git a/src/libsyntax/ext/mbe/macro_check.rs b/src/libsyntax/ext/mbe/macro_check.rs index a1734689595f0..aa88d71666eb5 100644 --- a/src/libsyntax/ext/mbe/macro_check.rs +++ b/src/libsyntax/ext/mbe/macro_check.rs @@ -106,7 +106,7 @@ //! bound. use crate::ast::NodeId; use crate::early_buffered_lints::BufferedEarlyLintId; -use crate::ext::tt::quoted::{KleeneToken, TokenTree}; +use crate::ext::mbe::quoted::{KleeneToken, TokenTree}; use crate::parse::token::TokenKind; use crate::parse::token::{DelimToken, Token}; use crate::parse::ParseSess; diff --git a/src/libsyntax/ext/mbe/macro_parser.rs b/src/libsyntax/ext/mbe/macro_parser.rs index a34a0344f2740..88145cd121f14 100644 --- a/src/libsyntax/ext/mbe/macro_parser.rs +++ b/src/libsyntax/ext/mbe/macro_parser.rs @@ -75,7 +75,7 @@ crate use ParseResult::*; use TokenTreeOrTokenTreeSlice::*; use crate::ast::{Ident, Name}; -use crate::ext::tt::quoted::{self, TokenTree}; +use crate::ext::mbe::quoted::{self, TokenTree}; use crate::parse::{Directory, ParseSess}; use crate::parse::parser::{Parser, PathStyle}; use crate::parse::token::{self, DocComment, Nonterminal, Token}; diff --git a/src/libsyntax/ext/mbe/macro_rules.rs b/src/libsyntax/ext/mbe/macro_rules.rs index 90dfa6e7ac8a4..939f5b8f51d57 100644 --- a/src/libsyntax/ext/mbe/macro_rules.rs +++ b/src/libsyntax/ext/mbe/macro_rules.rs @@ -4,12 +4,12 @@ use crate::edition::Edition; use crate::ext::base::{DummyResult, ExtCtxt, MacResult, TTMacroExpander}; use crate::ext::base::{SyntaxExtension, SyntaxExtensionKind}; use crate::ext::expand::{AstFragment, AstFragmentKind}; -use crate::ext::tt::macro_check; -use crate::ext::tt::macro_parser::{parse, parse_failure_msg}; -use crate::ext::tt::macro_parser::{Error, Failure, Success}; -use crate::ext::tt::macro_parser::{MatchedNonterminal, MatchedSeq}; -use crate::ext::tt::quoted; -use crate::ext::tt::transcribe::transcribe; +use crate::ext::mbe::macro_check; +use crate::ext::mbe::macro_parser::{parse, parse_failure_msg}; +use crate::ext::mbe::macro_parser::{Error, Failure, Success}; +use crate::ext::mbe::macro_parser::{MatchedNonterminal, MatchedSeq}; +use crate::ext::mbe::quoted; +use crate::ext::mbe::transcribe::transcribe; use crate::feature_gate::Features; use crate::parse::parser::Parser; use crate::parse::token::TokenKind::*; diff --git a/src/libsyntax/ext/mbe/quoted.rs b/src/libsyntax/ext/mbe/quoted.rs index d161e6638bf75..8ef2834523112 100644 --- a/src/libsyntax/ext/mbe/quoted.rs +++ b/src/libsyntax/ext/mbe/quoted.rs @@ -1,6 +1,6 @@ use crate::ast; use crate::ast::NodeId; -use crate::ext::tt::macro_parser; +use crate::ext::mbe::macro_parser; use crate::feature_gate::Features; use crate::parse::token::{self, Token, TokenKind}; use crate::parse::ParseSess; diff --git a/src/libsyntax/ext/mbe/transcribe.rs b/src/libsyntax/ext/mbe/transcribe.rs index f9c07e3a2e4ff..94ac1f60c6407 100644 --- a/src/libsyntax/ext/mbe/transcribe.rs +++ b/src/libsyntax/ext/mbe/transcribe.rs @@ -1,7 +1,7 @@ use crate::ast::{Ident, Mac}; use crate::ext::base::ExtCtxt; -use crate::ext::tt::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch}; -use crate::ext::tt::quoted; +use crate::ext::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch}; +use crate::ext::mbe::quoted; use crate::mut_visit::{self, MutVisitor}; use crate::parse::token::{self, NtTT, Token}; use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint}; diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index c06f43021021a..045a36931883c 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -162,14 +162,14 @@ pub mod ext { mod proc_macro_server; pub use syntax_pos::hygiene; - pub use tt::macro_rules::compile_declarative_macro; + pub use mbe::macro_rules::compile_declarative_macro; pub mod allocator; pub mod base; pub mod build; pub mod expand; pub mod proc_macro; - crate mod tt { + crate mod mbe { crate mod transcribe; crate mod macro_check; crate mod macro_parser; diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 15fc4b02041b7..d46e38f53d51b 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -14,7 +14,7 @@ //! ownership of the original. use crate::ext::base; -use crate::ext::tt::{macro_parser, quoted}; +use crate::ext::mbe::{macro_parser, quoted}; use crate::parse::Directory; use crate::parse::token::{self, DelimToken, Token, TokenKind}; use crate::print::pprust; From e30c5166db72f9f1ceccc355df25b49df826df02 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 22 Sep 2019 18:28:32 +0300 Subject: [PATCH 27/55] move mbe module to a separate file --- src/libsyntax/ext/mbe.rs | 5 +++++ src/libsyntax/lib.rs | 8 +------- 2 files changed, 6 insertions(+), 7 deletions(-) create mode 100644 src/libsyntax/ext/mbe.rs diff --git a/src/libsyntax/ext/mbe.rs b/src/libsyntax/ext/mbe.rs new file mode 100644 index 0000000000000..b77b59fea7039 --- /dev/null +++ b/src/libsyntax/ext/mbe.rs @@ -0,0 +1,5 @@ +crate mod transcribe; +crate mod macro_check; +crate mod macro_parser; +crate mod macro_rules; +crate mod quoted; diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 045a36931883c..402d563010fdc 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -169,13 +169,7 @@ pub mod ext { pub mod expand; pub mod proc_macro; - crate mod mbe { - crate mod transcribe; - crate mod macro_check; - crate mod macro_parser; - crate mod macro_rules; - crate mod quoted; - } + crate mod mbe; } pub mod early_buffered_lints; From 636b3543c27e1eba301605afd2143fc96fd14431 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 22 Sep 2019 20:36:35 +0300 Subject: [PATCH 28/55] docstring for mbe module --- src/libsyntax/ext/mbe.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libsyntax/ext/mbe.rs b/src/libsyntax/ext/mbe.rs index b77b59fea7039..78d96f471fa7f 100644 --- a/src/libsyntax/ext/mbe.rs +++ b/src/libsyntax/ext/mbe.rs @@ -1,3 +1,8 @@ +//! This module implements declarative macros: old `macro_rules` and the newer +//! `macro`. Declarative macros are also known as "macro by example", and that's +//! why we call this module `mbe`. For external documentation, prefer the +//! official terminology: "declarative macros". + crate mod transcribe; crate mod macro_check; crate mod macro_parser; From 9fd75f52877a3e23a7b9a6a9675f37a42340a428 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 22 Sep 2019 19:17:30 +0300 Subject: [PATCH 29/55] pull mbe token tree definition up --- src/libsyntax/ext/mbe.rs | 156 ++++++++++++++++++++++++++ src/libsyntax/ext/mbe/macro_check.rs | 2 +- src/libsyntax/ext/mbe/macro_parser.rs | 10 +- src/libsyntax/ext/mbe/macro_rules.rs | 116 +++++++++---------- src/libsyntax/ext/mbe/quoted.rs | 155 +------------------------ src/libsyntax/ext/mbe/transcribe.rs | 34 +++--- src/libsyntax/tokenstream.rs | 4 +- 7 files changed, 243 insertions(+), 234 deletions(-) diff --git a/src/libsyntax/ext/mbe.rs b/src/libsyntax/ext/mbe.rs index 78d96f471fa7f..c18b8918ff1e3 100644 --- a/src/libsyntax/ext/mbe.rs +++ b/src/libsyntax/ext/mbe.rs @@ -8,3 +8,159 @@ crate mod macro_check; crate mod macro_parser; crate mod macro_rules; crate mod quoted; + +use crate::ast; +use crate::parse::token::{self, Token, TokenKind}; +use crate::tokenstream::{DelimSpan}; + +use syntax_pos::{BytePos, Span}; + +use rustc_data_structures::sync::Lrc; + +/// Contains the sub-token-trees of a "delimited" token tree, such as the contents of `(`. Note +/// that the delimiter itself might be `NoDelim`. +#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)] +crate struct Delimited { + crate delim: token::DelimToken, + crate tts: Vec, +} + +impl Delimited { + /// Returns a `self::TokenTree` with a `Span` corresponding to the opening delimiter. + crate fn open_tt(&self, span: Span) -> TokenTree { + let open_span = if span.is_dummy() { + span + } else { + span.with_hi(span.lo() + BytePos(self.delim.len() as u32)) + }; + TokenTree::token(token::OpenDelim(self.delim), open_span) + } + + /// Returns a `self::TokenTree` with a `Span` corresponding to the closing delimiter. + crate fn close_tt(&self, span: Span) -> TokenTree { + let close_span = if span.is_dummy() { + span + } else { + span.with_lo(span.hi() - BytePos(self.delim.len() as u32)) + }; + TokenTree::token(token::CloseDelim(self.delim), close_span) + } +} + +#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)] +crate struct SequenceRepetition { + /// The sequence of token trees + crate tts: Vec, + /// The optional separator + crate separator: Option, + /// Whether the sequence can be repeated zero (*), or one or more times (+) + crate kleene: KleeneToken, + /// The number of `Match`s that appear in the sequence (and subsequences) + crate num_captures: usize, +} + +#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)] +crate struct KleeneToken { + crate span: Span, + crate op: KleeneOp, +} + +impl KleeneToken { + crate fn new(op: KleeneOp, span: Span) -> KleeneToken { + KleeneToken { span, op } + } +} + +/// A Kleene-style [repetition operator](http://en.wikipedia.org/wiki/Kleene_star) +/// for token sequences. +#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +crate enum KleeneOp { + /// Kleene star (`*`) for zero or more repetitions + ZeroOrMore, + /// Kleene plus (`+`) for one or more repetitions + OneOrMore, + /// Kleene optional (`?`) for zero or one reptitions + ZeroOrOne, +} + +/// Similar to `tokenstream::TokenTree`, except that `$i`, `$i:ident`, and `$(...)` +/// are "first-class" token trees. Useful for parsing macros. +#[derive(Debug, Clone, PartialEq, RustcEncodable, RustcDecodable)] +crate enum TokenTree { + Token(Token), + Delimited(DelimSpan, Lrc), + /// A kleene-style repetition sequence + Sequence(DelimSpan, Lrc), + /// e.g., `$var` + MetaVar(Span, ast::Ident), + /// e.g., `$var:expr`. This is only used in the left hand side of MBE macros. + MetaVarDecl( + Span, + ast::Ident, /* name to bind */ + ast::Ident, /* kind of nonterminal */ + ), +} + +impl TokenTree { + /// Return the number of tokens in the tree. + crate fn len(&self) -> usize { + match *self { + TokenTree::Delimited(_, ref delimed) => match delimed.delim { + token::NoDelim => delimed.tts.len(), + _ => delimed.tts.len() + 2, + }, + TokenTree::Sequence(_, ref seq) => seq.tts.len(), + _ => 0, + } + } + + /// Returns `true` if the given token tree is delimited. + crate fn is_delimited(&self) -> bool { + match *self { + TokenTree::Delimited(..) => true, + _ => false, + } + } + + /// Returns `true` if the given token tree is a token of the given kind. + crate fn is_token(&self, expected_kind: &TokenKind) -> bool { + match self { + TokenTree::Token(Token { kind: actual_kind, .. }) => actual_kind == expected_kind, + _ => false, + } + } + + /// Gets the `index`-th sub-token-tree. This only makes sense for delimited trees and sequences. + crate fn get_tt(&self, index: usize) -> TokenTree { + match (self, index) { + (&TokenTree::Delimited(_, ref delimed), _) if delimed.delim == token::NoDelim => { + delimed.tts[index].clone() + } + (&TokenTree::Delimited(span, ref delimed), _) => { + if index == 0 { + return delimed.open_tt(span.open); + } + if index == delimed.tts.len() + 1 { + return delimed.close_tt(span.close); + } + delimed.tts[index - 1].clone() + } + (&TokenTree::Sequence(_, ref seq), _) => seq.tts[index].clone(), + _ => panic!("Cannot expand a token tree"), + } + } + + /// Retrieves the `TokenTree`'s span. + crate fn span(&self) -> Span { + match *self { + TokenTree::Token(Token { span, .. }) + | TokenTree::MetaVar(span, _) + | TokenTree::MetaVarDecl(span, _, _) => span, + TokenTree::Delimited(span, _) | TokenTree::Sequence(span, _) => span.entire(), + } + } + + crate fn token(kind: TokenKind, span: Span) -> TokenTree { + TokenTree::Token(Token::new(kind, span)) + } +} diff --git a/src/libsyntax/ext/mbe/macro_check.rs b/src/libsyntax/ext/mbe/macro_check.rs index aa88d71666eb5..a3750e5c46945 100644 --- a/src/libsyntax/ext/mbe/macro_check.rs +++ b/src/libsyntax/ext/mbe/macro_check.rs @@ -106,7 +106,7 @@ //! bound. use crate::ast::NodeId; use crate::early_buffered_lints::BufferedEarlyLintId; -use crate::ext::mbe::quoted::{KleeneToken, TokenTree}; +use crate::ext::mbe::{KleeneToken, TokenTree}; use crate::parse::token::TokenKind; use crate::parse::token::{DelimToken, Token}; use crate::parse::ParseSess; diff --git a/src/libsyntax/ext/mbe/macro_parser.rs b/src/libsyntax/ext/mbe/macro_parser.rs index 88145cd121f14..35fc6cf21b80e 100644 --- a/src/libsyntax/ext/mbe/macro_parser.rs +++ b/src/libsyntax/ext/mbe/macro_parser.rs @@ -75,7 +75,7 @@ crate use ParseResult::*; use TokenTreeOrTokenTreeSlice::*; use crate::ast::{Ident, Name}; -use crate::ext::mbe::quoted::{self, TokenTree}; +use crate::ext::mbe::{self, TokenTree}; use crate::parse::{Directory, ParseSess}; use crate::parse::parser::{Parser, PathStyle}; use crate::parse::token::{self, DocComment, Nonterminal, Token}; @@ -195,7 +195,7 @@ struct MatcherPos<'root, 'tt> { // `None`. /// The KleeneOp of this sequence if we are in a repetition. - seq_op: Option, + seq_op: Option, /// The separator if we are in a repetition. sep: Option, @@ -532,7 +532,7 @@ fn inner_parse_loop<'root, 'tt>( } // We don't need a separator. Move the "dot" back to the beginning of the matcher // and try to match again UNLESS we are only allowed to have _one_ repetition. - else if item.seq_op != Some(quoted::KleeneOp::ZeroOrOne) { + else if item.seq_op != Some(mbe::KleeneOp::ZeroOrOne) { item.match_cur = item.match_lo; item.idx = 0; cur_items.push(item); @@ -555,8 +555,8 @@ fn inner_parse_loop<'root, 'tt>( // implicitly disallowing OneOrMore from having 0 matches here. Thus, that will // result in a "no rules expected token" error by virtue of this matcher not // working. - if seq.kleene.op == quoted::KleeneOp::ZeroOrMore - || seq.kleene.op == quoted::KleeneOp::ZeroOrOne + if seq.kleene.op == mbe::KleeneOp::ZeroOrMore + || seq.kleene.op == mbe::KleeneOp::ZeroOrOne { let mut new_item = item.clone(); new_item.match_cur += seq.num_captures; diff --git a/src/libsyntax/ext/mbe/macro_rules.rs b/src/libsyntax/ext/mbe/macro_rules.rs index 939f5b8f51d57..2ec171a7fb591 100644 --- a/src/libsyntax/ext/mbe/macro_rules.rs +++ b/src/libsyntax/ext/mbe/macro_rules.rs @@ -4,11 +4,11 @@ use crate::edition::Edition; use crate::ext::base::{DummyResult, ExtCtxt, MacResult, TTMacroExpander}; use crate::ext::base::{SyntaxExtension, SyntaxExtensionKind}; use crate::ext::expand::{AstFragment, AstFragmentKind}; +use crate::ext::mbe; use crate::ext::mbe::macro_check; use crate::ext::mbe::macro_parser::{parse, parse_failure_msg}; use crate::ext::mbe::macro_parser::{Error, Failure, Success}; use crate::ext::mbe::macro_parser::{MatchedNonterminal, MatchedSeq}; -use crate::ext::mbe::quoted; use crate::ext::mbe::transcribe::transcribe; use crate::feature_gate::Features; use crate::parse::parser::Parser; @@ -135,8 +135,8 @@ struct MacroRulesMacroExpander { name: ast::Ident, span: Span, transparency: Transparency, - lhses: Vec, - rhses: Vec, + lhses: Vec, + rhses: Vec, valid: bool, } @@ -169,8 +169,8 @@ fn generic_extension<'cx>( name: ast::Ident, transparency: Transparency, arg: TokenStream, - lhses: &[quoted::TokenTree], - rhses: &[quoted::TokenTree], + lhses: &[mbe::TokenTree], + rhses: &[mbe::TokenTree], ) -> Box { if cx.trace_macros() { trace_macros_note(cx, sp, format!("expanding `{}! {{ {} }}`", name, arg)); @@ -182,7 +182,7 @@ fn generic_extension<'cx>( for (i, lhs) in lhses.iter().enumerate() { // try each arm's matchers let lhs_tt = match *lhs { - quoted::TokenTree::Delimited(_, ref delim) => &delim.tts[..], + mbe::TokenTree::Delimited(_, ref delim) => &delim.tts[..], _ => cx.span_bug(sp, "malformed macro lhs"), }; @@ -190,7 +190,7 @@ fn generic_extension<'cx>( Success(named_matches) => { let rhs = match rhses[i] { // ignore delimiters - quoted::TokenTree::Delimited(_, ref delimed) => delimed.tts.clone(), + mbe::TokenTree::Delimited(_, ref delimed) => delimed.tts.clone(), _ => cx.span_bug(sp, "malformed macro rhs"), }; let arm_span = rhses[i].span(); @@ -258,7 +258,7 @@ fn generic_extension<'cx>( for lhs in lhses { // try each arm's matchers let lhs_tt = match *lhs { - quoted::TokenTree::Delimited(_, ref delim) => &delim.tts[..], + mbe::TokenTree::Delimited(_, ref delim) => &delim.tts[..], _ => continue, }; match TokenTree::parse(cx, lhs_tt, arg.clone()) { @@ -312,32 +312,32 @@ pub fn compile_declarative_macro( // ...quasiquoting this would be nice. // These spans won't matter, anyways let argument_gram = vec![ - quoted::TokenTree::Sequence( + mbe::TokenTree::Sequence( DelimSpan::dummy(), - Lrc::new(quoted::SequenceRepetition { + Lrc::new(mbe::SequenceRepetition { tts: vec![ - quoted::TokenTree::MetaVarDecl(def.span, lhs_nm, tt_spec), - quoted::TokenTree::token(token::FatArrow, def.span), - quoted::TokenTree::MetaVarDecl(def.span, rhs_nm, tt_spec), + mbe::TokenTree::MetaVarDecl(def.span, lhs_nm, tt_spec), + mbe::TokenTree::token(token::FatArrow, def.span), + mbe::TokenTree::MetaVarDecl(def.span, rhs_nm, tt_spec), ], separator: Some(Token::new( if body.legacy { token::Semi } else { token::Comma }, def.span, )), - kleene: quoted::KleeneToken::new(quoted::KleeneOp::OneOrMore, def.span), + kleene: mbe::KleeneToken::new(mbe::KleeneOp::OneOrMore, def.span), num_captures: 2, }), ), // to phase into semicolon-termination instead of semicolon-separation - quoted::TokenTree::Sequence( + mbe::TokenTree::Sequence( DelimSpan::dummy(), - Lrc::new(quoted::SequenceRepetition { - tts: vec![quoted::TokenTree::token( + Lrc::new(mbe::SequenceRepetition { + tts: vec![mbe::TokenTree::token( if body.legacy { token::Semi } else { token::Comma }, def.span, )], separator: None, - kleene: quoted::KleeneToken::new(quoted::KleeneOp::ZeroOrMore, def.span), + kleene: mbe::KleeneToken::new(mbe::KleeneOp::ZeroOrMore, def.span), num_captures: 0, }), ), @@ -367,7 +367,7 @@ pub fn compile_declarative_macro( .map(|m| { if let MatchedNonterminal(ref nt) = *m { if let NtTT(ref tt) = **nt { - let tt = quoted::parse( + let tt = mbe::quoted::parse( tt.clone().into(), true, sess, @@ -384,7 +384,7 @@ pub fn compile_declarative_macro( } sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs") }) - .collect::>(), + .collect::>(), _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs"), }; @@ -394,7 +394,7 @@ pub fn compile_declarative_macro( .map(|m| { if let MatchedNonterminal(ref nt) = *m { if let NtTT(ref tt) = **nt { - return quoted::parse( + return mbe::quoted::parse( tt.clone().into(), false, sess, @@ -409,7 +409,7 @@ pub fn compile_declarative_macro( } sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs") }) - .collect::>(), + .collect::>(), _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs"), }; @@ -454,11 +454,11 @@ fn check_lhs_nt_follows( sess: &ParseSess, features: &Features, attrs: &[ast::Attribute], - lhs: "ed::TokenTree, + lhs: &mbe::TokenTree, ) -> bool { // lhs is going to be like TokenTree::Delimited(...), where the // entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens. - if let quoted::TokenTree::Delimited(_, ref tts) = *lhs { + if let mbe::TokenTree::Delimited(_, ref tts) = *lhs { check_matcher(sess, features, attrs, &tts.tts) } else { let msg = "invalid macro matcher; matchers must be contained in balanced delimiters"; @@ -471,8 +471,8 @@ fn check_lhs_nt_follows( /// Checks that the lhs contains no repetition which could match an empty token /// tree, because then the matcher would hang indefinitely. -fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[quoted::TokenTree]) -> bool { - use quoted::TokenTree; +fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool { + use mbe::TokenTree; for tt in tts { match *tt { TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => (), @@ -486,8 +486,8 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[quoted::TokenTree]) -> bool { && seq.tts.iter().all(|seq_tt| match *seq_tt { TokenTree::MetaVarDecl(_, _, id) => id.name == sym::vis, TokenTree::Sequence(_, ref sub_seq) => { - sub_seq.kleene.op == quoted::KleeneOp::ZeroOrMore - || sub_seq.kleene.op == quoted::KleeneOp::ZeroOrOne + sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore + || sub_seq.kleene.op == mbe::KleeneOp::ZeroOrOne } _ => false, }) @@ -506,9 +506,9 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[quoted::TokenTree]) -> bool { true } -fn check_rhs(sess: &ParseSess, rhs: "ed::TokenTree) -> bool { +fn check_rhs(sess: &ParseSess, rhs: &mbe::TokenTree) -> bool { match *rhs { - quoted::TokenTree::Delimited(..) => return true, + mbe::TokenTree::Delimited(..) => return true, _ => sess.span_diagnostic.span_err(rhs.span(), "macro rhs must be delimited"), } false @@ -518,7 +518,7 @@ fn check_matcher( sess: &ParseSess, features: &Features, attrs: &[ast::Attribute], - matcher: &[quoted::TokenTree], + matcher: &[mbe::TokenTree], ) -> bool { let first_sets = FirstSets::new(matcher); let empty_suffix = TokenSet::empty(); @@ -550,8 +550,8 @@ struct FirstSets { } impl FirstSets { - fn new(tts: &[quoted::TokenTree]) -> FirstSets { - use quoted::TokenTree; + fn new(tts: &[mbe::TokenTree]) -> FirstSets { + use mbe::TokenTree; let mut sets = FirstSets { first: FxHashMap::default() }; build_recur(&mut sets, tts); @@ -598,8 +598,8 @@ impl FirstSets { // Reverse scan: Sequence comes before `first`. if subfirst.maybe_empty - || seq_rep.kleene.op == quoted::KleeneOp::ZeroOrMore - || seq_rep.kleene.op == quoted::KleeneOp::ZeroOrOne + || seq_rep.kleene.op == mbe::KleeneOp::ZeroOrMore + || seq_rep.kleene.op == mbe::KleeneOp::ZeroOrOne { // If sequence is potentially empty, then // union them (preserving first emptiness). @@ -619,8 +619,8 @@ impl FirstSets { // walks forward over `tts` until all potential FIRST tokens are // identified. - fn first(&self, tts: &[quoted::TokenTree]) -> TokenSet { - use quoted::TokenTree; + fn first(&self, tts: &[mbe::TokenTree]) -> TokenSet { + use mbe::TokenTree; let mut first = TokenSet::empty(); for tt in tts.iter() { @@ -656,8 +656,8 @@ impl FirstSets { assert!(first.maybe_empty); first.add_all(subfirst); if subfirst.maybe_empty - || seq_rep.kleene.op == quoted::KleeneOp::ZeroOrMore - || seq_rep.kleene.op == quoted::KleeneOp::ZeroOrOne + || seq_rep.kleene.op == mbe::KleeneOp::ZeroOrMore + || seq_rep.kleene.op == mbe::KleeneOp::ZeroOrOne { // Continue scanning for more first // tokens, but also make sure we @@ -678,7 +678,7 @@ impl FirstSets { } } -// A set of `quoted::TokenTree`s, which may include `TokenTree::Match`s +// A set of `mbe::TokenTree`s, which may include `TokenTree::Match`s // (for macro-by-example syntactic variables). It also carries the // `maybe_empty` flag; that is true if and only if the matcher can // match an empty token sequence. @@ -690,7 +690,7 @@ impl FirstSets { // (Notably, we must allow for *-op to occur zero times.) #[derive(Clone, Debug)] struct TokenSet { - tokens: Vec, + tokens: Vec, maybe_empty: bool, } @@ -702,13 +702,13 @@ impl TokenSet { // Returns the set `{ tok }` for the single-token (and thus // non-empty) sequence [tok]. - fn singleton(tok: quoted::TokenTree) -> Self { + fn singleton(tok: mbe::TokenTree) -> Self { TokenSet { tokens: vec![tok], maybe_empty: false } } // Changes self to be the set `{ tok }`. // Since `tok` is always present, marks self as non-empty. - fn replace_with(&mut self, tok: quoted::TokenTree) { + fn replace_with(&mut self, tok: mbe::TokenTree) { self.tokens.clear(); self.tokens.push(tok); self.maybe_empty = false; @@ -723,7 +723,7 @@ impl TokenSet { } // Adds `tok` to the set for `self`, marking sequence as non-empy. - fn add_one(&mut self, tok: quoted::TokenTree) { + fn add_one(&mut self, tok: mbe::TokenTree) { if !self.tokens.contains(&tok) { self.tokens.push(tok); } @@ -731,7 +731,7 @@ impl TokenSet { } // Adds `tok` to the set for `self`. (Leaves `maybe_empty` flag alone.) - fn add_one_maybe(&mut self, tok: quoted::TokenTree) { + fn add_one_maybe(&mut self, tok: mbe::TokenTree) { if !self.tokens.contains(&tok) { self.tokens.push(tok); } @@ -772,10 +772,10 @@ fn check_matcher_core( features: &Features, attrs: &[ast::Attribute], first_sets: &FirstSets, - matcher: &[quoted::TokenTree], + matcher: &[mbe::TokenTree], follow: &TokenSet, ) -> TokenSet { - use quoted::TokenTree; + use mbe::TokenTree; let mut last = TokenSet::empty(); @@ -950,8 +950,8 @@ fn check_matcher_core( last } -fn token_can_be_followed_by_any(tok: "ed::TokenTree) -> bool { - if let quoted::TokenTree::MetaVarDecl(_, _, frag_spec) = *tok { +fn token_can_be_followed_by_any(tok: &mbe::TokenTree) -> bool { + if let mbe::TokenTree::MetaVarDecl(_, _, frag_spec) = *tok { frag_can_be_followed_by_any(frag_spec.name) } else { // (Non NT's can always be followed by anthing in matchers.) @@ -997,8 +997,8 @@ enum IsInFollow { /// break macros that were relying on that binary operator as a /// separator. // when changing this do not forget to update doc/book/macros.md! -fn is_in_follow(tok: "ed::TokenTree, frag: Symbol) -> IsInFollow { - use quoted::TokenTree; +fn is_in_follow(tok: &mbe::TokenTree, frag: Symbol) -> IsInFollow { + use mbe::TokenTree; if let TokenTree::Token(Token { kind: token::CloseDelim(_), .. }) = *tok { // closing a token tree can never be matched by any fragment; @@ -1116,10 +1116,10 @@ fn has_legal_fragment_specifier( sess: &ParseSess, features: &Features, attrs: &[ast::Attribute], - tok: "ed::TokenTree, + tok: &mbe::TokenTree, ) -> Result<(), String> { debug!("has_legal_fragment_specifier({:?})", tok); - if let quoted::TokenTree::MetaVarDecl(_, _, ref frag_spec) = *tok { + if let mbe::TokenTree::MetaVarDecl(_, _, ref frag_spec) = *tok { let frag_span = tok.span(); if !is_legal_fragment_specifier(sess, features, attrs, frag_spec.name, frag_span) { return Err(frag_spec.to_string()); @@ -1160,13 +1160,13 @@ fn is_legal_fragment_specifier( } } -fn quoted_tt_to_string(tt: "ed::TokenTree) -> String { +fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String { match *tt { - quoted::TokenTree::Token(ref token) => crate::print::pprust::token_to_string(&token), - quoted::TokenTree::MetaVar(_, name) => format!("${}", name), - quoted::TokenTree::MetaVarDecl(_, name, kind) => format!("${}:{}", name, kind), + mbe::TokenTree::Token(ref token) => crate::print::pprust::token_to_string(&token), + mbe::TokenTree::MetaVar(_, name) => format!("${}", name), + mbe::TokenTree::MetaVarDecl(_, name, kind) => format!("${}:{}", name, kind), _ => panic!( - "unexpected quoted::TokenTree::{{Sequence or Delimited}} \ + "unexpected mbe::TokenTree::{{Sequence or Delimited}} \ in follow set checker" ), } diff --git a/src/libsyntax/ext/mbe/quoted.rs b/src/libsyntax/ext/mbe/quoted.rs index 8ef2834523112..82289d7449d36 100644 --- a/src/libsyntax/ext/mbe/quoted.rs +++ b/src/libsyntax/ext/mbe/quoted.rs @@ -1,166 +1,19 @@ use crate::ast; use crate::ast::NodeId; use crate::ext::mbe::macro_parser; +use crate::ext::mbe::{TokenTree, KleeneOp, KleeneToken, SequenceRepetition, Delimited}; use crate::feature_gate::Features; -use crate::parse::token::{self, Token, TokenKind}; +use crate::parse::token::{self, Token}; use crate::parse::ParseSess; use crate::print::pprust; use crate::symbol::kw; -use crate::tokenstream::{self, DelimSpan}; +use crate::tokenstream; -use syntax_pos::{edition::Edition, BytePos, Span}; +use syntax_pos::{edition::Edition, Span}; use rustc_data_structures::sync::Lrc; use std::iter::Peekable; -/// Contains the sub-token-trees of a "delimited" token tree, such as the contents of `(`. Note -/// that the delimiter itself might be `NoDelim`. -#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)] -crate struct Delimited { - crate delim: token::DelimToken, - crate tts: Vec, -} - -impl Delimited { - /// Returns a `self::TokenTree` with a `Span` corresponding to the opening delimiter. - crate fn open_tt(&self, span: Span) -> TokenTree { - let open_span = if span.is_dummy() { - span - } else { - span.with_hi(span.lo() + BytePos(self.delim.len() as u32)) - }; - TokenTree::token(token::OpenDelim(self.delim), open_span) - } - - /// Returns a `self::TokenTree` with a `Span` corresponding to the closing delimiter. - crate fn close_tt(&self, span: Span) -> TokenTree { - let close_span = if span.is_dummy() { - span - } else { - span.with_lo(span.hi() - BytePos(self.delim.len() as u32)) - }; - TokenTree::token(token::CloseDelim(self.delim), close_span) - } -} - -#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)] -crate struct SequenceRepetition { - /// The sequence of token trees - crate tts: Vec, - /// The optional separator - crate separator: Option, - /// Whether the sequence can be repeated zero (*), or one or more times (+) - crate kleene: KleeneToken, - /// The number of `Match`s that appear in the sequence (and subsequences) - crate num_captures: usize, -} - -#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)] -crate struct KleeneToken { - crate span: Span, - crate op: KleeneOp, -} - -impl KleeneToken { - crate fn new(op: KleeneOp, span: Span) -> KleeneToken { - KleeneToken { span, op } - } -} - -/// A Kleene-style [repetition operator](http://en.wikipedia.org/wiki/Kleene_star) -/// for token sequences. -#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] -crate enum KleeneOp { - /// Kleene star (`*`) for zero or more repetitions - ZeroOrMore, - /// Kleene plus (`+`) for one or more repetitions - OneOrMore, - /// Kleene optional (`?`) for zero or one reptitions - ZeroOrOne, -} - -/// Similar to `tokenstream::TokenTree`, except that `$i`, `$i:ident`, and `$(...)` -/// are "first-class" token trees. Useful for parsing macros. -#[derive(Debug, Clone, PartialEq, RustcEncodable, RustcDecodable)] -crate enum TokenTree { - Token(Token), - Delimited(DelimSpan, Lrc), - /// A kleene-style repetition sequence - Sequence(DelimSpan, Lrc), - /// e.g., `$var` - MetaVar(Span, ast::Ident), - /// e.g., `$var:expr`. This is only used in the left hand side of MBE macros. - MetaVarDecl( - Span, - ast::Ident, /* name to bind */ - ast::Ident, /* kind of nonterminal */ - ), -} - -impl TokenTree { - /// Return the number of tokens in the tree. - crate fn len(&self) -> usize { - match *self { - TokenTree::Delimited(_, ref delimed) => match delimed.delim { - token::NoDelim => delimed.tts.len(), - _ => delimed.tts.len() + 2, - }, - TokenTree::Sequence(_, ref seq) => seq.tts.len(), - _ => 0, - } - } - - /// Returns `true` if the given token tree is delimited. - crate fn is_delimited(&self) -> bool { - match *self { - TokenTree::Delimited(..) => true, - _ => false, - } - } - - /// Returns `true` if the given token tree is a token of the given kind. - crate fn is_token(&self, expected_kind: &TokenKind) -> bool { - match self { - TokenTree::Token(Token { kind: actual_kind, .. }) => actual_kind == expected_kind, - _ => false, - } - } - - /// Gets the `index`-th sub-token-tree. This only makes sense for delimited trees and sequences. - crate fn get_tt(&self, index: usize) -> TokenTree { - match (self, index) { - (&TokenTree::Delimited(_, ref delimed), _) if delimed.delim == token::NoDelim => { - delimed.tts[index].clone() - } - (&TokenTree::Delimited(span, ref delimed), _) => { - if index == 0 { - return delimed.open_tt(span.open); - } - if index == delimed.tts.len() + 1 { - return delimed.close_tt(span.close); - } - delimed.tts[index - 1].clone() - } - (&TokenTree::Sequence(_, ref seq), _) => seq.tts[index].clone(), - _ => panic!("Cannot expand a token tree"), - } - } - - /// Retrieves the `TokenTree`'s span. - crate fn span(&self) -> Span { - match *self { - TokenTree::Token(Token { span, .. }) - | TokenTree::MetaVar(span, _) - | TokenTree::MetaVarDecl(span, _, _) => span, - TokenTree::Delimited(span, _) | TokenTree::Sequence(span, _) => span.entire(), - } - } - - crate fn token(kind: TokenKind, span: Span) -> TokenTree { - TokenTree::Token(Token::new(kind, span)) - } -} - /// Takes a `tokenstream::TokenStream` and returns a `Vec`. Specifically, this /// takes a generic `TokenStream`, such as is used in the rest of the compiler, and returns a /// collection of `TokenTree` for use in parsing a macro. diff --git a/src/libsyntax/ext/mbe/transcribe.rs b/src/libsyntax/ext/mbe/transcribe.rs index 94ac1f60c6407..ba818ebd35c7f 100644 --- a/src/libsyntax/ext/mbe/transcribe.rs +++ b/src/libsyntax/ext/mbe/transcribe.rs @@ -1,7 +1,7 @@ use crate::ast::{Ident, Mac}; use crate::ext::base::ExtCtxt; +use crate::ext::mbe; use crate::ext::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch}; -use crate::ext::mbe::quoted; use crate::mut_visit::{self, MutVisitor}; use crate::parse::token::{self, NtTT, Token}; use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint}; @@ -38,22 +38,22 @@ impl Marker { /// An iterator over the token trees in a delimited token tree (`{ ... }`) or a sequence (`$(...)`). enum Frame { - Delimited { forest: Lrc, idx: usize, span: DelimSpan }, - Sequence { forest: Lrc, idx: usize, sep: Option }, + Delimited { forest: Lrc, idx: usize, span: DelimSpan }, + Sequence { forest: Lrc, idx: usize, sep: Option }, } impl Frame { /// Construct a new frame around the delimited set of tokens. - fn new(tts: Vec) -> Frame { - let forest = Lrc::new(quoted::Delimited { delim: token::NoDelim, tts }); + fn new(tts: Vec) -> Frame { + let forest = Lrc::new(mbe::Delimited { delim: token::NoDelim, tts }); Frame::Delimited { forest, idx: 0, span: DelimSpan::dummy() } } } impl Iterator for Frame { - type Item = quoted::TokenTree; + type Item = mbe::TokenTree; - fn next(&mut self) -> Option { + fn next(&mut self) -> Option { match *self { Frame::Delimited { ref forest, ref mut idx, .. } => { *idx += 1; @@ -90,7 +90,7 @@ impl Iterator for Frame { pub(super) fn transcribe( cx: &ExtCtxt<'_>, interp: &FxHashMap, - src: Vec, + src: Vec, transparency: Transparency, ) -> TokenStream { // Nothing for us to transcribe... @@ -178,7 +178,7 @@ pub(super) fn transcribe( // We are descending into a sequence. We first make sure that the matchers in the RHS // and the matches in `interp` have the same shape. Otherwise, either the caller or the // macro writer has made a mistake. - seq @ quoted::TokenTree::Sequence(..) => { + seq @ mbe::TokenTree::Sequence(..) => { match lockstep_iter_size(&seq, interp, &repeats) { LockstepIterSize::Unconstrained => { cx.span_fatal( @@ -199,7 +199,7 @@ pub(super) fn transcribe( LockstepIterSize::Constraint(len, _) => { // We do this to avoid an extra clone above. We know that this is a // sequence already. - let (sp, seq) = if let quoted::TokenTree::Sequence(sp, seq) = seq { + let (sp, seq) = if let mbe::TokenTree::Sequence(sp, seq) = seq { (sp, seq) } else { unreachable!() @@ -207,7 +207,7 @@ pub(super) fn transcribe( // Is the repetition empty? if len == 0 { - if seq.kleene.op == quoted::KleeneOp::OneOrMore { + if seq.kleene.op == mbe::KleeneOp::OneOrMore { // FIXME: this really ought to be caught at macro definition // time... It happens when the Kleene operator in the matcher and // the body for the same meta-variable do not match. @@ -232,7 +232,7 @@ pub(super) fn transcribe( } // Replace the meta-var with the matched token tree from the invocation. - quoted::TokenTree::MetaVar(mut sp, mut ident) => { + mbe::TokenTree::MetaVar(mut sp, mut ident) => { // Find the matched nonterminal from the macro invocation, and use it to replace // the meta-var. if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) { @@ -269,7 +269,7 @@ pub(super) fn transcribe( // We will produce all of the results of the inside of the `Delimited` and then we will // jump back out of the Delimited, pop the result_stack and add the new results back to // the previous results (from outside the Delimited). - quoted::TokenTree::Delimited(mut span, delimited) => { + mbe::TokenTree::Delimited(mut span, delimited) => { marker.visit_delim_span(&mut span); stack.push(Frame::Delimited { forest: delimited, idx: 0, span }); result_stack.push(mem::take(&mut result)); @@ -277,14 +277,14 @@ pub(super) fn transcribe( // Nothing much to do here. Just push the token to the result, being careful to // preserve syntax context. - quoted::TokenTree::Token(token) => { + mbe::TokenTree::Token(token) => { let mut tt = TokenTree::Token(token); marker.visit_tt(&mut tt); result.push(tt.into()); } // There should be no meta-var declarations in the invocation of a macro. - quoted::TokenTree::MetaVarDecl(..) => panic!("unexpected `TokenTree::MetaVarDecl"), + mbe::TokenTree::MetaVarDecl(..) => panic!("unexpected `TokenTree::MetaVarDecl"), } } } @@ -368,11 +368,11 @@ impl LockstepIterSize { /// `lookup_cur_matched` will return `None`, which is why this still works even in the presnece of /// multiple nested matcher sequences. fn lockstep_iter_size( - tree: "ed::TokenTree, + tree: &mbe::TokenTree, interpolations: &FxHashMap, repeats: &[(usize, usize)], ) -> LockstepIterSize { - use quoted::TokenTree; + use mbe::TokenTree; match *tree { TokenTree::Delimited(_, ref delimed) => { delimed.tts.iter().fold(LockstepIterSize::Unconstrained, |size, tt| { diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index d46e38f53d51b..fd87f8a1f678a 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -14,7 +14,7 @@ //! ownership of the original. use crate::ext::base; -use crate::ext::mbe::{macro_parser, quoted}; +use crate::ext::mbe::{self, macro_parser}; use crate::parse::Directory; use crate::parse::token::{self, DelimToken, Token, TokenKind}; use crate::print::pprust; @@ -64,7 +64,7 @@ where impl TokenTree { /// Use this token tree as a matcher to parse given tts. - crate fn parse(cx: &base::ExtCtxt<'_>, mtch: &[quoted::TokenTree], tts: TokenStream) + crate fn parse(cx: &base::ExtCtxt<'_>, mtch: &[mbe::TokenTree], tts: TokenStream) -> macro_parser::NamedParseResult { // `None` is because we're not interpolating let directory = Directory { From 983569732d24df434c644dd1764e9c5e4ecfd081 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 22 Sep 2019 19:41:04 +0300 Subject: [PATCH 30/55] push TokenTree::parse down --- src/libsyntax/ext/mbe/macro_rules.rs | 15 ++++++++++++++- src/libsyntax/tokenstream.rs | 15 --------------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/libsyntax/ext/mbe/macro_rules.rs b/src/libsyntax/ext/mbe/macro_rules.rs index 2ec171a7fb591..816baadb12fbb 100644 --- a/src/libsyntax/ext/mbe/macro_rules.rs +++ b/src/libsyntax/ext/mbe/macro_rules.rs @@ -8,7 +8,7 @@ use crate::ext::mbe; use crate::ext::mbe::macro_check; use crate::ext::mbe::macro_parser::{parse, parse_failure_msg}; use crate::ext::mbe::macro_parser::{Error, Failure, Success}; -use crate::ext::mbe::macro_parser::{MatchedNonterminal, MatchedSeq}; +use crate::ext::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedParseResult}; use crate::ext::mbe::transcribe::transcribe; use crate::feature_gate::Features; use crate::parse::parser::Parser; @@ -1171,3 +1171,16 @@ fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String { ), } } + +impl TokenTree { + /// Use this token tree as a matcher to parse given tts. + fn parse(cx: &ExtCtxt<'_>, mtch: &[mbe::TokenTree], tts: TokenStream) + -> NamedParseResult { + // `None` is because we're not interpolating + let directory = Directory { + path: Cow::from(cx.current_expansion.module.directory.as_path()), + ownership: cx.current_expansion.directory_ownership, + }; + parse(cx.parse_sess(), tts, mtch, Some(directory), true) + } +} diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index fd87f8a1f678a..26cae2a8e7c42 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -13,9 +13,6 @@ //! and a borrowed `TokenStream` is sufficient to build an owned `TokenStream` without taking //! ownership of the original. -use crate::ext::base; -use crate::ext::mbe::{self, macro_parser}; -use crate::parse::Directory; use crate::parse::token::{self, DelimToken, Token, TokenKind}; use crate::print::pprust; @@ -26,7 +23,6 @@ use rustc_data_structures::sync::Lrc; use rustc_serialize::{Decoder, Decodable, Encoder, Encodable}; use smallvec::{SmallVec, smallvec}; -use std::borrow::Cow; use std::{fmt, iter, mem}; #[cfg(test)] @@ -63,17 +59,6 @@ where {} impl TokenTree { - /// Use this token tree as a matcher to parse given tts. - crate fn parse(cx: &base::ExtCtxt<'_>, mtch: &[mbe::TokenTree], tts: TokenStream) - -> macro_parser::NamedParseResult { - // `None` is because we're not interpolating - let directory = Directory { - path: Cow::from(cx.current_expansion.module.directory.as_path()), - ownership: cx.current_expansion.directory_ownership, - }; - macro_parser::parse(cx.parse_sess(), tts, mtch, Some(directory), true) - } - /// Checks if this TokenTree is equal to the other, regardless of span information. pub fn eq_unspanned(&self, other: &TokenTree) -> bool { match (self, other) { From 81fe85710d7f749c87494c4b968861adc67a9c4a Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 22 Sep 2019 19:42:52 +0300 Subject: [PATCH 31/55] make mbe::TokenTree private to module --- src/libsyntax/ext/mbe.rs | 44 +++++++++++++-------------- src/libsyntax/ext/mbe/macro_check.rs | 2 +- src/libsyntax/ext/mbe/macro_parser.rs | 4 +-- src/libsyntax/ext/mbe/quoted.rs | 2 +- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/libsyntax/ext/mbe.rs b/src/libsyntax/ext/mbe.rs index c18b8918ff1e3..a87da791c9b4f 100644 --- a/src/libsyntax/ext/mbe.rs +++ b/src/libsyntax/ext/mbe.rs @@ -20,14 +20,14 @@ use rustc_data_structures::sync::Lrc; /// Contains the sub-token-trees of a "delimited" token tree, such as the contents of `(`. Note /// that the delimiter itself might be `NoDelim`. #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)] -crate struct Delimited { - crate delim: token::DelimToken, - crate tts: Vec, +struct Delimited { + delim: token::DelimToken, + tts: Vec, } impl Delimited { /// Returns a `self::TokenTree` with a `Span` corresponding to the opening delimiter. - crate fn open_tt(&self, span: Span) -> TokenTree { + fn open_tt(&self, span: Span) -> TokenTree { let open_span = if span.is_dummy() { span } else { @@ -37,7 +37,7 @@ impl Delimited { } /// Returns a `self::TokenTree` with a `Span` corresponding to the closing delimiter. - crate fn close_tt(&self, span: Span) -> TokenTree { + fn close_tt(&self, span: Span) -> TokenTree { let close_span = if span.is_dummy() { span } else { @@ -48,25 +48,25 @@ impl Delimited { } #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)] -crate struct SequenceRepetition { +struct SequenceRepetition { /// The sequence of token trees - crate tts: Vec, + tts: Vec, /// The optional separator - crate separator: Option, + separator: Option, /// Whether the sequence can be repeated zero (*), or one or more times (+) - crate kleene: KleeneToken, + kleene: KleeneToken, /// The number of `Match`s that appear in the sequence (and subsequences) - crate num_captures: usize, + num_captures: usize, } #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)] -crate struct KleeneToken { - crate span: Span, - crate op: KleeneOp, +struct KleeneToken { + span: Span, + op: KleeneOp, } impl KleeneToken { - crate fn new(op: KleeneOp, span: Span) -> KleeneToken { + fn new(op: KleeneOp, span: Span) -> KleeneToken { KleeneToken { span, op } } } @@ -74,7 +74,7 @@ impl KleeneToken { /// A Kleene-style [repetition operator](http://en.wikipedia.org/wiki/Kleene_star) /// for token sequences. #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] -crate enum KleeneOp { +enum KleeneOp { /// Kleene star (`*`) for zero or more repetitions ZeroOrMore, /// Kleene plus (`+`) for one or more repetitions @@ -86,7 +86,7 @@ crate enum KleeneOp { /// Similar to `tokenstream::TokenTree`, except that `$i`, `$i:ident`, and `$(...)` /// are "first-class" token trees. Useful for parsing macros. #[derive(Debug, Clone, PartialEq, RustcEncodable, RustcDecodable)] -crate enum TokenTree { +enum TokenTree { Token(Token), Delimited(DelimSpan, Lrc), /// A kleene-style repetition sequence @@ -103,7 +103,7 @@ crate enum TokenTree { impl TokenTree { /// Return the number of tokens in the tree. - crate fn len(&self) -> usize { + fn len(&self) -> usize { match *self { TokenTree::Delimited(_, ref delimed) => match delimed.delim { token::NoDelim => delimed.tts.len(), @@ -115,7 +115,7 @@ impl TokenTree { } /// Returns `true` if the given token tree is delimited. - crate fn is_delimited(&self) -> bool { + fn is_delimited(&self) -> bool { match *self { TokenTree::Delimited(..) => true, _ => false, @@ -123,7 +123,7 @@ impl TokenTree { } /// Returns `true` if the given token tree is a token of the given kind. - crate fn is_token(&self, expected_kind: &TokenKind) -> bool { + fn is_token(&self, expected_kind: &TokenKind) -> bool { match self { TokenTree::Token(Token { kind: actual_kind, .. }) => actual_kind == expected_kind, _ => false, @@ -131,7 +131,7 @@ impl TokenTree { } /// Gets the `index`-th sub-token-tree. This only makes sense for delimited trees and sequences. - crate fn get_tt(&self, index: usize) -> TokenTree { + fn get_tt(&self, index: usize) -> TokenTree { match (self, index) { (&TokenTree::Delimited(_, ref delimed), _) if delimed.delim == token::NoDelim => { delimed.tts[index].clone() @@ -151,7 +151,7 @@ impl TokenTree { } /// Retrieves the `TokenTree`'s span. - crate fn span(&self) -> Span { + fn span(&self) -> Span { match *self { TokenTree::Token(Token { span, .. }) | TokenTree::MetaVar(span, _) @@ -160,7 +160,7 @@ impl TokenTree { } } - crate fn token(kind: TokenKind, span: Span) -> TokenTree { + fn token(kind: TokenKind, span: Span) -> TokenTree { TokenTree::Token(Token::new(kind, span)) } } diff --git a/src/libsyntax/ext/mbe/macro_check.rs b/src/libsyntax/ext/mbe/macro_check.rs index a3750e5c46945..97074f5cbe46c 100644 --- a/src/libsyntax/ext/mbe/macro_check.rs +++ b/src/libsyntax/ext/mbe/macro_check.rs @@ -196,7 +196,7 @@ struct MacroState<'a> { /// - `node_id` is used to emit lints /// - `span` is used when no spans are available /// - `lhses` and `rhses` should have the same length and represent the macro definition -crate fn check_meta_variables( +pub(super) fn check_meta_variables( sess: &ParseSess, node_id: NodeId, span: Span, diff --git a/src/libsyntax/ext/mbe/macro_parser.rs b/src/libsyntax/ext/mbe/macro_parser.rs index 35fc6cf21b80e..b51384d3b15e1 100644 --- a/src/libsyntax/ext/mbe/macro_parser.rs +++ b/src/libsyntax/ext/mbe/macro_parser.rs @@ -282,7 +282,7 @@ crate enum ParseResult { crate type NamedParseResult = ParseResult>; /// Count how many metavars are named in the given matcher `ms`. -crate fn count_names(ms: &[TokenTree]) -> usize { +pub(super) fn count_names(ms: &[TokenTree]) -> usize { ms.iter().fold(0, |count, elt| { count + match *elt { TokenTree::Sequence(_, ref seq) => seq.num_captures, @@ -648,7 +648,7 @@ fn inner_parse_loop<'root, 'tt>( /// - `directory`: Information about the file locations (needed for the black-box parser) /// - `recurse_into_modules`: Whether or not to recurse into modules (needed for the black-box /// parser) -crate fn parse( +pub(super) fn parse( sess: &ParseSess, tts: TokenStream, ms: &[TokenTree], diff --git a/src/libsyntax/ext/mbe/quoted.rs b/src/libsyntax/ext/mbe/quoted.rs index 82289d7449d36..3952e29a5f0d1 100644 --- a/src/libsyntax/ext/mbe/quoted.rs +++ b/src/libsyntax/ext/mbe/quoted.rs @@ -35,7 +35,7 @@ use std::iter::Peekable; /// # Returns /// /// A collection of `self::TokenTree`. There may also be some errors emitted to `sess`. -crate fn parse( +pub(super) fn parse( input: tokenstream::TokenStream, expect_matchers: bool, sess: &ParseSess, From 4ea371e40bfff6254f66c9b35510be09de5db1e6 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Mon, 23 Sep 2019 11:57:07 +1000 Subject: [PATCH 32/55] Delete iter-order-by.md --- src/doc/unstable-book/src/iter-order-by.md | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 src/doc/unstable-book/src/iter-order-by.md diff --git a/src/doc/unstable-book/src/iter-order-by.md b/src/doc/unstable-book/src/iter-order-by.md deleted file mode 100644 index 1ed97872c881c..0000000000000 --- a/src/doc/unstable-book/src/iter-order-by.md +++ /dev/null @@ -1,9 +0,0 @@ -# `iter_order_by` - -The tracking issue for this feature is: [#64295] - -[#64295]: https://github.com/rust-lang/rust/issues/64295 - ------------------------- - -Add `cmp_by`, `partial_cmp_by` and `eq_by` methods to `Iterator` in the same vein as `max_by` and `min_by`. From 0423c2a7a35ce17b44b4c93c227177fc0fcd7217 Mon Sep 17 00:00:00 2001 From: Shotaro Yamada Date: Thu, 19 Sep 2019 22:24:06 +0900 Subject: [PATCH 33/55] Remove unused dependencies --- Cargo.lock | 13 ------------- src/librustc_ast_borrowck/Cargo.toml | 2 -- src/librustc_codegen_ssa/Cargo.toml | 1 - src/librustc_codegen_utils/Cargo.toml | 1 - src/librustc_mir/Cargo.toml | 1 - src/librustc_plugin/Cargo.toml | 1 - src/librustc_resolve/Cargo.toml | 1 - src/librustc_save_analysis/Cargo.toml | 1 - src/librustc_traits/Cargo.toml | 2 -- src/libstd/Cargo.toml | 3 --- src/libsyntax/Cargo.toml | 1 - src/libsyntax_ext/Cargo.toml | 1 - 12 files changed, 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fa749e5e3aebe..5b446c517c915 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3325,8 +3325,6 @@ dependencies = [ "log", "rustc", "rustc_data_structures", - "rustc_errors", - "syntax", "syntax_pos", ] @@ -3348,7 +3346,6 @@ dependencies = [ "log", "memmap", "num_cpus", - "parking_lot 0.9.0", "rustc", "rustc_apfloat", "rustc_codegen_utils", @@ -3367,7 +3364,6 @@ dependencies = [ name = "rustc_codegen_utils" version = "0.0.0" dependencies = [ - "flate2", "log", "punycode", "rustc", @@ -3562,7 +3558,6 @@ name = "rustc_mir" version = "0.0.0" dependencies = [ "arena", - "byteorder", "either", "graphviz", "log", @@ -3615,7 +3610,6 @@ name = "rustc_plugin_impl" version = "0.0.0" dependencies = [ "rustc", - "rustc_errors", "rustc_metadata", "syntax", "syntax_pos", @@ -3639,7 +3633,6 @@ version = "0.0.0" dependencies = [ "arena", "bitflags", - "indexmap", "log", "rustc", "rustc_data_structures", @@ -3661,7 +3654,6 @@ dependencies = [ "rustc_codegen_utils", "rustc_data_structures", "rustc_target", - "rustc_typeck", "serde_json", "syntax", "syntax_pos", @@ -3692,9 +3684,7 @@ checksum = "b725dadae9fabc488df69a287f5a99c5eaf5d10853842a8a3dfac52476f544ee" name = "rustc_traits" version = "0.0.0" dependencies = [ - "bitflags", "chalk-engine", - "graphviz", "log", "rustc", "rustc_data_structures", @@ -4057,7 +4047,6 @@ version = "0.0.0" dependencies = [ "alloc", "backtrace", - "cc", "cfg-if", "compiler_builtins", "core", @@ -4242,7 +4231,6 @@ dependencies = [ "rustc_data_structures", "rustc_errors", "rustc_lexer", - "rustc_macros", "rustc_target", "scoped-tls", "serialize", @@ -4258,7 +4246,6 @@ dependencies = [ "log", "rustc_data_structures", "rustc_errors", - "rustc_lexer", "rustc_target", "smallvec", "syntax", diff --git a/src/librustc_ast_borrowck/Cargo.toml b/src/librustc_ast_borrowck/Cargo.toml index 024b2640e1e8e..40c4c1fc3fee6 100644 --- a/src/librustc_ast_borrowck/Cargo.toml +++ b/src/librustc_ast_borrowck/Cargo.toml @@ -12,11 +12,9 @@ doctest = false [dependencies] log = "0.4" -syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } # for "clarity", rename the graphviz crate to dot; graphviz within `borrowck` # refers to the borrowck-specific graphviz adapter traits. dot = { path = "../libgraphviz", package = "graphviz" } rustc = { path = "../librustc" } -errors = { path = "../librustc_errors", package = "rustc_errors" } rustc_data_structures = { path = "../librustc_data_structures" } diff --git a/src/librustc_codegen_ssa/Cargo.toml b/src/librustc_codegen_ssa/Cargo.toml index bc028d6624279..2e3666e609657 100644 --- a/src/librustc_codegen_ssa/Cargo.toml +++ b/src/librustc_codegen_ssa/Cargo.toml @@ -17,7 +17,6 @@ memmap = "0.6" log = "0.4.5" libc = "0.2.44" jobserver = "0.1.11" -parking_lot = "0.9" tempfile = "3.1" rustc_serialize = { path = "../libserialize", package = "serialize" } diff --git a/src/librustc_codegen_utils/Cargo.toml b/src/librustc_codegen_utils/Cargo.toml index 89b50c5daccae..c8c219d039a73 100644 --- a/src/librustc_codegen_utils/Cargo.toml +++ b/src/librustc_codegen_utils/Cargo.toml @@ -10,7 +10,6 @@ path = "lib.rs" test = false [dependencies] -flate2 = "1.0" log = "0.4" punycode = "0.4.0" rustc-demangle = "0.1.16" diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml index 0691390bead4b..f296753a0304c 100644 --- a/src/librustc_mir/Cargo.toml +++ b/src/librustc_mir/Cargo.toml @@ -24,6 +24,5 @@ rustc_lexer = { path = "../librustc_lexer" } rustc_serialize = { path = "../libserialize", package = "serialize" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -byteorder = { version = "1.3" } rustc_apfloat = { path = "../librustc_apfloat" } smallvec = { version = "0.6.7", features = ["union", "may_dangle"] } diff --git a/src/librustc_plugin/Cargo.toml b/src/librustc_plugin/Cargo.toml index 84a743ed1ad7d..3f11430dc82cb 100644 --- a/src/librustc_plugin/Cargo.toml +++ b/src/librustc_plugin/Cargo.toml @@ -15,4 +15,3 @@ rustc = { path = "../librustc" } rustc_metadata = { path = "../librustc_metadata" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -rustc_errors = { path = "../librustc_errors" } diff --git a/src/librustc_resolve/Cargo.toml b/src/librustc_resolve/Cargo.toml index 548f982fe3bf0..936e72ef2c571 100644 --- a/src/librustc_resolve/Cargo.toml +++ b/src/librustc_resolve/Cargo.toml @@ -12,7 +12,6 @@ doctest = false [dependencies] bitflags = "1.0" -indexmap = "1" log = "0.4" syntax = { path = "../libsyntax" } rustc = { path = "../librustc" } diff --git a/src/librustc_save_analysis/Cargo.toml b/src/librustc_save_analysis/Cargo.toml index 88bb76d2aba3a..b89c83d630b7d 100644 --- a/src/librustc_save_analysis/Cargo.toml +++ b/src/librustc_save_analysis/Cargo.toml @@ -14,7 +14,6 @@ rustc = { path = "../librustc" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_codegen_utils = { path = "../librustc_codegen_utils" } rustc_target = { path = "../librustc_target" } -rustc_typeck = { path = "../librustc_typeck" } serde_json = "1" syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_traits/Cargo.toml b/src/librustc_traits/Cargo.toml index bb28ac839a544..b86a3a5e9639b 100644 --- a/src/librustc_traits/Cargo.toml +++ b/src/librustc_traits/Cargo.toml @@ -9,8 +9,6 @@ name = "rustc_traits" path = "lib.rs" [dependencies] -bitflags = "1.0" -graphviz = { path = "../libgraphviz" } log = { version = "0.4" } rustc = { path = "../librustc" } rustc_data_structures = { path = "../librustc_data_structures" } diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index af1d2402f88e7..ee4b367b5c5b9 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -53,9 +53,6 @@ fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] } [target.wasm32-wasi.dependencies] wasi = { version = "0.7.0", features = ['rustc-dep-of-std', 'alloc'] } -[build-dependencies] -cc = "1.0" - [features] default = ["std_detect_file_io", "std_detect_dlsym_getauxval"] diff --git a/src/libsyntax/Cargo.toml b/src/libsyntax/Cargo.toml index d4a9acc1569b4..196cf4d9dfae8 100644 --- a/src/libsyntax/Cargo.toml +++ b/src/libsyntax/Cargo.toml @@ -19,6 +19,5 @@ syntax_pos = { path = "../libsyntax_pos" } errors = { path = "../librustc_errors", package = "rustc_errors" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_lexer = { path = "../librustc_lexer" } -rustc_macros = { path = "../librustc_macros" } rustc_target = { path = "../librustc_target" } smallvec = { version = "0.6.7", features = ["union", "may_dangle"] } diff --git a/src/libsyntax_ext/Cargo.toml b/src/libsyntax_ext/Cargo.toml index 791ee94b4fa77..73310df305b32 100644 --- a/src/libsyntax_ext/Cargo.toml +++ b/src/libsyntax_ext/Cargo.toml @@ -18,4 +18,3 @@ rustc_target = { path = "../librustc_target" } smallvec = { version = "0.6.7", features = ["union", "may_dangle"] } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -rustc_lexer = { path = "../librustc_lexer" } From 5f58834fb85b6a49da05c90ff592ccff2496cefe Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 13 Sep 2019 14:21:40 -0400 Subject: [PATCH 34/55] Provide helper for synthesizing paths with resource suffix --- src/librustdoc/html/render.rs | 69 ++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 2623f8d227e14..4b281dc6a7b6d 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -212,6 +212,26 @@ crate struct SharedContext { playground: Option, } +impl Context { + fn path(&self, filename: &str) -> PathBuf { + // We use splitn vs Path::extension here because we might get a filename + // like `style.min.css` and we want to process that into + // `style-suffix.min.css`. Path::extension would just return `css` + // which would result in `style.min-suffix.css` which isn't what we + // want. + let mut iter = filename.splitn(2, '.'); + let base = iter.next().unwrap(); + let ext = iter.next().unwrap(); + let filename = format!( + "{}{}.{}", + base, + self.shared.resource_suffix, + ext, + ); + self.dst.join(&filename) + } +} + impl SharedContext { crate fn ensure_dir(&self, dst: &Path) -> Result<(), Error> { let mut dirs = self.created_dirs.borrow_mut(); @@ -530,13 +550,13 @@ fn write_shared( // Add all the static files. These may already exist, but we just // overwrite them anyway to make sure that they're fresh and up-to-date. - write_minify(&cx.shared.fs, cx.dst.join(&format!("rustdoc{}.css", cx.shared.resource_suffix)), + write_minify(&cx.shared.fs, cx.path("rustdoc.css"), static_files::RUSTDOC_CSS, options.enable_minification)?; - write_minify(&cx.shared.fs, cx.dst.join(&format!("settings{}.css", cx.shared.resource_suffix)), + write_minify(&cx.shared.fs, cx.path("settings.css"), static_files::SETTINGS_CSS, options.enable_minification)?; - write_minify(&cx.shared.fs, cx.dst.join(&format!("noscript{}.css", cx.shared.resource_suffix)), + write_minify(&cx.shared.fs, cx.path("noscript.css"), static_files::NOSCRIPT_CSS, options.enable_minification)?; @@ -548,34 +568,25 @@ fn write_shared( let content = try_err!(fs::read(&entry), &entry); let theme = try_none!(try_none!(entry.file_stem(), &entry).to_str(), &entry); let extension = try_none!(try_none!(entry.extension(), &entry).to_str(), &entry); - cx.shared.fs.write( - cx.dst.join(format!("{}{}.{}", theme, cx.shared.resource_suffix, extension)), - content.as_slice())?; + cx.shared.fs.write(cx.path(&format!("{}.{}", theme, extension)), content.as_slice())?; themes.insert(theme.to_owned()); } let write = |p, c| { cx.shared.fs.write(p, c) }; if (*cx.shared).layout.logo.is_empty() { - write(cx.dst.join(&format!("rust-logo{}.png", cx.shared.resource_suffix)), - static_files::RUST_LOGO)?; + write(cx.path("rust-log.png"), static_files::RUST_LOGO)?; } if (*cx.shared).layout.favicon.is_empty() { - write(cx.dst.join(&format!("favicon{}.ico", cx.shared.resource_suffix)), - static_files::RUST_FAVICON)?; - } - write(cx.dst.join(&format!("brush{}.svg", cx.shared.resource_suffix)), - static_files::BRUSH_SVG)?; - write(cx.dst.join(&format!("wheel{}.svg", cx.shared.resource_suffix)), - static_files::WHEEL_SVG)?; - write(cx.dst.join(&format!("down-arrow{}.svg", cx.shared.resource_suffix)), - static_files::DOWN_ARROW_SVG)?; - write_minify(&cx.shared.fs, cx.dst.join(&format!("light{}.css", cx.shared.resource_suffix)), - static_files::themes::LIGHT, - options.enable_minification)?; + write(cx.path("favicon.ico"), static_files::RUST_FAVICON)?; + } + write(cx.path("brush.svg"), static_files::BRUSH_SVG)?; + write(cx.path("wheel.svg"), static_files::WHEEL_SVG)?; + write(cx.path("down-arrow.svg"), static_files::DOWN_ARROW_SVG)?; + write_minify(&cx.shared.fs, + cx.path("light.css"), static_files::themes::LIGHT, options.enable_minification)?; themes.insert("light".to_owned()); - write_minify(&cx.shared.fs, cx.dst.join(&format!("dark{}.css", cx.shared.resource_suffix)), - static_files::themes::DARK, - options.enable_minification)?; + write_minify(&cx.shared.fs, + cx.path("dark.css"), static_files::themes::DARK, options.enable_minification)?; themes.insert("dark".to_owned()); let mut themes: Vec<&String> = themes.iter().collect(); @@ -638,16 +649,16 @@ themePicker.onblur = handleThemeButtonsBlur; theme_js.as_bytes() )?; - write_minify(&cx.shared.fs, cx.dst.join(&format!("main{}.js", cx.shared.resource_suffix)), + write_minify(&cx.shared.fs, cx.path("main.js"), static_files::MAIN_JS, options.enable_minification)?; - write_minify(&cx.shared.fs, cx.dst.join(&format!("settings{}.js", cx.shared.resource_suffix)), + write_minify(&cx.shared.fs, cx.path("settings.js"), static_files::SETTINGS_JS, options.enable_minification)?; if cx.shared.include_sources { write_minify( &cx.shared.fs, - cx.dst.join(&format!("source-script{}.js", cx.shared.resource_suffix)), + cx.path("source-script.js"), static_files::sidebar::SOURCE_SCRIPT, options.enable_minification)?; } @@ -655,7 +666,7 @@ themePicker.onblur = handleThemeButtonsBlur; { write_minify( &cx.shared.fs, - cx.dst.join(&format!("storage{}.js", cx.shared.resource_suffix)), + cx.path("storage.js"), &format!("var resourcesSuffix = \"{}\";{}", cx.shared.resource_suffix, static_files::STORAGE_JS), @@ -663,7 +674,7 @@ themePicker.onblur = handleThemeButtonsBlur; } if let Some(ref css) = cx.shared.layout.css_file_extension { - let out = cx.dst.join(&format!("theme{}.css", cx.shared.resource_suffix)); + let out = cx.path("theme.css"); let buffer = try_err!(fs::read_to_string(css), css); if !options.enable_minification { cx.shared.fs.write(&out, &buffer)?; @@ -671,7 +682,7 @@ themePicker.onblur = handleThemeButtonsBlur; write_minify(&cx.shared.fs, out, &buffer, options.enable_minification)?; } } - write_minify(&cx.shared.fs, cx.dst.join(&format!("normalize{}.css", cx.shared.resource_suffix)), + write_minify(&cx.shared.fs, cx.path("normalize.css"), static_files::NORMALIZE_CSS, options.enable_minification)?; write(cx.dst.join("FiraSans-Regular.woff"), From 61f16920b3783e91cc853c720d152be6dc94e2da Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 13 Sep 2019 14:25:56 -0400 Subject: [PATCH 35/55] Remove needless Rc> --- src/librustdoc/html/render.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 4b281dc6a7b6d..e4ace7a0211b7 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -3771,12 +3771,12 @@ fn sidebar_assoc_items(it: &clean::Item) -> String { let mut used_links = FxHashSet::default(); { - let used_links_bor = Rc::new(RefCell::new(&mut used_links)); + let used_links_bor = &mut used_links; let mut ret = v.iter() .filter(|i| i.inner_impl().trait_.is_none()) .flat_map(move |i| get_methods(i.inner_impl(), false, - &mut used_links_bor.borrow_mut(), false)) + used_links_bor, false)) .collect::>(); // We want links' order to be reproducible so we don't use unstable sort. ret.sort(); From 583a81dc5e19bcc21092c8f16fd7185c357bd077 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 13 Sep 2019 14:32:59 -0400 Subject: [PATCH 36/55] Remove pointless or --- src/librustdoc/html/render.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index e4ace7a0211b7..e3f227e0cf4d6 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -3405,7 +3405,7 @@ fn render_impl(w: &mut Buffer, cx: &Context, i: &Impl, link: AssocItemLink<'_>, let item_type = item.type_(); let name = item.name.as_ref().unwrap(); - let render_method_item: bool = match render_mode { + let render_method_item = match render_mode { RenderMode::Normal => true, RenderMode::ForDeref { mut_: deref_mut_ } => should_render_item(&item, deref_mut_), }; @@ -3474,7 +3474,7 @@ fn render_impl(w: &mut Buffer, cx: &Context, i: &Impl, link: AssocItemLink<'_>, _ => panic!("can't make docs for trait item with name {:?}", item.name) } - if render_method_item || render_mode == RenderMode::Normal { + if render_method_item { if !is_default_item { if let Some(t) = trait_ { // The trait item may have been stripped so we might not From 53acfc3f8a52f9d26ce3ea3cdaea00345b1e9973 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 13 Sep 2019 14:59:08 -0400 Subject: [PATCH 37/55] Utilize shared error codes rather than re-querying env --- src/librustdoc/html/render.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index e3f227e0cf4d6..e66224c0b5e00 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2123,7 +2123,7 @@ fn stability_tags(item: &clean::Item) -> String { /// documentation. fn short_stability(item: &clean::Item, cx: &Context) -> Vec { let mut stability = vec![]; - let error_codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()); + let error_codes = cx.shared.codes; if let Some(Deprecation { note, since }) = &item.deprecation() { // We display deprecation messages for #[deprecated] and #[rustc_deprecated] From cac7e5faedc0f7adb41c8cc81ee7be56d8217fd1 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 13 Sep 2019 15:22:00 -0400 Subject: [PATCH 38/55] Remove unused arguments --- src/librustdoc/html/render.rs | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index e66224c0b5e00..301dddbbfb9b2 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1702,12 +1702,12 @@ fn print_item(cx: &Context, item: &clean::Item, buf: &mut Buffer) { clean::TypedefItem(ref t, _) => item_typedef(buf, cx, item, t), clean::MacroItem(ref m) => item_macro(buf, cx, item, m), clean::ProcMacroItem(ref m) => item_proc_macro(buf, cx, item, m), - clean::PrimitiveItem(ref p) => item_primitive(buf, cx, item, p), + clean::PrimitiveItem(_) => item_primitive(buf, cx, item), clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) => item_static(buf, cx, item, i), clean::ConstantItem(ref c) => item_constant(buf, cx, item, c), clean::ForeignTypeItem => item_foreign_type(buf, cx, item), - clean::KeywordItem(ref k) => item_keyword(buf, cx, item, k), + clean::KeywordItem(_) => item_keyword(buf, cx, item), clean::OpaqueTyItem(ref e, _) => item_opaque_ty(buf, cx, item, e), clean::TraitAliasItem(ref ta) => item_trait_alias(buf, cx, item, ta), _ => { @@ -3665,11 +3665,11 @@ fn print_sidebar(cx: &Context, it: &clean::Item, buffer: &mut Buffer) { match it.inner { clean::StructItem(ref s) => sidebar_struct(buffer, it, s), clean::TraitItem(ref t) => sidebar_trait(buffer, it, t), - clean::PrimitiveItem(ref p) => sidebar_primitive(buffer, it, p), + clean::PrimitiveItem(_) => sidebar_primitive(buffer, it), clean::UnionItem(ref u) => sidebar_union(buffer, it, u), clean::EnumItem(ref e) => sidebar_enum(buffer, it, e), - clean::TypedefItem(ref t, _) => sidebar_typedef(buffer, it, t), - clean::ModuleItem(ref m) => sidebar_module(buffer, it, &m.items), + clean::TypedefItem(_, _) => sidebar_typedef(buffer, it), + clean::ModuleItem(ref m) => sidebar_module(buffer, &m.items), clean::ForeignTypeItem => sidebar_foreign_type(buffer, it), _ => (), } @@ -4038,7 +4038,7 @@ fn sidebar_trait(buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) { write!(buf, "
    {}
    ", sidebar) } -fn sidebar_primitive(buf: &mut Buffer, it: &clean::Item, _p: &clean::PrimitiveType) { +fn sidebar_primitive(buf: &mut Buffer, it: &clean::Item) { let sidebar = sidebar_assoc_items(it); if !sidebar.is_empty() { @@ -4046,7 +4046,7 @@ fn sidebar_primitive(buf: &mut Buffer, it: &clean::Item, _p: &clean::PrimitiveTy } } -fn sidebar_typedef(buf: &mut Buffer, it: &clean::Item, _t: &clean::Typedef) { +fn sidebar_typedef(buf: &mut Buffer, it: &clean::Item) { let sidebar = sidebar_assoc_items(it); if !sidebar.is_empty() { @@ -4138,7 +4138,7 @@ fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) { } } -fn sidebar_module(buf: &mut Buffer, _it: &clean::Item, items: &[clean::Item]) { +fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) { let mut sidebar = String::new(); if items.iter().any(|it| it.type_() == ItemType::ExternCrate || @@ -4216,16 +4216,12 @@ fn item_proc_macro(w: &mut Buffer, cx: &Context, it: &clean::Item, m: &clean::Pr document(w, cx, it) } -fn item_primitive(w: &mut Buffer, cx: &Context, - it: &clean::Item, - _p: &clean::PrimitiveType) { +fn item_primitive(w: &mut Buffer, cx: &Context, it: &clean::Item) { document(w, cx, it); render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All) } -fn item_keyword(w: &mut Buffer, cx: &Context, - it: &clean::Item, - _p: &str) { +fn item_keyword(w: &mut Buffer, cx: &Context, it: &clean::Item) { document(w, cx, it) } From 059163fad796e3ecf04c29f423b9cf985717f025 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 13 Sep 2019 16:00:36 -0400 Subject: [PATCH 39/55] Remove needless `mut` in paths --- src/librustdoc/html/render/cache.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index e9f0955c54126..65dd119c27cb7 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -548,7 +548,7 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { let Cache { ref mut search_index, ref orphan_impl_items, - ref mut paths, .. } = *cache; + ref paths, .. } = *cache; // Attach all orphan items to the type's definition if the type // has since been learned. From ae8b3e8fc6e95a0f68fc49338f394d670e233883 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 23 Sep 2019 04:45:21 +0200 Subject: [PATCH 40/55] Introduce a diagnostic stashing API. --- src/librustc/session/mod.rs | 1 + src/librustc_driver/lib.rs | 3 +- src/librustc_errors/diagnostic_builder.rs | 41 +++++++---- src/librustc_errors/lib.rs | 84 +++++++++++++++++++---- 4 files changed, 102 insertions(+), 27 deletions(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index a24fed8f21c5a..49342d95fdb03 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -321,6 +321,7 @@ impl Session { } pub fn compile_status(&self) -> Result<(), ErrorReported> { if self.has_errors() { + self.diagnostic().emit_stashed_diagnostics(); Err(ErrorReported) } else { Ok(()) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index f99e65b4494a7..4a8681367410e 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -296,7 +296,6 @@ pub fn run_compiler( ); Ok(()) })?; - return sess.compile_status(); } else { let mut krate = compiler.parse()?.take(); pretty::visit_crate(sess, &mut krate, ppm); @@ -307,8 +306,8 @@ pub fn run_compiler( ppm, compiler.output_file().as_ref().map(|p| &**p), ); - return sess.compile_status(); } + return sess.compile_status(); } if callbacks.after_parsing(compiler) == Compilation::Stop { diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs index e85388bfea29c..cc60bf89c7eca 100644 --- a/src/librustc_errors/diagnostic_builder.rs +++ b/src/librustc_errors/diagnostic_builder.rs @@ -1,10 +1,6 @@ -use crate::Diagnostic; -use crate::DiagnosticId; -use crate::DiagnosticStyledString; -use crate::Applicability; +use crate::{Diagnostic, DiagnosticId, DiagnosticStyledString}; +use crate::{Applicability, Level, Handler, StashKey}; -use crate::Level; -use crate::Handler; use std::fmt::{self, Debug}; use std::ops::{Deref, DerefMut}; use std::thread::panicking; @@ -117,18 +113,30 @@ impl<'a> DiagnosticBuilder<'a> { } } - /// Buffers the diagnostic for later emission, unless handler - /// has disabled such buffering. - pub fn buffer(mut self, buffered_diagnostics: &mut Vec) { + /// Stashes diagnostic for possible later improvement in a different, + /// later stage of the compiler. The diagnostic can be accessed with + /// the provided `span` and `key` through `.steal_diagnostic` on `Handler`. + /// + /// As with `buffer`, this is unless the handler has disabled such buffering. + pub fn stash(self, span: Span, key: StashKey) { + if let Some((diag, handler)) = self.into_diagnostic() { + handler.stash_diagnostic(span, key, diag); + } + } + + /// Converts the builder to a `Diagnostic` for later emission, + /// unless handler has disabled such buffering. + pub fn into_diagnostic(mut self) -> Option<(Diagnostic, &'a Handler)> { if self.0.handler.flags.dont_buffer_diagnostics || self.0.handler.flags.treat_err_as_bug.is_some() { self.emit(); - return; + return None; } - // We need to use `ptr::read` because `DiagnosticBuilder` - // implements `Drop`. + let handler = self.0.handler; + + // We need to use `ptr::read` because `DiagnosticBuilder` implements `Drop`. let diagnostic; unsafe { diagnostic = std::ptr::read(&self.0.diagnostic); @@ -137,7 +145,14 @@ impl<'a> DiagnosticBuilder<'a> { // Logging here is useful to help track down where in logs an error was // actually emitted. debug!("buffer: diagnostic={:?}", diagnostic); - buffered_diagnostics.push(diagnostic); + + Some((diagnostic, handler)) + } + + /// Buffers the diagnostic for later emission, + /// unless handler has disabled such buffering. + pub fn buffer(self, buffered_diagnostics: &mut Vec) { + buffered_diagnostics.extend(self.into_diagnostic().map(|(diag, _)| diag)); } /// Convenience function for internal use, clients should use one of the diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 1fe5b71d7b1cf..40f63ae1eee33 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -17,7 +17,7 @@ use emitter::{Emitter, EmitterWriter}; use registry::Registry; use rustc_data_structures::sync::{self, Lrc, Lock}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::stable_hasher::StableHasher; use std::borrow::Cow; @@ -326,6 +326,18 @@ struct HandlerInner { /// this handler. These hashes is used to avoid emitting the same error /// twice. emitted_diagnostics: FxHashSet, + + /// Stashed diagnostics emitted in one stage of the compiler that may be + /// stolen by other stages (e.g. to improve them and add more information). + /// The stashed diagnostics count towards the total error count. + /// When `.abort_if_errors()` is called, these are also emitted. + stashed_diagnostics: FxIndexMap<(Span, StashKey), Diagnostic>, +} + +/// A key denoting where from a diagnostic was stashed. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub enum StashKey { + ItemNoType, } fn default_track_diagnostic(_: &Diagnostic) {} @@ -354,7 +366,9 @@ pub struct HandlerFlags { impl Drop for HandlerInner { fn drop(&mut self) { - if self.err_count == 0 { + self.emit_stashed_diagnostics(); + + if !self.has_errors() { let bugs = std::mem::replace(&mut self.delayed_span_bugs, Vec::new()); let has_bugs = !bugs.is_empty(); for bug in bugs { @@ -419,6 +433,7 @@ impl Handler { taught_diagnostics: Default::default(), emitted_diagnostic_codes: Default::default(), emitted_diagnostics: Default::default(), + stashed_diagnostics: Default::default(), }), } } @@ -445,6 +460,31 @@ impl Handler { inner.emitted_diagnostics = Default::default(); inner.deduplicated_err_count = 0; inner.err_count = 0; + inner.stashed_diagnostics.clear(); + } + + /// Stash a given diagnostic with the given `Span` and `StashKey` as the key for later stealing. + /// If the diagnostic with this `(span, key)` already exists, this will result in an ICE. + pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) { + if let Some(old) = self.inner.borrow_mut().stashed_diagnostics.insert((span, key), diag) { + // We are removing a previously stashed diagnostic which should not happen. + // Create a builder and drop it on the floor to get an ICE. + drop(DiagnosticBuilder::new_diagnostic(self, old)); + } + } + + /// Steal a previously stashed diagnostic with the given `Span` and `StashKey` as the key. + pub fn steal_diagnostic(&self, span: Span, key: StashKey) -> Option> { + self.inner + .borrow_mut() + .stashed_diagnostics + .remove(&(span, key)) + .map(|diag| DiagnosticBuilder::new_diagnostic(self, diag)) + } + + /// Emit all stashed diagnostics. + pub fn emit_stashed_diagnostics(&self) { + self.inner.borrow_mut().emit_stashed_diagnostics(); } pub fn struct_dummy(&self) -> DiagnosticBuilder<'_> { @@ -617,11 +657,11 @@ impl Handler { } pub fn err_count(&self) -> usize { - self.inner.borrow().err_count + self.inner.borrow().err_count() } pub fn has_errors(&self) -> bool { - self.err_count() > 0 + self.inner.borrow().has_errors() } pub fn print_error_count(&self, registry: &Registry) { @@ -629,11 +669,11 @@ impl Handler { } pub fn abort_if_errors(&self) { - self.inner.borrow().abort_if_errors() + self.inner.borrow_mut().abort_if_errors() } pub fn abort_if_errors_and_should_abort(&self) { - self.inner.borrow().abort_if_errors_and_should_abort() + self.inner.borrow_mut().abort_if_errors_and_should_abort() } pub fn must_teach(&self, code: &DiagnosticId) -> bool { @@ -671,6 +711,12 @@ impl HandlerInner { self.emitter.emit_diagnostic(&db); } + /// Emit all stashed diagnostics. + fn emit_stashed_diagnostics(&mut self) { + let diags = self.stashed_diagnostics.drain(..).map(|x| x.1).collect::>(); + diags.iter().for_each(|diag| self.emit_diagnostic(diag)); + } + fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) { if diagnostic.cancelled() { return; @@ -713,10 +759,12 @@ impl HandlerInner { } fn treat_err_as_bug(&self) -> bool { - self.flags.treat_err_as_bug.map(|c| self.err_count >= c).unwrap_or(false) + self.flags.treat_err_as_bug.map(|c| self.err_count() >= c).unwrap_or(false) } fn print_error_count(&mut self, registry: &Registry) { + self.emit_stashed_diagnostics(); + let s = match self.deduplicated_err_count { 0 => return, 1 => "aborting due to previous error".to_string(), @@ -760,14 +808,26 @@ impl HandlerInner { } } - fn abort_if_errors_and_should_abort(&self) { - if self.err_count > 0 && !self.continue_after_error { + fn err_count(&self) -> usize { + self.err_count + self.stashed_diagnostics.len() + } + + fn has_errors(&self) -> bool { + self.err_count() > 0 + } + + fn abort_if_errors_and_should_abort(&mut self) { + self.emit_stashed_diagnostics(); + + if self.has_errors() && !self.continue_after_error { FatalError.raise(); } } - fn abort_if_errors(&self) { - if self.err_count > 0 { + fn abort_if_errors(&mut self) { + self.emit_stashed_diagnostics(); + + if self.has_errors() { FatalError.raise(); } } @@ -826,7 +886,7 @@ impl HandlerInner { fn panic_if_treat_err_as_bug(&self) { if self.treat_err_as_bug() { - let s = match (self.err_count, self.flags.treat_err_as_bug.unwrap_or(0)) { + let s = match (self.err_count(), self.flags.treat_err_as_bug.unwrap_or(0)) { (0, _) => return, (1, 1) => "aborting due to `-Z treat-err-as-bug=1`".to_string(), (1, _) => return, From 62d85849d0a9a828dc58a1820469daf80a2b5b52 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 23 Sep 2019 04:48:22 +0200 Subject: [PATCH 41/55] Add parser recovery for `const $ident = $expr;`. Then use the diagnostics-stealing API to stash parser errors and enrich them with type information in typeck. --- src/librustc_typeck/collect.rs | 49 ++++++++++++++------ src/libsyntax/parse/parser/item.rs | 47 +++++++++++++++++-- src/test/ui/suggestions/const-no-type.rs | 46 ++++++++++++++++++ src/test/ui/suggestions/const-no-type.stderr | 38 +++++++++++++++ 4 files changed, 164 insertions(+), 16 deletions(-) create mode 100644 src/test/ui/suggestions/const-no-type.rs create mode 100644 src/test/ui/suggestions/const-no-type.stderr diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index d2e9203779cc8..e6e0cb88fbd23 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -46,7 +46,7 @@ use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc::hir::GenericParamKind; use rustc::hir::{self, CodegenFnAttrFlags, CodegenFnAttrs, Unsafety}; -use errors::{Applicability, DiagnosticId}; +use errors::{Applicability, DiagnosticId, StashKey}; struct OnlySelfBounds(bool); @@ -1149,18 +1149,41 @@ fn infer_placeholder_type( def_id: DefId, body_id: hir::BodyId, span: Span, + item_ident: Ident, ) -> Ty<'_> { let ty = tcx.typeck_tables_of(def_id).node_type(body_id.hir_id); - let mut diag = bad_placeholder_type(tcx, span); - if ty != tcx.types.err { - diag.span_suggestion( - span, - "replace `_` with the correct type", - ty.to_string(), - Applicability::MaybeIncorrect, - ); + + // If this came from a free `const` or `static mut?` item, + // then the user may have written e.g. `const A = 42;`. + // In this case, the parser has stashed a diagnostic for + // us to improve in typeck so we do that now. + match tcx.sess.diagnostic().steal_diagnostic(span, StashKey::ItemNoType) { + Some(mut err) => { + // The parser provided a sub-optimal `HasPlaceholders` suggestion for the type. + // We are typeck and have the real type, so remove that and suggest the actual type. + err.suggestions.clear(); + err.span_suggestion( + span, + "provide a type for the item", + format!("{}: {}", item_ident, ty), + Applicability::MachineApplicable, + ) + .emit(); + } + None => { + let mut diag = bad_placeholder_type(tcx, span); + if ty != tcx.types.err { + diag.span_suggestion( + span, + "replace `_` with the correct type", + ty.to_string(), + Applicability::MaybeIncorrect, + ); + } + diag.emit(); + } } - diag.emit(); + ty } @@ -1192,7 +1215,7 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option { body_id.and_then(|body_id| { if let hir::TyKind::Infer = ty.node { - Some(infer_placeholder_type(tcx, def_id, body_id, ty.span)) + Some(infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident)) } else { None } @@ -1214,7 +1237,7 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option { if let hir::TyKind::Infer = ty.node { - infer_placeholder_type(tcx, def_id, body_id, ty.span) + infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident) } else { icx.to_ty(ty) } @@ -1246,7 +1269,7 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option { if let hir::TyKind::Infer = ty.node { - infer_placeholder_type(tcx, def_id, body_id, ty.span) + infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident) } else { icx.to_ty(ty) } diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index cf196645e4f7b..0d073f0cc97b1 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -24,7 +24,7 @@ use crate::symbol::{kw, sym}; use std::mem; use log::debug; use rustc_target::spec::abi::Abi; -use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; +use errors::{Applicability, DiagnosticBuilder, DiagnosticId, StashKey}; /// Whether the type alias or associated type is a concrete type or an opaque type. #[derive(Debug)] @@ -1477,10 +1477,23 @@ impl<'a> Parser<'a> { } } + /// Parse `["const" | ("static" "mut"?)] $ident ":" $ty = $expr` with + /// `["const" | ("static" "mut"?)]` already parsed and stored in `m`. + /// + /// When `m` is `"const"`, `$ident` may also be `"_"`. fn parse_item_const(&mut self, m: Option) -> PResult<'a, ItemInfo> { let id = if m.is_none() { self.parse_ident_or_underscore() } else { self.parse_ident() }?; - self.expect(&token::Colon)?; - let ty = self.parse_ty()?; + + // Parse the type of a `const` or `static mut?` item. + // That is, the `":" $ty` fragment. + let ty = if self.token == token::Eq { + self.recover_missing_const_type(id, m) + } else { + // Not `=` so expect `":"" $ty` as usual. + self.expect(&token::Colon)?; + self.parse_ty()? + }; + self.expect(&token::Eq)?; let e = self.parse_expr()?; self.expect(&token::Semi)?; @@ -1491,6 +1504,34 @@ impl<'a> Parser<'a> { Ok((id, item, None)) } + /// We were supposed to parse `:` but instead, we're already at `=`. + /// This means that the type is missing. + fn recover_missing_const_type(&mut self, id: Ident, m: Option) -> P { + // Construct the error and stash it away with the hope + // that typeck will later enrich the error with a type. + let kind = match m { + Some(Mutability::Mutable) => "static mut", + Some(Mutability::Immutable) => "static", + None => "const", + }; + let mut err = self.struct_span_err(id.span, &format!("missing type for `{}` item", kind)); + err.span_suggestion( + id.span, + "provide a type for the item", + format!("{}: ", id), + Applicability::HasPlaceholders, + ); + err.stash(id.span, StashKey::ItemNoType); + + // The user intended that the type be inferred, + // so treat this as if the user wrote e.g. `const A: _ = expr;`. + P(Ty { + node: TyKind::Infer, + span: id.span, + id: ast::DUMMY_NODE_ID, + }) + } + /// Parses `type Foo = Bar;` or returns `None` /// without modifying the parser state. fn eat_type(&mut self) -> Option> { diff --git a/src/test/ui/suggestions/const-no-type.rs b/src/test/ui/suggestions/const-no-type.rs new file mode 100644 index 0000000000000..99200a965dd21 --- /dev/null +++ b/src/test/ui/suggestions/const-no-type.rs @@ -0,0 +1,46 @@ +// In the cases below, the type is missing from the `const` and `static` items. +// +// Here, we test that we: +// +// a) Perform parser recovery. +// +// b) Emit a diagnostic with the actual inferred type to RHS of `=` as the suggestion. + +fn main() {} + +// These will not reach typeck: + +#[cfg(FALSE)] +const C2 = 42; +//~^ ERROR missing type for `const` item +//~| HELP provide a type for the item +//~| SUGGESTION C2: + +#[cfg(FALSE)] +static S2 = "abc"; +//~^ ERROR missing type for `static` item +//~| HELP provide a type for the item +//~| SUGGESTION S2: + +#[cfg(FALSE)] +static mut SM2 = "abc"; +//~^ ERROR missing type for `static mut` item +//~| HELP provide a type for the item +//~| SUGGESTION SM2: + +// These will, so the diagnostics should be stolen by typeck: + +const C = 42; +//~^ ERROR missing type for `const` item +//~| HELP provide a type for the item +//~| SUGGESTION C: i32 + +static S = Vec::::new(); +//~^ ERROR missing type for `static` item +//~| HELP provide a type for the item +//~| SUGGESTION S: std::vec::Vec + +static mut SM = "abc"; +//~^ ERROR missing type for `static mut` item +//~| HELP provide a type for the item +//~| SUGGESTION &'static str diff --git a/src/test/ui/suggestions/const-no-type.stderr b/src/test/ui/suggestions/const-no-type.stderr new file mode 100644 index 0000000000000..c4f17109dc5c7 --- /dev/null +++ b/src/test/ui/suggestions/const-no-type.stderr @@ -0,0 +1,38 @@ +error: missing type for `const` item + --> $DIR/const-no-type.rs:33:7 + | +LL | const C = 42; + | ^ help: provide a type for the item: `C: i32` + +error: missing type for `static` item + --> $DIR/const-no-type.rs:38:8 + | +LL | static S = Vec::::new(); + | ^ help: provide a type for the item: `S: std::vec::Vec` + +error: missing type for `static mut` item + --> $DIR/const-no-type.rs:43:12 + | +LL | static mut SM = "abc"; + | ^^ help: provide a type for the item: `SM: &'static str` + +error: missing type for `const` item + --> $DIR/const-no-type.rs:14:7 + | +LL | const C2 = 42; + | ^^ help: provide a type for the item: `C2: ` + +error: missing type for `static` item + --> $DIR/const-no-type.rs:20:8 + | +LL | static S2 = "abc"; + | ^^ help: provide a type for the item: `S2: ` + +error: missing type for `static mut` item + --> $DIR/const-no-type.rs:26:12 + | +LL | static mut SM2 = "abc"; + | ^^^ help: provide a type for the item: `SM2: ` + +error: aborting due to 6 previous errors + From 62fc4d36dfeedbf0795f36a8d08c39e0f4e41632 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 23 Sep 2019 19:29:02 +0200 Subject: [PATCH 42/55] stash_diagnostic: ICE in a different way --- src/librustc_errors/lib.rs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 40f63ae1eee33..cdaa528e8e497 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -466,10 +466,15 @@ impl Handler { /// Stash a given diagnostic with the given `Span` and `StashKey` as the key for later stealing. /// If the diagnostic with this `(span, key)` already exists, this will result in an ICE. pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) { - if let Some(old) = self.inner.borrow_mut().stashed_diagnostics.insert((span, key), diag) { + let mut inner = self.inner.borrow_mut(); + if let Some(mut old_diag) = inner.stashed_diagnostics.insert((span, key), diag) { // We are removing a previously stashed diagnostic which should not happen. - // Create a builder and drop it on the floor to get an ICE. - drop(DiagnosticBuilder::new_diagnostic(self, old)); + old_diag.level = Bug; + old_diag.note(&format!( + "{}:{}: already existing stashed diagnostic with (span = {:?}, key = {:?})", + file!(), line!(), span, key + )); + inner.emit_explicit_bug(&old_diag); } } @@ -676,6 +681,11 @@ impl Handler { self.inner.borrow_mut().abort_if_errors_and_should_abort() } + /// `true` if we haven't taught a diagnostic with this code already. + /// The caller must then teach the user about such a diagnostic. + /// + /// Used to suppress emitting the same error multiple times with extended explanation when + /// calling `-Zteach`. pub fn must_teach(&self, code: &DiagnosticId) -> bool { self.inner.borrow_mut().must_teach(code) } @@ -698,11 +708,6 @@ impl Handler { } impl HandlerInner { - /// `true` if we haven't taught a diagnostic with this code already. - /// The caller must then teach the user about such a diagnostic. - /// - /// Used to suppress emitting the same error multiple times with extended explanation when - /// calling `-Zteach`. fn must_teach(&mut self, code: &DiagnosticId) -> bool { self.taught_diagnostics.insert(code.clone()) } @@ -833,7 +838,11 @@ impl HandlerInner { } fn span_bug>(&mut self, sp: S, msg: &str) -> ! { - self.emit_diagnostic(Diagnostic::new(Bug, msg).set_span(sp)); + self.emit_explicit_bug(Diagnostic::new(Bug, msg).set_span(sp)); + } + + fn emit_explicit_bug(&mut self, diag: &Diagnostic) -> ! { + self.emit_diagnostic(diag); self.abort_if_errors_and_should_abort(); panic!(ExplicitBug); } From 8acf95886b6d045a5069b3a0c2c5f0fc29b1dc35 Mon Sep 17 00:00:00 2001 From: Andrew Banchich Date: Mon, 23 Sep 2019 16:09:36 -0400 Subject: [PATCH 43/55] update test Use assert_eq and assert_ne over comparison operators. --- src/libcore/mem/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs index 87ec05a243d36..8767625d4ed37 100644 --- a/src/libcore/mem/mod.rs +++ b/src/libcore/mem/mod.rs @@ -818,9 +818,9 @@ impl fmt::Debug for Discriminant { /// /// enum Foo { A(&'static str), B(i32), C(i32) } /// -/// assert!(mem::discriminant(&Foo::A("bar")) == mem::discriminant(&Foo::A("baz"))); -/// assert!(mem::discriminant(&Foo::B(1)) == mem::discriminant(&Foo::B(2))); -/// assert!(mem::discriminant(&Foo::B(3)) != mem::discriminant(&Foo::C(3))); +/// assert_eq!(mem::discriminant(&Foo::A("bar")), mem::discriminant(&Foo::A("baz"))); +/// assert_eq!(mem::discriminant(&Foo::B(1)), mem::discriminant(&Foo::B(2))); +/// assert_ne!(mem::discriminant(&Foo::B(3)), mem::discriminant(&Foo::C(3))); /// ``` #[stable(feature = "discriminant_value", since = "1.21.0")] pub fn discriminant(v: &T) -> Discriminant { From f70665a84692a80a820fccdaed19df5dde94c533 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 23 Sep 2019 22:28:14 +0200 Subject: [PATCH 44/55] cleanup librustc_errors Handler code. --- src/librustc_errors/lib.rs | 301 +++++++++++++++------------ src/librustc_typeck/check/wfcheck.rs | 2 +- src/libsyntax/ext/base.rs | 4 - src/libsyntax/ext/expand.rs | 2 +- src/libsyntax_ext/format.rs | 4 +- 5 files changed, 170 insertions(+), 143 deletions(-) diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index cdaa528e8e497..c01dcd94c725e 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -302,6 +302,9 @@ pub struct Handler { inner: Lock, } +/// This inner struct exists to keep it all behind a single lock; +/// this is done to prevent possible deadlocks in a multi-threaded compiler, +/// as well as inconsistent state observation. struct HandlerInner { flags: HandlerFlags, /// The number of errors that have been emitted, including duplicates. @@ -382,52 +385,65 @@ impl Drop for HandlerInner { } impl Handler { - pub fn with_tty_emitter(color_config: ColorConfig, - can_emit_warnings: bool, - treat_err_as_bug: Option, - cm: Option>) - -> Handler { - Handler::with_tty_emitter_and_flags( + pub fn with_tty_emitter( + color_config: ColorConfig, + can_emit_warnings: bool, + treat_err_as_bug: Option, + cm: Option>, + ) -> Self { + Self::with_tty_emitter_and_flags( color_config, cm, HandlerFlags { can_emit_warnings, treat_err_as_bug, .. Default::default() - }) + }, + ) } - pub fn with_tty_emitter_and_flags(color_config: ColorConfig, - cm: Option>, - flags: HandlerFlags) - -> Handler { + pub fn with_tty_emitter_and_flags( + color_config: ColorConfig, + cm: Option>, + flags: HandlerFlags, + ) -> Self { let emitter = Box::new(EmitterWriter::stderr( - color_config, cm, false, false, None, flags.external_macro_backtrace)); - Handler::with_emitter_and_flags(emitter, flags) - } - - pub fn with_emitter(can_emit_warnings: bool, - treat_err_as_bug: Option, - e: Box) - -> Handler { + color_config, + cm, + false, + false, + None, + flags.external_macro_backtrace, + )); + Self::with_emitter_and_flags(emitter, flags) + } + + pub fn with_emitter( + can_emit_warnings: bool, + treat_err_as_bug: Option, + emitter: Box, + ) -> Self { Handler::with_emitter_and_flags( - e, + emitter, HandlerFlags { can_emit_warnings, treat_err_as_bug, .. Default::default() - }) + }, + ) } - pub fn with_emitter_and_flags(e: Box, flags: HandlerFlags) -> Handler - { - Handler { + pub fn with_emitter_and_flags( + emitter: Box, + flags: HandlerFlags + ) -> Self { + Self { flags, inner: Lock::new(HandlerInner { flags, err_count: 0, deduplicated_err_count: 0, - emitter: e, + emitter, continue_after_error: true, delayed_span_bugs: Vec::new(), taught_diagnostics: Default::default(), @@ -474,7 +490,8 @@ impl Handler { "{}:{}: already existing stashed diagnostic with (span = {:?}, key = {:?})", file!(), line!(), span, key )); - inner.emit_explicit_bug(&old_diag); + inner.emit_diag_at_span(old_diag, span); + panic!(ExplicitBug); } } @@ -492,34 +509,35 @@ impl Handler { self.inner.borrow_mut().emit_stashed_diagnostics(); } + /// Construct a dummy builder with `Level::Cancelled`. + /// + /// Using this will neither report anything to the user (e.g. a warning), + /// nor will compilation cancel as a result. pub fn struct_dummy(&self) -> DiagnosticBuilder<'_> { DiagnosticBuilder::new(self, Level::Cancelled, "") } - pub fn struct_span_warn>(&self, - sp: S, - msg: &str) - -> DiagnosticBuilder<'_> { - let mut result = DiagnosticBuilder::new(self, Level::Warning, msg); - result.set_span(sp); - if !self.flags.can_emit_warnings { - result.cancel(); - } + /// Construct a builder at the `Warning` level at the given `span` and with the `msg`. + pub fn struct_span_warn(&self, span: impl Into, msg: &str) -> DiagnosticBuilder<'_> { + let mut result = self.struct_warn(msg); + result.set_span(span); result } - pub fn struct_span_warn_with_code>(&self, - sp: S, - msg: &str, - code: DiagnosticId) - -> DiagnosticBuilder<'_> { - let mut result = DiagnosticBuilder::new(self, Level::Warning, msg); - result.set_span(sp); + + /// Construct a builder at the `Warning` level at the given `span` and with the `msg`. + /// Also include a code. + pub fn struct_span_warn_with_code( + &self, + span: impl Into, + msg: &str, + code: DiagnosticId, + ) -> DiagnosticBuilder<'_> { + let mut result = self.struct_span_warn(span, msg); result.code(code); - if !self.flags.can_emit_warnings { - result.cancel(); - } result } + + /// Construct a builder at the `Warning` level with the `msg`. pub fn struct_warn(&self, msg: &str) -> DiagnosticBuilder<'_> { let mut result = DiagnosticBuilder::new(self, Level::Warning, msg); if !self.flags.can_emit_warnings { @@ -527,136 +545,141 @@ impl Handler { } result } - pub fn struct_span_err>(&self, - sp: S, - msg: &str) - -> DiagnosticBuilder<'_> { - let mut result = DiagnosticBuilder::new(self, Level::Error, msg); - result.set_span(sp); + + /// Construct a builder at the `Error` level at the given `span` and with the `msg`. + pub fn struct_span_err(&self, span: impl Into, msg: &str) -> DiagnosticBuilder<'_> { + let mut result = self.struct_err(msg); + result.set_span(span); result } - pub fn struct_span_err_with_code>(&self, - sp: S, - msg: &str, - code: DiagnosticId) - -> DiagnosticBuilder<'_> { - let mut result = DiagnosticBuilder::new(self, Level::Error, msg); - result.set_span(sp); + + /// Construct a builder at the `Error` level at the given `span`, with the `msg`, and `code`. + pub fn struct_span_err_with_code( + &self, + span: impl Into, + msg: &str, + code: DiagnosticId, + ) -> DiagnosticBuilder<'_> { + let mut result = self.struct_span_err(span, msg); result.code(code); result } + + /// Construct a builder at the `Error` level with the `msg`. // FIXME: This method should be removed (every error should have an associated error code). pub fn struct_err(&self, msg: &str) -> DiagnosticBuilder<'_> { DiagnosticBuilder::new(self, Level::Error, msg) } - pub fn struct_err_with_code( - &self, - msg: &str, - code: DiagnosticId, - ) -> DiagnosticBuilder<'_> { - let mut result = DiagnosticBuilder::new(self, Level::Error, msg); + + /// Construct a builder at the `Error` level with the `msg` and the `code`. + pub fn struct_err_with_code(&self, msg: &str, code: DiagnosticId) -> DiagnosticBuilder<'_> { + let mut result = self.struct_err(msg); result.code(code); result } - pub fn struct_span_fatal>(&self, - sp: S, - msg: &str) - -> DiagnosticBuilder<'_> { - let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg); - result.set_span(sp); + + /// Construct a builder at the `Fatal` level at the given `span` and with the `msg`. + pub fn struct_span_fatal( + &self, + span: impl Into, + msg: &str, + ) -> DiagnosticBuilder<'_> { + let mut result = self.struct_fatal(msg); + result.set_span(span); result } - pub fn struct_span_fatal_with_code>(&self, - sp: S, - msg: &str, - code: DiagnosticId) - -> DiagnosticBuilder<'_> { - let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg); - result.set_span(sp); + + /// Construct a builder at the `Fatal` level at the given `span`, with the `msg`, and `code`. + pub fn struct_span_fatal_with_code( + &self, + span: impl Into, + msg: &str, + code: DiagnosticId, + ) -> DiagnosticBuilder<'_> { + let mut result = self.struct_span_fatal(span, msg); result.code(code); result } + + /// Construct a builder at the `Error` level with the `msg`. pub fn struct_fatal(&self, msg: &str) -> DiagnosticBuilder<'_> { DiagnosticBuilder::new(self, Level::Fatal, msg) } - pub fn span_fatal>(&self, sp: S, msg: &str) -> FatalError { - self.emit_diagnostic(Diagnostic::new(Fatal, msg).set_span(sp)); - self.abort_if_errors_and_should_abort(); + pub fn span_fatal(&self, span: impl Into, msg: &str) -> FatalError { + self.emit_diag_at_span(Diagnostic::new(Fatal, msg), span); FatalError } - pub fn span_fatal_with_code>(&self, - sp: S, - msg: &str, - code: DiagnosticId) - -> FatalError { - self.emit_diagnostic(Diagnostic::new_with_code(Fatal, Some(code), msg).set_span(sp)); - self.abort_if_errors_and_should_abort(); + + pub fn span_fatal_with_code( + &self, + span: impl Into, + msg: &str, + code: DiagnosticId, + ) -> FatalError { + self.emit_diag_at_span(Diagnostic::new_with_code(Fatal, Some(code), msg), span); FatalError } - pub fn span_err>(&self, sp: S, msg: &str) { - self.emit_diagnostic(Diagnostic::new(Error, msg).set_span(sp)); - self.abort_if_errors_and_should_abort(); - } - pub fn mut_span_err>(&self, - sp: S, - msg: &str) - -> DiagnosticBuilder<'_> { - let mut result = DiagnosticBuilder::new(self, Level::Error, msg); - result.set_span(sp); - result + + pub fn span_err(&self, span: impl Into, msg: &str) { + self.emit_diag_at_span(Diagnostic::new(Error, msg), span); } - pub fn span_err_with_code>(&self, sp: S, msg: &str, code: DiagnosticId) { - self.emit_diagnostic(Diagnostic::new_with_code(Error, Some(code), msg).set_span(sp)); - self.abort_if_errors_and_should_abort(); + + pub fn span_err_with_code(&self, span: impl Into, msg: &str, code: DiagnosticId) { + self.emit_diag_at_span(Diagnostic::new_with_code(Error, Some(code), msg), span); } - pub fn span_warn>(&self, sp: S, msg: &str) { - self.emit_diagnostic(Diagnostic::new(Warning, msg).set_span(sp)); - self.abort_if_errors_and_should_abort(); + + pub fn span_warn(&self, span: impl Into, msg: &str) { + self.emit_diag_at_span(Diagnostic::new(Warning, msg), span); } - pub fn span_warn_with_code>(&self, sp: S, msg: &str, code: DiagnosticId) { - self.emit_diagnostic(Diagnostic::new_with_code(Warning, Some(code), msg).set_span(sp)); - self.abort_if_errors_and_should_abort(); + + pub fn span_warn_with_code(&self, span: impl Into, msg: &str, code: DiagnosticId) { + self.emit_diag_at_span(Diagnostic::new_with_code(Warning, Some(code), msg), span); } - pub fn span_bug>(&self, sp: S, msg: &str) -> ! { - self.inner.borrow_mut().span_bug(sp, msg) + + pub fn span_bug(&self, span: impl Into, msg: &str) -> ! { + self.inner.borrow_mut().span_bug(span, msg) } - pub fn delay_span_bug>(&self, sp: S, msg: &str) { - self.inner.borrow_mut().delay_span_bug(sp, msg) + + pub fn delay_span_bug(&self, span: impl Into, msg: &str) { + self.inner.borrow_mut().delay_span_bug(span, msg) } - pub fn span_bug_no_panic>(&self, sp: S, msg: &str) { - self.emit_diagnostic(Diagnostic::new(Bug, msg).set_span(sp)); - self.abort_if_errors_and_should_abort(); + + pub fn span_bug_no_panic(&self, span: impl Into, msg: &str) { + self.emit_diag_at_span(Diagnostic::new(Bug, msg), span); } - pub fn span_note_without_error>(&self, sp: S, msg: &str) { - self.emit_diagnostic(Diagnostic::new(Note, msg).set_span(sp)); - self.abort_if_errors_and_should_abort(); + + pub fn span_note_without_error(&self, span: impl Into, msg: &str) { + self.emit_diag_at_span(Diagnostic::new(Note, msg), span); } - pub fn span_note_diag(&self, - sp: Span, - msg: &str) - -> DiagnosticBuilder<'_> { + + pub fn span_note_diag(&self, span: Span, msg: &str) -> DiagnosticBuilder<'_> { let mut db = DiagnosticBuilder::new(self, Note, msg); - db.set_span(sp); + db.set_span(span); db } + pub fn failure(&self, msg: &str) { self.inner.borrow_mut().failure(msg); } + pub fn fatal(&self, msg: &str) -> FatalError { self.inner.borrow_mut().fatal(msg) } + pub fn err(&self, msg: &str) { self.inner.borrow_mut().err(msg); } + pub fn warn(&self, msg: &str) { let mut db = DiagnosticBuilder::new(self, Warning, msg); db.emit(); } + pub fn note_without_error(&self, msg: &str) { - let mut db = DiagnosticBuilder::new(self, Note, msg); - db.emit(); + DiagnosticBuilder::new(self, Note, msg).emit(); } + pub fn bug(&self, msg: &str) -> ! { self.inner.borrow_mut().bug(msg) } @@ -698,6 +721,12 @@ impl Handler { self.inner.borrow_mut().emit_diagnostic(diagnostic) } + fn emit_diag_at_span(&self, mut diag: Diagnostic, sp: impl Into) { + let mut inner = self.inner.borrow_mut(); + inner.emit_diagnostic(diag.set_span(sp)); + inner.abort_if_errors_and_should_abort(); + } + pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) { self.inner.borrow_mut().emit_artifact_notification(path, artifact_type) } @@ -837,17 +866,17 @@ impl HandlerInner { } } - fn span_bug>(&mut self, sp: S, msg: &str) -> ! { - self.emit_explicit_bug(Diagnostic::new(Bug, msg).set_span(sp)); + fn span_bug(&mut self, sp: impl Into, msg: &str) -> ! { + self.emit_diag_at_span(Diagnostic::new(Bug, msg), sp); + panic!(ExplicitBug); } - fn emit_explicit_bug(&mut self, diag: &Diagnostic) -> ! { - self.emit_diagnostic(diag); + fn emit_diag_at_span(&mut self, mut diag: Diagnostic, sp: impl Into) { + self.emit_diagnostic(diag.set_span(sp)); self.abort_if_errors_and_should_abort(); - panic!(ExplicitBug); } - fn delay_span_bug>(&mut self, sp: S, msg: &str) { + fn delay_span_bug(&mut self, sp: impl Into, msg: &str) { if self.treat_err_as_bug() { // FIXME: don't abort here if report_delayed_bugs is off self.span_bug(sp, msg); @@ -862,18 +891,20 @@ impl HandlerInner { } fn fatal(&mut self, msg: &str) -> FatalError { - if self.treat_err_as_bug() { - self.bug(msg); - } - self.emit_diagnostic(&Diagnostic::new(Fatal, msg)); + self.emit_error(Fatal, msg); FatalError } fn err(&mut self, msg: &str) { + self.emit_error(Error, msg); + } + + /// Emit an error; level should be `Error` or `Fatal`. + fn emit_error(&mut self, level: Level, msg: &str,) { if self.treat_err_as_bug() { self.bug(msg); } - self.emit_diagnostic(&Diagnostic::new(Error, msg)); + self.emit_diagnostic(&Diagnostic::new(level, msg)); } fn bug(&mut self, msg: &str) -> ! { diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index b0e886a2aa2eb..f7e766bb84d57 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -832,7 +832,7 @@ fn check_method_receiver<'fcx, 'tcx>( } fn e0307(fcx: &FnCtxt<'fcx, 'tcx>, span: Span, receiver_ty: Ty<'_>) { - fcx.tcx.sess.diagnostic().mut_span_err( + fcx.tcx.sess.diagnostic().struct_span_err( span, &format!("invalid `self` parameter type: {:?}", receiver_ty) ).note("type of `self` must be `Self` or a type that dereferences to it") diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index a6be5b101788e..36d066b026933 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -1041,10 +1041,6 @@ impl<'a> ExtCtxt<'a> { pub fn span_err_with_code>(&self, sp: S, msg: &str, code: DiagnosticId) { self.parse_sess.span_diagnostic.span_err_with_code(sp, msg, code); } - pub fn mut_span_err>(&self, sp: S, msg: &str) - -> DiagnosticBuilder<'a> { - self.parse_sess.span_diagnostic.mut_span_err(sp, msg) - } pub fn span_warn>(&self, sp: S, msg: &str) { self.parse_sess.span_diagnostic.span_warn(sp, msg); } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index b80c530731dfc..c3b1f91d5317d 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -384,7 +384,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let attr = attr::find_by_name(item.attrs(), sym::derive) .expect("`derive` attribute should exist"); let span = attr.span; - let mut err = self.cx.mut_span_err(span, + let mut err = self.cx.struct_span_err(span, "`derive` may only be applied to structs, enums and unions"); if let ast::AttrStyle::Inner = attr.style { let trait_list = derives.iter() diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 26455df17b896..2765346b333cf 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -295,7 +295,7 @@ impl<'a, 'b> Context<'a, 'b> { .filter(|fmt| fmt.precision_span.is_some()) .count(); if self.names.is_empty() && !numbered_position_args && count != self.args.len() { - e = self.ecx.mut_span_err( + e = self.ecx.struct_span_err( sp, &format!( "{} positional argument{} in format string, but {}", @@ -336,7 +336,7 @@ impl<'a, 'b> Context<'a, 'b> { sp = MultiSpan::from_span(self.fmtsp); } - e = self.ecx.mut_span_err(sp, + e = self.ecx.struct_span_err(sp, &format!("invalid reference to positional {} ({})", arg_list, self.describe_num_args())); From 4fd9b9944f52afa948288c96c9860709c9f82231 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 18 Sep 2019 14:35:56 -0700 Subject: [PATCH 45/55] Add cycle detection for graphs --- .../graph/iterate/mod.rs | 204 +++++++++++++++++- .../graph/iterate/tests.rs | 11 + src/librustc_data_structures/graph/mod.rs | 10 + 3 files changed, 224 insertions(+), 1 deletion(-) diff --git a/src/librustc_data_structures/graph/iterate/mod.rs b/src/librustc_data_structures/graph/iterate/mod.rs index c4185fc7cd9c3..cbf6a0a3c03a0 100644 --- a/src/librustc_data_structures/graph/iterate/mod.rs +++ b/src/librustc_data_structures/graph/iterate/mod.rs @@ -1,5 +1,5 @@ use super::super::indexed_vec::IndexVec; -use super::{DirectedGraph, WithNumNodes, WithSuccessors}; +use super::{DirectedGraph, WithNumNodes, WithSuccessors, WithStartNode}; use crate::bit_set::BitSet; #[cfg(test)] @@ -85,3 +85,205 @@ where Some(n) } } + +/// Allows searches to terminate early with a value. +#[derive(Clone, Copy, Debug)] +pub enum ControlFlow { + Break(T), + Continue, +} + +/// The status of a node in the depth-first search. +/// +/// See the documentation of `TriColorDepthFirstSearch` to see how a node's status is updated +/// during DFS. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum NodeStatus { + /// This node has been examined by the depth-first search but is not yet `Settled`. + /// + /// Also referred to as "gray" or "discovered" nodes in [CLR][]. + /// + /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms + Visited, + + /// This node and all nodes reachable from it have been examined by the depth-first search. + /// + /// Also referred to as "black" or "finished" nodes in [CLR][]. + /// + /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms + Settled, +} + +struct Event { + node: N, + becomes: NodeStatus, +} + +/// A depth-first search that also tracks when all successors of a node have been examined. +/// +/// This is based on the DFS described in [Introduction to Algorithms (1st ed.)][CLR], hereby +/// referred to as **CLR**. However, we use the terminology in [`NodeStatus`][] above instead of +/// "discovered"/"finished" or "white"/"grey"/"black". Each node begins the search with no status, +/// becomes `Visited` when it is first examined by the DFS and is `Settled` when all nodes +/// reachable from it have been examined. This allows us to differentiate between "tree", "back" +/// and "forward" edges (see [`TriColorVisitor::node_examined`]). +/// +/// Unlike the pseudocode in [CLR][], this implementation is iterative and does not use timestamps. +/// We accomplish this by storing `Event`s on the stack that result in a (possible) state change +/// for each node. A `Visited` event signifies that we should examine this node if it has not yet +/// been `Visited` or `Settled`. When a node is examined for the first time, we mark it as +/// `Visited` and push a `Settled` event for it on stack followed by `Visited` events for all of +/// its predecessors, scheduling them for examination. Multiple `Visited` events for a single node +/// may exist on the stack simultaneously if a node has multiple predecessors, but only one +/// `Settled` event will ever be created for each node. After all `Visited` events for a node's +/// successors have been popped off the stack (as well as any new events triggered by visiting +/// those successors), we will pop off that node's `Settled` event. +/// +/// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms +/// [`NodeStatus`]: ./enum.NodeStatus.html +/// [`TriColorVisitor::node_examined`]: ./trait.TriColorVisitor.html#method.node_examined +pub struct TriColorDepthFirstSearch<'graph, G> +where + G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, +{ + graph: &'graph G, + stack: Vec>, + visited: BitSet, + settled: BitSet, +} + +impl TriColorDepthFirstSearch<'graph, G> +where + G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, +{ + pub fn new(graph: &'graph G) -> Self { + TriColorDepthFirstSearch { + graph, + stack: vec![], + visited: BitSet::new_empty(graph.num_nodes()), + settled: BitSet::new_empty(graph.num_nodes()), + } + } + + /// Performs a depth-first search, starting from the given `root`. + /// + /// This won't visit nodes that are not reachable from `root`. + pub fn run_from(mut self, root: G::Node, visitor: &mut V) -> Option + where + V: TriColorVisitor, + { + use NodeStatus::{Visited, Settled}; + + self.stack.push(Event { node: root, becomes: Visited }); + + loop { + match self.stack.pop()? { + Event { node, becomes: Settled } => { + let not_previously_settled = self.settled.insert(node); + assert!(not_previously_settled, "A node should be settled exactly once"); + if let ControlFlow::Break(val) = visitor.node_settled(node) { + return Some(val); + } + } + + Event { node, becomes: Visited } => { + let not_previously_visited = self.visited.insert(node); + let prior_status = if not_previously_visited { + None + } else if self.settled.contains(node) { + Some(Settled) + } else { + Some(Visited) + }; + + if let ControlFlow::Break(val) = visitor.node_examined(node, prior_status) { + return Some(val); + } + + // If this node has already been examined, we are done. + if prior_status.is_some() { + continue; + } + + // Otherwise, push a `Settled` event for this node onto the stack, then + // schedule its successors for examination. + self.stack.push(Event { node, becomes: Settled }); + for succ in self.graph.successors(node) { + self.stack.push(Event { node: succ, becomes: Visited }); + } + } + } + } + } +} + +impl TriColorDepthFirstSearch<'graph, G> +where + G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors + WithStartNode, +{ + /// Performs a depth-first search, starting from `G::start_node()`. + /// + /// This won't visit nodes that are not reachable from the start node. + pub fn run_from_start(self, visitor: &mut V) -> Option + where + V: TriColorVisitor, + { + let root = self.graph.start_node(); + self.run_from(root, visitor) + } +} + +/// What to do when a node is examined or becomes `Settled` during DFS. +pub trait TriColorVisitor +where + G: ?Sized + DirectedGraph, +{ + /// The value returned by this search. + type BreakVal; + + /// Called when a node is examined by the depth-first search. + /// + /// By checking the value of `prior_status`, this visitor can determine whether the edge + /// leading to this node was a tree edge (`None`), forward edge (`Some(Settled)`) or back edge + /// (`Some(Visited)`). For a full explanation of each edge type, see the "Depth-first Search" + /// chapter in [CLR][] or [wikipedia][]. + /// + /// If you want to know *both* nodes linked by each edge, you'll need to modify + /// `TriColorDepthFirstSearch` to store a `source` node for each `Visited` event. + /// + /// [wikipedia]: https://en.wikipedia.org/wiki/Depth-first_search#Output_of_a_depth-first_search + /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms + fn node_examined( + &mut self, + _target: G::Node, + _prior_status: Option, + ) -> ControlFlow { + ControlFlow::Continue + } + + /// Called after all nodes reachable from this one have been examined. + fn node_settled(&mut self, _target: G::Node) -> ControlFlow { + ControlFlow::Continue + } +} + +/// This `TriColorVisitor` looks for back edges in a graph, which indicate that a cycle exists. +pub struct CycleDetector; + +impl TriColorVisitor for CycleDetector +where + G: ?Sized + DirectedGraph, +{ + type BreakVal = (); + + fn node_examined( + &mut self, + _node: G::Node, + prior_status: Option, + ) -> ControlFlow { + match prior_status { + Some(NodeStatus::Visited) => ControlFlow::Break(()), + _ => ControlFlow::Continue, + } + } +} diff --git a/src/librustc_data_structures/graph/iterate/tests.rs b/src/librustc_data_structures/graph/iterate/tests.rs index 6c7cfd6d8a777..0e038e88b221d 100644 --- a/src/librustc_data_structures/graph/iterate/tests.rs +++ b/src/librustc_data_structures/graph/iterate/tests.rs @@ -9,3 +9,14 @@ fn diamond_post_order() { let result = post_order_from(&graph, 0); assert_eq!(result, vec![3, 1, 2, 0]); } + +#[test] +fn is_cyclic() { + use super::super::is_cyclic; + + let diamond_acyclic = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3)]); + let diamond_cyclic = TestGraph::new(0, &[(0, 1), (1, 2), (2, 3), (3, 0)]); + + assert!(!is_cyclic(&diamond_acyclic)); + assert!(is_cyclic(&diamond_cyclic)); +} diff --git a/src/librustc_data_structures/graph/mod.rs b/src/librustc_data_structures/graph/mod.rs index 662581ca1e498..0a607659f3e24 100644 --- a/src/librustc_data_structures/graph/mod.rs +++ b/src/librustc_data_structures/graph/mod.rs @@ -81,3 +81,13 @@ where + WithNumNodes, { } + +/// Returns `true` if the graph has a cycle that is reachable from the start node. +pub fn is_cyclic(graph: &G) -> bool +where + G: ?Sized + DirectedGraph + WithStartNode + WithSuccessors + WithNumNodes, +{ + iterate::TriColorDepthFirstSearch::new(graph) + .run_from_start(&mut iterate::CycleDetector) + .is_some() +} From c9e4816fe319b2fde83779ff375037c8079d36a2 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 18 Sep 2019 14:53:55 -0700 Subject: [PATCH 46/55] Add convenience function for detecting cyclic CFGs --- src/librustc/mir/mod.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 0ebc70750a6bb..5206e044f9fa5 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -262,6 +262,12 @@ impl<'tcx> Body<'tcx> { dominators(self) } + /// Returns `true` if a cycle exists in the control-flow graph that is reachable from the + /// `START_BLOCK`. + pub fn is_cfg_cyclic(&self) -> bool { + graph::is_cyclic(self) + } + #[inline] pub fn local_kind(&self, local: Local) -> LocalKind { let index = local.as_usize(); From b548814a8b01ee155ceb2946fc92a47dcbe74197 Mon Sep 17 00:00:00 2001 From: Baoshan Pang Date: Mon, 23 Sep 2019 15:37:18 -0700 Subject: [PATCH 47/55] remove rtp.rs, and move rtpSpawn and RTP_ID_ERROR to libc --- src/libstd/sys/vxworks/process/mod.rs | 1 - .../sys/vxworks/process/process_vxworks.rs | 5 +- src/libstd/sys/vxworks/process/rtp.rs | 298 ------------------ 3 files changed, 2 insertions(+), 302 deletions(-) delete mode 100644 src/libstd/sys/vxworks/process/rtp.rs diff --git a/src/libstd/sys/vxworks/process/mod.rs b/src/libstd/sys/vxworks/process/mod.rs index 1fc88fbde742f..3ecbe4e3b28ba 100644 --- a/src/libstd/sys/vxworks/process/mod.rs +++ b/src/libstd/sys/vxworks/process/mod.rs @@ -5,4 +5,3 @@ pub use crate::ffi::OsString as EnvKey; mod process_common; #[path = "process_vxworks.rs"] mod process_inner; -mod rtp; diff --git a/src/libstd/sys/vxworks/process/process_vxworks.rs b/src/libstd/sys/vxworks/process/process_vxworks.rs index 8780df17a1c7e..beb20aa48169a 100644 --- a/src/libstd/sys/vxworks/process/process_vxworks.rs +++ b/src/libstd/sys/vxworks/process/process_vxworks.rs @@ -3,7 +3,6 @@ use libc::{self, c_int, c_char}; use libc::{RTP_ID}; use crate::sys; use crate::sys::cvt; -use crate::sys::process::rtp; use crate::sys::process::process_common::*; use crate::sys_common::thread; @@ -53,7 +52,7 @@ impl Command { t!(cvt(libc::chdir(cwd.as_ptr()))); } - let ret = rtp::rtpSpawn( + let ret = libc::rtpSpawn( self.get_argv()[0], // executing program self.get_argv().as_ptr() as *const _, // argv *sys::os::environ() as *const *const c_char, @@ -78,7 +77,7 @@ impl Command { libc::close(orig_stderr); } - if ret != rtp::RTP_ID_ERROR { + if ret != libc::RTP_ID_ERROR { p.pid = ret; Ok((p, ours)) } else { diff --git a/src/libstd/sys/vxworks/process/rtp.rs b/src/libstd/sys/vxworks/process/rtp.rs deleted file mode 100644 index 3e6e0017abcb5..0000000000000 --- a/src/libstd/sys/vxworks/process/rtp.rs +++ /dev/null @@ -1,298 +0,0 @@ -#![allow(non_camel_case_types, unused)] - -use libc::{self, c_int, size_t, c_char, BOOL, RTP_DESC, RTP_ID, TASK_ID}; - - -// Copied directly from rtpLibCommon.h, rtpLib.h, signal.h and taskLibCommon.h (for task options) - -// **** definitions for rtpLibCommon.h **** - -pub const RTP_GLOBAL_SYMBOLS : c_int = 0x01; // register global symbols for RTP -pub const RTP_LOCAL_SYMBOLS : c_int = 0x02; // idem for local symbols -pub const RTP_ALL_SYMBOLS : c_int = (RTP_GLOBAL_SYMBOLS | RTP_LOCAL_SYMBOLS); -pub const RTP_DEBUG : c_int = 0x10; // set RTP in debug mode when created -pub const RTP_BUFFER_VAL_OFF : c_int = 0x20; // disable buffer validation for all - // system calls issued from the RTP -pub const RTP_LOADED_WAIT : c_int = 0x40; // Wait until the RTP is loaded -pub const RTP_CPU_AFFINITY_NONE : c_int = 0x80; // Remove any CPU affinity (SMP) - -// Error Status codes - -pub const M_rtpLib : c_int = 178 << 16; - -pub const S_rtpLib_INVALID_FILE : c_int = (M_rtpLib | 1); -pub const S_rtpLib_INVALID_OPTION : c_int = (M_rtpLib | 2); -pub const S_rtpLib_ACCESS_DENIED : c_int = (M_rtpLib | 3); -pub const S_rtpLib_INVALID_RTP_ID : c_int = (M_rtpLib | 4); -pub const S_rtpLib_NO_SYMBOL_TABLE : c_int = (M_rtpLib | 5); -pub const S_rtpLib_INVALID_SEGMENT_START_ADDRESS : c_int = (M_rtpLib | 6); -pub const S_rtpLib_INVALID_SYMBOL_REGISTR_POLICY : c_int = (M_rtpLib | 7); -pub const S_rtpLib_INSTANTIATE_FAILED : c_int = (M_rtpLib | 8); -pub const S_rtpLib_INVALID_TASK_OPTION : c_int = (M_rtpLib | 9); -pub const S_rtpLib_RTP_NAME_LENGTH_EXCEEDED : c_int = (M_rtpLib | 10); // rtpInfoGet - -pub const VX_RTP_NAME_LENGTH : c_int = 255; // max name length for diplay - - -// The 'status' field (32 bit integer) of a RTP holds the RTP state and status. -// -// NOTE: RTP_STATE_GET() : read the RTP state(s) -// RTP_STATE_PUT() : write the RTP state(s) -// RTP_STATE_SET() : set a RTP state -// RTP_STATE_UNSET() : unset a RTP state -// -// RTP_STATUS_GET() : read the RTP status -// RTP_STATUS_PUT() : write the RTP status -// RTP_STATUS_SET() : set a RTP status -// RTP_STATUS_UNSET() : unset a RTP status -// -// The PUT/SET/UNSET macros are available only in the kernel headers. - - -// RTP states - -pub const RTP_STATE_CREATE : c_int = 0x0001; // RrtpStructTP is under construction -pub const RTP_STATE_NORMAL : c_int = 0x0002; // RrtpStructTP is ready -pub const RTP_STATE_DELETE : c_int = 0x0004; // RrtpStructTP is being deleted - -pub const RTP_STATUS_STOP : c_int = 0x0100; // RTP hrtpStructas recieved stopped signal -pub const RTP_STATUS_ELECTED_DELETER : c_int = 0x0200; // RTP drtpStructelete has started - -pub const RTP_STATE_MASK : c_int = (RTP_STATE_CREATE | RTP_STATE_NORMAL | - RTP_STATE_DELETE); -pub const RTP_STATUS_MASK : c_int = (RTP_STATUS_STOP | RTP_STATUS_ELECTED_DELETER); - -pub fn RTP_STATE_GET (value : c_int) -> c_int { - value & RTP_STATE_MASK -} -pub fn RTP_STATUS_GET (value : c_int) -> c_int { - value & RTP_STATUS_MASK -} - -// Indicates that the RTP_ID returned is not valid. - -// RTP_ID_ERROR is supposed to be set to -1, but you can't set -// an unsigned value to a negative without casting, and you -// can't cast unless the size of the integer types are the same, -// but the size of RTP_ID may differ between kernel and user space. -// Bitwise or-ing min and max should get the same result. -pub const RTP_ID_ERROR : RTP_ID = RTP_ID::min_value() | RTP_ID::max_value(); - -// IS_RTP_ C macros - -pub fn IS_RTP_STATE_NORMAL (value : c_int) -> bool { - (RTP_STATE_GET(value) & RTP_STATE_NORMAL) == RTP_STATE_NORMAL -} -pub fn IS_RTP_STATE_CREATE (value : c_int) -> bool { - (RTP_STATE_GET(value) & RTP_STATE_CREATE) == RTP_STATE_CREATE -} -pub fn IS_RTP_STATE_DELETE (value : c_int) -> bool { - (RTP_STATE_GET(value) & RTP_STATE_DELETE) == RTP_STATE_DELETE -} -pub fn IS_RTP_STATUS_STOP (value : c_int) -> bool { - (RTP_STATUS_GET(value) & RTP_STATUS_STOP ) == RTP_STATUS_STOP -} -pub fn IS_RTP_STATUS_ELECTED_DELETER (value : c_int) -> bool { - (RTP_STATUS_GET(value) & RTP_STATUS_ELECTED_DELETER) == RTP_STATUS_ELECTED_DELETER -} - -// **** end of definitions for rtpLibCommon.h **** - - - - -// **** definitions for rtpLib.h **** - -pub fn rtpExit(exitCode : c_int) -> ! { - unsafe{ libc::exit (exitCode) } -} - -/* rtpLib.h in the kernel -pub const RTP_DEL_VIA_TASK_DELETE : c_int = 0x1; // rtpDelete() via taskDestroy() -pub const RTP_DEL_FORCE : c_int = 0x2; // Forceful rtpDelete() -pub const RTP_ID_ANY : RTP_ID = 0; // used for when a kernel task - // wants to wait for the next - // RTP to finish - - -// Function pointers - -pub type RTP_PRE_CREATE_HOOK = size_t; -pub type RTP_POST_CREATE_HOOK = size_t; -pub type RTP_INIT_COMPLETE_HOOK = size_t; -pub type RTP_DELETE_HOOK = size_t; -*/ - -// **** end of definitions for rtpLib.h **** - - - - - -// **** definitions for signal.h **** -pub fn rtpKill(rtpId : RTP_ID, signo : c_int) -> c_int { - unsafe{ libc::kill(rtpId as c_int, signo) } -} - -pub fn rtpSigqueue(rtpId : RTP_ID, signo : c_int, value : size_t) -> c_int { - unsafe{ libc::sigqueue(rtpId as c_int, signo, value) } -} - -pub fn _rtpSigqueue(rtpId : RTP_ID, signo : c_int, value : *mut size_t, code : c_int) -> c_int { - unsafe{ libc::_sigqueue(rtpId, signo, value, code) } -} - -pub fn taskRaise(signo : c_int) -> c_int { - unsafe{ libc::taskKill(libc::taskIdSelf(), signo) } -} -pub fn rtpRaise(signo : c_int) -> c_int { - unsafe{ libc::raise(signo) } -} - -// **** end of definitions for signal.h **** - - - -// **** definitions for taskLibCommon.h **** -pub const VX_PRIVATE_ENV : c_int = 0x0080; // 1 = private environment variables -pub const VX_NO_STACK_FILL : c_int = 0x0100; // 1 = avoid stack fill of 0xee -pub const VX_PRIVATE_UMASK : c_int = 0x0400; // 1 = private file creation mode mask -pub const VX_TASK_NOACTIVATE : c_int = 0x2000; // taskOpen() does not taskActivate() -pub const VX_NO_STACK_PROTECT : c_int = 0x4000; // no over/underflow stack protection, - // stack space remains executable - -// define for all valid user task options - -pub const VX_USR_TASK_OPTIONS_BASE: c_int = (VX_PRIVATE_ENV | - VX_NO_STACK_FILL | - VX_TASK_NOACTIVATE | - VX_NO_STACK_PROTECT | - VX_PRIVATE_UMASK); - -// **** end of definitions for taskLibCommon.h **** - - - -extern "C" { -// functions in rtpLibCommon.h - -// forward declarations - pub fn rtpSpawn ( - pubrtpFileName : *const c_char, - argv : *const *const c_char, - envp : *const *const c_char, - priority : c_int, - uStackSize : size_t, - options : c_int, - taskOptions : c_int, - ) -> RTP_ID; - - pub fn rtpInfoGet ( - rtpId : RTP_ID, - rtpStruct : *mut RTP_DESC, - ) -> c_int; - -/* functions in rtpLib.h for kernel - - - // function declarations - - pub fn rtpDelete ( - id : RTP_ID, - options : c_int, - status : c_int, - ) -> c_int; - - pub fn rtpDeleteForce ( - rtpId : RTP_ID - ) -> c_int; - - pub fn rtpShow ( - rtpNameOrId : *mut c_char, - level : c_int, - ) -> BOOL; - - // RTP signals are always present when RTPs are included. The public RTP - // signal APIs are declared here. - - - pub fn rtpKill ( - rtpId : RTP_ID, - signo : c_int, - ) -> c_int; - - pub fn rtpSigqueue ( - rtpId : RTP_ID, - signo : c_int, - value : size_t, // Actual type is const union sigval value, - // which is a union of int and void * - ) -> c_int; - - pub fn rtpTaskKill ( - tid : TASK_ID, - signo : c_int, - ) -> c_int; - - pub fn rtpTaskSigqueue ( - tid : TASK_ID, - signo : c_int, - value : const size_t, // Actual type is const union sigval, - // which is a union of int and void * - ) -> c_int; - - pub fn rtpWait ( - rtpWaitId : RTP_ID, - timeout : libc::alloc_jemalloc_Vx_ticks_t, - pRtpId : *mut RTP_ID, - pStatus : *mut c_int, - ) -> c_int; - - // Other public functions - - - pub fn rtpPreCreateHookAdd ( - hook : RTP_PRE_CREATE_HOOK, - addToHead : BOOL, - ) -> c_int; - - pub fn rtpPreCreateHookDelete ( - hook : RTP_POST_CREATE_HOOK, - ) -> c_int; - - pub fn rtpPostCreateHookAdd ( - hook : RTP_POST_CREATE_HOOK, - addToHead : BOOL, - ) -> c_int; - - pub fn rtpPostCreateHookDelete ( - hook : RTP_POST_CREATE_HOOK, - ) -> c_int; - - pub fn rtpInitCompleteHookAdd ( - hook : RTP_INIT_COMPLETE_HOOK, - addToHead : BOOL, - ) -> c_int; - - pub fn rtpInitCompleteHookDelete ( - hook : RTP_INIT_COMPLETE_HOOK, - ) -> c_int; - - pub fn rtpDeleteHookAdd ( - hook : RTP_DELETE_HOOK, - addToHead : BOOL, - ) -> c_int; - - pub fn rtpDeleteHookDelete ( - hook : RTP_DELETE_HOOK, - ) -> c_int; - - pub fn rtpMemShow ( - rtpNameOrId : *mut c_char, - level : c_int, - ) -> c_int; - - pub fn rtpHookShow ( - - ); -*/ -} From fa2cfaf064ecda727fb922864a8eafbae1875228 Mon Sep 17 00:00:00 2001 From: hman523 Date: Mon, 23 Sep 2019 18:20:21 -0500 Subject: [PATCH 48/55] Fixed issue from #64447 --- src/librustc_errors/emitter.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index fc441320e0039..c13a4b8dbb487 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -1043,14 +1043,13 @@ impl EmitterWriter { } fn get_max_line_num(&mut self, span: &MultiSpan, children: &[SubDiagnostic]) -> usize { - let mut max = 0; let primary = self.get_multispan_max_line_num(span); - max = if primary > max { primary } else { max }; + let mut max = primary; for sub in children { let sub_result = self.get_multispan_max_line_num(&sub.span); - max = if sub_result > max { primary } else { max }; + max = if sub_result > max { sub_result } else { max }; } max } From a6da0e921b01352dbdf45320afc9e41f27ac5784 Mon Sep 17 00:00:00 2001 From: hman523 Date: Mon, 23 Sep 2019 19:51:15 -0500 Subject: [PATCH 49/55] changed a line from an if else to std::cmp::max --- src/librustc_errors/emitter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index c13a4b8dbb487..2a89c94652a24 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -1049,7 +1049,7 @@ impl EmitterWriter { for sub in children { let sub_result = self.get_multispan_max_line_num(&sub.span); - max = if sub_result > max { sub_result } else { max }; + max = std::cmp::max(sub_result, max); } max } From 5aa5d5780839cda5a7fde2cf434a630b98cd485b Mon Sep 17 00:00:00 2001 From: Guanqun Lu Date: Tue, 24 Sep 2019 10:29:09 +0800 Subject: [PATCH 50/55] fix one typo --- src/librustc_typeck/check/method/suggest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 74e4f28255b16..4c681544978e5 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -232,7 +232,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let mut err = if !actual.references_error() { // Suggest clamping down the type if the method that is being attempted to - // be used exists at all, and the type is an ambiuous numeric type + // be used exists at all, and the type is an ambiguous numeric type // ({integer}/{float}). let mut candidates = all_traits(self.tcx) .into_iter() From 62dc7948d1e6b45e25a2ce177f76f257f3a5c1a4 Mon Sep 17 00:00:00 2001 From: jordins Date: Tue, 24 Sep 2019 15:25:24 +0200 Subject: [PATCH 51/55] fix several issues in String docs - In some places &str was shown instead of String. - into_bytes is the reverse of from_utf8 Fixes #63797 --- src/liballoc/string.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 1166e7b5df295..e5f96ada6d5ee 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -429,7 +429,7 @@ impl String { /// Converts a vector of bytes to a `String`. /// - /// A string slice ([`&str`]) is made of bytes ([`u8`]), and a vector of bytes + /// A string ([`String`]) is made of bytes ([`u8`]), and a vector of bytes /// ([`Vec`]) is made of bytes, so this function converts between the /// two. Not all byte slices are valid `String`s, however: `String` /// requires that it is valid UTF-8. `from_utf8()` checks to ensure that @@ -446,7 +446,7 @@ impl String { /// If you need a [`&str`] instead of a `String`, consider /// [`str::from_utf8`]. /// - /// The inverse of this method is [`as_bytes`]. + /// The inverse of this method is [`into_bytes`]. /// /// # Errors /// @@ -480,11 +480,11 @@ impl String { /// with this error. /// /// [`from_utf8_unchecked`]: struct.String.html#method.from_utf8_unchecked - /// [`&str`]: ../../std/primitive.str.html + /// [`String`]: struct.String.html /// [`u8`]: ../../std/primitive.u8.html /// [`Vec`]: ../../std/vec/struct.Vec.html /// [`str::from_utf8`]: ../../std/str/fn.from_utf8.html - /// [`as_bytes`]: struct.String.html#method.as_bytes + /// [`into_bytes`]: struct.String.html#method.into_bytes /// [`FromUtf8Error`]: struct.FromUtf8Error.html /// [`Err`]: ../../std/result/enum.Result.html#variant.Err #[inline] From 33e1dd78646e712e7fe159e903fff58bd1734418 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 26 Aug 2019 21:32:14 -0400 Subject: [PATCH 52/55] Fix coherence checking for impl trait in type aliases Fixes #63677 RFC #2071 (impl-trait-existential-types) does not explicitly state how impl trait type alises should interact with coherence. However, there's only one choice which makes sense - coherence should look at the underlying type (i.e. the 'defining' type of the impl trait) of the type alias, just like we do for non-impl-trait type aliases. Specifically, impl trait type alises which resolve to a local type should be treated like a local type with respect to coherence (e.g. impl trait type aliases which resolve to a forieign type should be treated as a foreign type, and those that resolve to a local type should be treated as a local type). Since neither inherent impls nor direct trait impl (i.e. `impl MyType` or `impl MyTrait for MyType`) are allowd for type aliases, this usually does not come up. Before we ever attempt to do coherence checking, we will have errored out if an impl trait type alias was used directly in an 'impl' clause. However, during trait selection, we sometimes need to prove bounds like 'T: Sized' for some type 'T'. If 'T' is an impl trait type alias, this requires to know the coherence behavior for impl trait type aliases when we perform coherence checking. Note: Since determining the underlying type of an impl trait type alias requires us to perform body type checking, this commit causes us to type check some bodies easlier than we otherwise would have. However, since this is done through a query, this shouldn't cause any problems For completeness, I've added an additional test of the coherence-related behavior of impl trait type aliases. --- src/librustc/traits/coherence.rs | 18 +++++++++++----- .../traits/specialize/specialization_graph.rs | 2 +- .../auxiliary/foreign-crate.rs | 2 ++ .../ui/type-alias-impl-trait/coherence.rs | 17 +++++++++++++++ .../ui/type-alias-impl-trait/coherence.stderr | 9 ++++++++ .../issue-63677-type-alias-coherence.rs | 21 +++++++++++++++++++ 6 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/type-alias-impl-trait/auxiliary/foreign-crate.rs create mode 100644 src/test/ui/type-alias-impl-trait/coherence.rs create mode 100644 src/test/ui/type-alias-impl-trait/coherence.stderr create mode 100644 src/test/ui/type-alias-impl-trait/issue-63677-type-alias-coherence.rs diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index b6f0addd77107..ee318b127ae66 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -432,7 +432,7 @@ fn orphan_check_trait_ref<'tcx>( } fn uncovered_tys<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, in_crate: InCrate) -> Vec> { - if ty_is_local_constructor(ty, in_crate) { + if ty_is_local_constructor(tcx, ty, in_crate) { vec![] } else if fundamental_ty(ty) { ty.walk_shallow() @@ -451,7 +451,7 @@ fn is_possibly_remote_type(ty: Ty<'_>, _in_crate: InCrate) -> bool { } fn ty_is_local(tcx: TyCtxt<'_>, ty: Ty<'_>, in_crate: InCrate) -> bool { - ty_is_local_constructor(ty, in_crate) || + ty_is_local_constructor(tcx, ty, in_crate) || fundamental_ty(ty) && ty.walk_shallow().any(|t| ty_is_local(tcx, t, in_crate)) } @@ -472,7 +472,7 @@ fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool { } } -fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool { +fn ty_is_local_constructor(tcx: TyCtxt<'_>, ty: Ty<'_>, in_crate: InCrate) -> bool { debug!("ty_is_local_constructor({:?})", ty); match ty.sty { @@ -504,6 +504,15 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool { ty::Adt(def, _) => def_id_is_local(def.did, in_crate), ty::Foreign(did) => def_id_is_local(did, in_crate), + ty::Opaque(did, _) => { + // Check the underlying type that this opaque + // type resolves to. + // This recursion will eventually terminate, + // since we've already managed to successfully + // resolve all opaque types by this point + let real_ty = tcx.type_of(did); + ty_is_local_constructor(tcx, real_ty, in_crate) + } ty::Dynamic(ref tt, ..) => { if let Some(principal) = tt.principal() { @@ -518,8 +527,7 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool { ty::UnnormalizedProjection(..) | ty::Closure(..) | ty::Generator(..) | - ty::GeneratorWitness(..) | - ty::Opaque(..) => { + ty::GeneratorWitness(..) => { bug!("ty_is_local invoked on unexpected type: {:?}", ty) } } diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index b43881defdb85..c9a40db41dfde 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -395,7 +395,7 @@ impl<'tcx> Graph { /// The parent of a given impl, which is the `DefId` of the trait when the /// impl is a "specialization root". pub fn parent(&self, child: DefId) -> DefId { - *self.parent.get(&child).unwrap() + *self.parent.get(&child).unwrap_or_else(|| panic!("Failed to get parent for {:?}", child)) } } diff --git a/src/test/ui/type-alias-impl-trait/auxiliary/foreign-crate.rs b/src/test/ui/type-alias-impl-trait/auxiliary/foreign-crate.rs new file mode 100644 index 0000000000000..52802dd8fbb47 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/auxiliary/foreign-crate.rs @@ -0,0 +1,2 @@ +pub trait ForeignTrait {} +pub struct ForeignType(pub T); diff --git a/src/test/ui/type-alias-impl-trait/coherence.rs b/src/test/ui/type-alias-impl-trait/coherence.rs new file mode 100644 index 0000000000000..1c0f83d6c12da --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/coherence.rs @@ -0,0 +1,17 @@ +// aux-build:foreign-crate.rs +#![feature(type_alias_impl_trait)] + +extern crate foreign_crate; + +trait LocalTrait {} +impl LocalTrait for foreign_crate::ForeignType {} + +type AliasOfForeignType = impl LocalTrait; +fn use_alias(val: T) -> AliasOfForeignType { + foreign_crate::ForeignType(val) +} + +impl foreign_crate::ForeignTrait for AliasOfForeignType {} +//~^ ERROR the type parameter `T` is not constrained by the impl trait, self type, or predicates + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/coherence.stderr b/src/test/ui/type-alias-impl-trait/coherence.stderr new file mode 100644 index 0000000000000..6ede0fa14ba70 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/coherence.stderr @@ -0,0 +1,9 @@ +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/coherence.rs:14:6 + | +LL | impl foreign_crate::ForeignTrait for AliasOfForeignType {} + | ^ unconstrained type parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0207`. diff --git a/src/test/ui/type-alias-impl-trait/issue-63677-type-alias-coherence.rs b/src/test/ui/type-alias-impl-trait/issue-63677-type-alias-coherence.rs new file mode 100644 index 0000000000000..28f4a85c9f290 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-63677-type-alias-coherence.rs @@ -0,0 +1,21 @@ +// check-pass +// Regression test for issue #63677 - ensure that +// coherence checking can properly handle 'impl trait' +// in type aliases +#![feature(type_alias_impl_trait)] + +pub trait Trait {} +pub struct S1(T); +pub struct S2(T); + +pub type T1 = impl Trait; +pub type T2 = S1; +pub type T3 = S2; + +impl Trait for S1 {} +impl S2 {} +impl T3 {} + +pub fn use_t1() -> T1 { S1(()) } + +fn main() {} From e8cf46e909bcfb6c77b3efb2a60ed674770e1603 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Tue, 24 Sep 2019 18:36:01 +0200 Subject: [PATCH 53/55] relnotes: make compatibility section more sterile and fix rustc version --- RELEASES.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index ecf49278f4b52..766cf64410c77 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -70,10 +70,10 @@ Misc Compatibility Notes ------------------- -- Unfortunately the [`x86_64-unknown-uefi` platform can not be built][62785] - with rustc 1.39.0. -- The [`armv7-unknown-linux-gnueabihf` platform is also known to have - issues][62896] for certain crates such as libc. +- The [`x86_64-unknown-uefi` platform can not be built][62785] with rustc + 1.38.0. +- The [`armv7-unknown-linux-gnueabihf` platform is known to have + issues][62896] with certain crates such as libc. [60260]: https://github.com/rust-lang/rust/pull/60260/ [61457]: https://github.com/rust-lang/rust/pull/61457/ From 61cfe92a992f8cd8b1af8e443c442be9559c3a19 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 24 Sep 2019 10:01:14 -0400 Subject: [PATCH 54/55] Add additional tests for type alias impl trait coherence --- src/test/ui/impl-trait/auto-trait.rs | 23 +++++++++++++++++++ src/test/ui/impl-trait/auto-trait.stderr | 12 ++++++++++ src/test/ui/impl-trait/negative-reasoning.rs | 22 ++++++++++++++++++ .../ui/impl-trait/negative-reasoning.stderr | 14 +++++++++++ 4 files changed, 71 insertions(+) create mode 100644 src/test/ui/impl-trait/auto-trait.rs create mode 100644 src/test/ui/impl-trait/auto-trait.stderr create mode 100644 src/test/ui/impl-trait/negative-reasoning.rs create mode 100644 src/test/ui/impl-trait/negative-reasoning.stderr diff --git a/src/test/ui/impl-trait/auto-trait.rs b/src/test/ui/impl-trait/auto-trait.rs new file mode 100644 index 0000000000000..c767578120883 --- /dev/null +++ b/src/test/ui/impl-trait/auto-trait.rs @@ -0,0 +1,23 @@ +// Tests that type alias impls traits do not leak auto-traits for +// the purposes of coherence checking +#![feature(type_alias_impl_trait)] + +trait OpaqueTrait { } +impl OpaqueTrait for T { } +type OpaqueType = impl OpaqueTrait; +fn mk_opaque() -> OpaqueType { () } + +#[derive(Debug)] +struct D(T); + +trait AnotherTrait { } +impl AnotherTrait for T { } + +// This is in error, because we cannot assume that `OpaqueType: !Send`. +// (We treat opaque types as "foreign types" that could grow more impls +// in the future.) +impl AnotherTrait for D { + //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D` +} + +fn main() {} diff --git a/src/test/ui/impl-trait/auto-trait.stderr b/src/test/ui/impl-trait/auto-trait.stderr new file mode 100644 index 0000000000000..5e72ca7a47ba1 --- /dev/null +++ b/src/test/ui/impl-trait/auto-trait.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D`: + --> $DIR/auto-trait.rs:19:1 + | +LL | impl AnotherTrait for T { } + | -------------------------------- first implementation here +... +LL | impl AnotherTrait for D { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/impl-trait/negative-reasoning.rs b/src/test/ui/impl-trait/negative-reasoning.rs new file mode 100644 index 0000000000000..4977f9bdbacd9 --- /dev/null +++ b/src/test/ui/impl-trait/negative-reasoning.rs @@ -0,0 +1,22 @@ +// Tests that we cannot assume that an opaque type does *not* implement some +// other trait +#![feature(type_alias_impl_trait)] + +trait OpaqueTrait { } +impl OpaqueTrait for T { } +type OpaqueType = impl OpaqueTrait; +fn mk_opaque() -> OpaqueType { () } + +#[derive(Debug)] +struct D(T); + +trait AnotherTrait { } +impl AnotherTrait for T { } + + +// This is in error, because we cannot assume that `OpaqueType: !Debug` +impl AnotherTrait for D { + //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D` +} + +fn main() {} diff --git a/src/test/ui/impl-trait/negative-reasoning.stderr b/src/test/ui/impl-trait/negative-reasoning.stderr new file mode 100644 index 0000000000000..526a664726ac2 --- /dev/null +++ b/src/test/ui/impl-trait/negative-reasoning.stderr @@ -0,0 +1,14 @@ +error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D`: + --> $DIR/negative-reasoning.rs:18:1 + | +LL | impl AnotherTrait for T { } + | ------------------------------------------- first implementation here +... +LL | impl AnotherTrait for D { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D` + | + = note: upstream crates may add a new impl of trait `std::fmt::Debug` for type `OpaqueType` in future versions + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. From 7b71abdb5490665e6e1f26486da0067904c1cd60 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 24 Sep 2019 22:42:45 +0200 Subject: [PATCH 55/55] Fix #64744 -- handle zero sub-pats case. --- src/librustc_typeck/check/pat.rs | 59 ++++++++++++++++++++++------ src/test/ui/error-codes/E0023.rs | 3 +- src/test/ui/error-codes/E0023.stderr | 15 ++++++- 3 files changed, 62 insertions(+), 15 deletions(-) diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index d687a5084e231..2cd8507d753a6 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -676,7 +676,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } else { // Pattern has wrong number of fields. - self.e0023(pat.span, res, &subpats, &variant.fields, expected); + self.e0023(pat.span, res, qpath, subpats, &variant.fields, expected); on_error(); return tcx.types.err; } @@ -687,22 +687,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, pat_span: Span, res: Res, + qpath: &hir::QPath, subpats: &'tcx [P], fields: &[ty::FieldDef], expected: Ty<'tcx> ) { let subpats_ending = pluralise!(subpats.len()); let fields_ending = pluralise!(fields.len()); - let missing_parenthesis = match expected.sty { - ty::Adt(_, substs) if fields.len() == 1 => { - let field_ty = fields[0].ty(self.tcx, substs); - match field_ty.sty { - ty::Tuple(_) => field_ty.tuple_fields().count() == subpats.len(), - _ => false, - } - } - _ => false, - }; let res_span = self.tcx.def_span(res.def_id()); let mut err = struct_span_err!( self.tcx.sess, @@ -723,11 +714,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )) .span_label(res_span, format!("{} defined here", res.descr())); + // Identify the case `Some(x, y)` where the expected type is e.g. `Option<(T, U)>`. + // More generally, the expected type wants a tuple variant with one field of an + // N-arity-tuple, e.g., `V_i((p_0, .., p_N))`. Meanwhile, the user supplied a pattern + // with the subpatterns directly in the tuple variant pattern, e.g., `V_i(p_0, .., p_N)`. + let missing_parenthesis = match expected.sty { + ty::Adt(_, substs) if fields.len() == 1 => { + let field_ty = fields[0].ty(self.tcx, substs); + match field_ty.sty { + ty::Tuple(_) => field_ty.tuple_fields().count() == subpats.len(), + _ => false, + } + } + _ => false, + }; if missing_parenthesis { + let (left, right) = match subpats { + // This is the zero case; we aim to get the "hi" part of the `QPath`'s + // span as the "lo" and then the "hi" part of the pattern's span as the "hi". + // This looks like: + // + // help: missing parenthesis + // | + // L | let A(()) = A(()); + // | ^ ^ + [] => { + let qpath_span = match qpath { + hir::QPath::Resolved(_, path) => path.span, + hir::QPath::TypeRelative(_, ps) => ps.ident.span, + }; + (qpath_span.shrink_to_hi(), pat_span) + }, + // Easy case. Just take the "lo" of the first sub-pattern and the "hi" of the + // last sub-pattern. In the case of `A(x)` the first and last may coincide. + // This looks like: + // + // help: missing parenthesis + // | + // L | let A((x, y)) = A((1, 2)); + // | ^ ^ + [first, ..] => (first.span.shrink_to_lo(), subpats.last().unwrap().span), + }; err.multipart_suggestion( "missing parenthesis", - vec![(subpats[0].span.shrink_to_lo(), "(".to_string()), - (subpats[subpats.len()-1].span.shrink_to_hi(), ")".to_string())], + vec![ + (left, "(".to_string()), + (right.shrink_to_hi(), ")".to_string()), + ], Applicability::MachineApplicable, ); } diff --git a/src/test/ui/error-codes/E0023.rs b/src/test/ui/error-codes/E0023.rs index dc421e060e86f..7ac22bb71092e 100644 --- a/src/test/ui/error-codes/E0023.rs +++ b/src/test/ui/error-codes/E0023.rs @@ -2,9 +2,9 @@ enum Fruit { Apple(String, String), Pear(u32), Orange((String, String)), + Banana(()), } - fn main() { let x = Fruit::Apple(String::new(), String::new()); match x { @@ -12,5 +12,6 @@ fn main() { Fruit::Apple(a, b, c) => {}, //~ ERROR E0023 Fruit::Pear(1, 2) => {}, //~ ERROR E0023 Fruit::Orange(a, b) => {}, //~ ERROR E0023 + Fruit::Banana() => {}, //~ ERROR E0023 } } diff --git a/src/test/ui/error-codes/E0023.stderr b/src/test/ui/error-codes/E0023.stderr index 8ae7d01ed5f7e..dbce6003a2bad 100644 --- a/src/test/ui/error-codes/E0023.stderr +++ b/src/test/ui/error-codes/E0023.stderr @@ -38,6 +38,19 @@ help: missing parenthesis LL | Fruit::Orange((a, b)) => {}, | ^ ^ -error: aborting due to 4 previous errors +error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 1 field + --> $DIR/E0023.rs:15:9 + | +LL | Banana(()), + | ---------- tuple variant defined here +... +LL | Fruit::Banana() => {}, + | ^^^^^^^^^^^^^^^ expected 1 field, found 0 +help: missing parenthesis + | +LL | Fruit::Banana(()) => {}, + | ^ ^ + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0023`.