From 920435f195b49029d0a83679c04d7dda66afb50a Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 2 Dec 2022 14:07:58 +0000 Subject: [PATCH 01/70] Windows: make Command prefer non-verbatim paths When spawning Commands, the path we use can end up being queried using `env::current_exe` (or the equivalent in other languages). Not all applications handle these paths properly therefore we should have a stronger preference for non-verbatim paths when spawning processes. --- library/std/src/sys/windows/args.rs | 23 +++++++--- library/std/src/sys/windows/path.rs | 63 ++++++++++++++++---------- library/std/src/sys/windows/process.rs | 12 ++--- 3 files changed, 61 insertions(+), 37 deletions(-) diff --git a/library/std/src/sys/windows/args.rs b/library/std/src/sys/windows/args.rs index 6741ae46d32d..497241615491 100644 --- a/library/std/src/sys/windows/args.rs +++ b/library/std/src/sys/windows/args.rs @@ -11,10 +11,11 @@ use crate::fmt; use crate::io; use crate::num::NonZeroU16; use crate::os::windows::prelude::*; -use crate::path::PathBuf; -use crate::sys::c; +use crate::path::{Path, PathBuf}; +use crate::sys::path::get_long_path; use crate::sys::process::ensure_no_nuls; use crate::sys::windows::os::current_exe; +use crate::sys::{c, to_u16s}; use crate::sys_common::wstr::WStrUnits; use crate::vec; @@ -302,7 +303,7 @@ pub(crate) fn make_bat_command_line( /// Takes a path and tries to return a non-verbatim path. /// /// This is necessary because cmd.exe does not support verbatim paths. -pub(crate) fn to_user_path(mut path: Vec) -> io::Result> { +pub(crate) fn to_user_path(path: &Path) -> io::Result> { use crate::ptr; use crate::sys::windows::fill_utf16_buf; @@ -315,6 +316,8 @@ pub(crate) fn to_user_path(mut path: Vec) -> io::Result> { const N: u16 = b'N' as _; const C: u16 = b'C' as _; + let mut path = to_u16s(path)?; + // Early return if the path is too long to remove the verbatim prefix. const LEGACY_MAX_PATH: usize = 260; if path.len() > LEGACY_MAX_PATH { @@ -328,7 +331,13 @@ pub(crate) fn to_user_path(mut path: Vec) -> io::Result> { fill_utf16_buf( |buffer, size| c::GetFullPathNameW(lpfilename, size, buffer, ptr::null_mut()), |full_path: &[u16]| { - if full_path == &path[4..path.len() - 1] { full_path.into() } else { path } + if full_path == &path[4..path.len() - 1] { + let mut path: Vec = full_path.into(); + path.push(0); + path + } else { + path + } }, ) }, @@ -341,7 +350,9 @@ pub(crate) fn to_user_path(mut path: Vec) -> io::Result> { |buffer, size| c::GetFullPathNameW(lpfilename, size, buffer, ptr::null_mut()), |full_path: &[u16]| { if full_path == &path[6..path.len() - 1] { - full_path.into() + let mut path: Vec = full_path.into(); + path.push(0); + path } else { // Restore the 'C' in "UNC". path[6] = b'C' as u16; @@ -351,6 +362,6 @@ pub(crate) fn to_user_path(mut path: Vec) -> io::Result> { ) }, // For everything else, leave the path unchanged. - _ => Ok(path), + _ => get_long_path(path, false), } } diff --git a/library/std/src/sys/windows/path.rs b/library/std/src/sys/windows/path.rs index beeca1917a9a..c3573d14c7f9 100644 --- a/library/std/src/sys/windows/path.rs +++ b/library/std/src/sys/windows/path.rs @@ -220,6 +220,19 @@ fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) { /// /// This path may or may not have a verbatim prefix. pub(crate) fn maybe_verbatim(path: &Path) -> io::Result> { + let path = to_u16s(path)?; + get_long_path(path, true) +} + +/// Get a normalized absolute path that can bypass path length limits. +/// +/// Setting prefer_verbatim to true suggests a stronger preference for verbatim +/// paths even when not strictly necessary. This allows the Windows API to avoid +/// repeating our work. However, if the path may be given back to users or +/// passed to other application then it's preferable to use non-verbatim paths +/// when possible. Non-verbatim paths are better understood by users and handled +/// by more software. +pub(crate) fn get_long_path(mut path: Vec, prefer_verbatim: bool) -> io::Result> { // Normally the MAX_PATH is 260 UTF-16 code units (including the NULL). // However, for APIs such as CreateDirectory[1], the limit is 248. // @@ -243,7 +256,6 @@ pub(crate) fn maybe_verbatim(path: &Path) -> io::Result> { // \\?\UNC\ const UNC_PREFIX: &[u16] = &[SEP, SEP, QUERY, SEP, U, N, C, SEP]; - let mut path = to_u16s(path)?; if path.starts_with(VERBATIM_PREFIX) || path.starts_with(NT_PREFIX) || path == &[0] { // Early return for paths that are already verbatim or empty. return Ok(path); @@ -275,29 +287,34 @@ pub(crate) fn maybe_verbatim(path: &Path) -> io::Result> { |mut absolute| { path.clear(); - // Secondly, add the verbatim prefix. This is easier here because we know the - // path is now absolute and fully normalized (e.g. `/` has been changed to `\`). - let prefix = match absolute { - // C:\ => \\?\C:\ - [_, COLON, SEP, ..] => VERBATIM_PREFIX, - // \\.\ => \\?\ - [SEP, SEP, DOT, SEP, ..] => { - absolute = &absolute[4..]; - VERBATIM_PREFIX - } - // Leave \\?\ and \??\ as-is. - [SEP, SEP, QUERY, SEP, ..] | [SEP, QUERY, QUERY, SEP, ..] => &[], - // \\ => \\?\UNC\ - [SEP, SEP, ..] => { - absolute = &absolute[2..]; - UNC_PREFIX - } - // Anything else we leave alone. - _ => &[], - }; + // Only prepend the prefix if needed. + if prefer_verbatim || absolute.len() + 1 >= LEGACY_MAX_PATH { + // Secondly, add the verbatim prefix. This is easier here because we know the + // path is now absolute and fully normalized (e.g. `/` has been changed to `\`). + let prefix = match absolute { + // C:\ => \\?\C:\ + [_, COLON, SEP, ..] => VERBATIM_PREFIX, + // \\.\ => \\?\ + [SEP, SEP, DOT, SEP, ..] => { + absolute = &absolute[4..]; + VERBATIM_PREFIX + } + // Leave \\?\ and \??\ as-is. + [SEP, SEP, QUERY, SEP, ..] | [SEP, QUERY, QUERY, SEP, ..] => &[], + // \\ => \\?\UNC\ + [SEP, SEP, ..] => { + absolute = &absolute[2..]; + UNC_PREFIX + } + // Anything else we leave alone. + _ => &[], + }; - path.reserve_exact(prefix.len() + absolute.len() + 1); - path.extend_from_slice(prefix); + path.reserve_exact(prefix.len() + absolute.len() + 1); + path.extend_from_slice(prefix); + } else { + path.reserve_exact(absolute.len() + 1); + } path.extend_from_slice(absolute); path.push(0); }, diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs index 9cbb4ef19e9b..82b3f6acde87 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -270,11 +270,7 @@ impl Command { let (program, mut cmd_str) = if is_batch_file { ( command_prompt()?, - args::make_bat_command_line( - &args::to_user_path(program)?, - &self.args, - self.force_quotes_enabled, - )?, + args::make_bat_command_line(&program, &self.args, self.force_quotes_enabled)?, ) } else { let cmd_str = make_command_line(&self.program, &self.args, self.force_quotes_enabled)?; @@ -397,7 +393,7 @@ fn resolve_exe<'a>( if has_exe_suffix { // The application name is a path to a `.exe` file. // Let `CreateProcessW` figure out if it exists or not. - return path::maybe_verbatim(Path::new(exe_path)); + return args::to_user_path(Path::new(exe_path)); } let mut path = PathBuf::from(exe_path); @@ -409,7 +405,7 @@ fn resolve_exe<'a>( // It's ok to use `set_extension` here because the intent is to // remove the extension that was just added. path.set_extension(""); - return path::maybe_verbatim(&path); + return args::to_user_path(&path); } } else { ensure_no_nuls(exe_path)?; @@ -497,7 +493,7 @@ where /// Check if a file exists without following symlinks. fn program_exists(path: &Path) -> Option> { unsafe { - let path = path::maybe_verbatim(path).ok()?; + let path = args::to_user_path(path).ok()?; // Getting attributes using `GetFileAttributesW` does not follow symlinks // and it will almost always be successful if the link exists. // There are some exceptions for special system files (e.g. the pagefile) From 01d6c04875e102f00a7d66a16ea09567dc7bbd97 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Wed, 4 Jan 2023 02:04:31 +0000 Subject: [PATCH 02/70] Link to Option/Result for `Iterator::sum/product` --- library/core/src/iter/traits/iterator.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index fc4d4bff24f3..7645e7d6f736 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -3366,6 +3366,9 @@ pub trait Iterator { /// /// An empty iterator returns the zero value of the type. /// + /// `sum()` can be used to sum any type implementing [`Sum`][`core::iter::Sum`], + /// including [`Option`][`Option::sum`] and [`Result`][`Result::sum`]. + /// /// # Panics /// /// When calling `sum()` and a primitive integer type is being returned, this @@ -3395,6 +3398,9 @@ pub trait Iterator { /// /// An empty iterator returns the one value of the type. /// + /// `product()` can be used to multiply any type implementing [`Product`][`core::iter::Product`], + /// including [`Option`][`Option::product`] and [`Result`][`Result::product`]. + /// /// # Panics /// /// When calling `product()` and a primitive integer type is being returned, From 746331edf3a6d055859ed0ed70dde1aa883c517d Mon Sep 17 00:00:00 2001 From: joboet Date: Fri, 17 Feb 2023 15:47:58 +0100 Subject: [PATCH 03/70] std: drop all messages in bounded channel when destroying the last receiver --- library/std/src/sync/mpmc/array.rs | 132 +++++++++++++++++++++++------ library/std/src/sync/mpmc/mod.rs | 4 +- 2 files changed, 109 insertions(+), 27 deletions(-) diff --git a/library/std/src/sync/mpmc/array.rs b/library/std/src/sync/mpmc/array.rs index c6bb09b0417f..703817600036 100644 --- a/library/std/src/sync/mpmc/array.rs +++ b/library/std/src/sync/mpmc/array.rs @@ -15,7 +15,7 @@ use super::utils::{Backoff, CachePadded}; use super::waker::SyncWaker; use crate::cell::UnsafeCell; -use crate::mem::MaybeUninit; +use crate::mem::{self, MaybeUninit}; use crate::ptr; use crate::sync::atomic::{self, AtomicUsize, Ordering}; use crate::time::Instant; @@ -25,7 +25,8 @@ struct Slot { /// The current stamp. stamp: AtomicUsize, - /// The message in this slot. + /// The message in this slot. Either read out in `read` or dropped through + /// `discard_all_messages`. msg: UnsafeCell>, } @@ -439,14 +440,13 @@ impl Channel { Some(self.cap) } - /// Disconnects the channel and wakes up all blocked senders and receivers. + /// Disconnects senders and wakes up all blocked receivers. /// /// Returns `true` if this call disconnected the channel. - pub(crate) fn disconnect(&self) -> bool { + pub(crate) fn disconnect_senders(&self) -> bool { let tail = self.tail.fetch_or(self.mark_bit, Ordering::SeqCst); if tail & self.mark_bit == 0 { - self.senders.disconnect(); self.receivers.disconnect(); true } else { @@ -454,6 +454,108 @@ impl Channel { } } + /// Disconnects receivers and wakes up all blocked senders. + /// + /// Returns `true` if this call disconnected the channel. + /// + /// # Safety + /// May only be called once upon dropping the last receiver. The + /// destruction of all other receivers must have been observed with acquire + /// ordering or stronger. + pub(crate) unsafe fn disconnect_receivers(&self) -> bool { + let tail = self.tail.fetch_or(self.mark_bit, Ordering::SeqCst); + self.discard_all_messages(tail); + + if tail & self.mark_bit == 0 { + self.senders.disconnect(); + true + } else { + false + } + } + + /// Discards all messages. + /// + /// `tail` should be the current (and therefore last) value of `tail`. + /// + /// # Safety + /// This method must only be called when dropping the last receiver. The + /// destruction of all other receivers must have been observed with acquire + /// ordering or stronger. + unsafe fn discard_all_messages(&self, tail: usize) { + debug_assert!(self.is_disconnected()); + + /// Use a helper struct with a custom `Drop` to ensure all messages are + /// dropped, even if a destructor panicks. + struct DiscardState<'a, T> { + channel: &'a Channel, + head: usize, + tail: usize, + backoff: Backoff, + } + + impl<'a, T> DiscardState<'a, T> { + fn discard(&mut self) { + loop { + // Deconstruct the head. + let index = self.head & (self.channel.mark_bit - 1); + let lap = self.head & !(self.channel.one_lap - 1); + + // Inspect the corresponding slot. + debug_assert!(index < self.channel.buffer.len()); + let slot = unsafe { self.channel.buffer.get_unchecked(index) }; + let stamp = slot.stamp.load(Ordering::Acquire); + + // If the stamp is ahead of the head by 1, we may drop the message. + if self.head + 1 == stamp { + self.head = if index + 1 < self.channel.cap { + // Same lap, incremented index. + // Set to `{ lap: lap, mark: 0, index: index + 1 }`. + self.head + 1 + } else { + // One lap forward, index wraps around to zero. + // Set to `{ lap: lap.wrapping_add(1), mark: 0, index: 0 }`. + lap.wrapping_add(self.channel.one_lap) + }; + + // We updated the head, so even if this descrutor panics, + // we will not attempt to destroy the slot again. + unsafe { + (*slot.msg.get()).assume_init_drop(); + } + // If the tail equals the head, that means the channel is empty. + } else if self.tail == self.head { + return; + // Otherwise, a sender is about to write into the slot, so we need + // to wait for it to update the stamp. + } else { + self.backoff.spin_heavy(); + } + } + } + } + + impl<'a, T> Drop for DiscardState<'a, T> { + fn drop(&mut self) { + self.discard(); + } + } + + let mut state = DiscardState { + channel: self, + // Only receivers modify `head`, so since we are the last one, + // this value will not change and will not be observed (since + // no new messages can be sent after disconnection). + head: self.head.load(Ordering::Relaxed), + tail: tail & !self.mark_bit, + backoff: Backoff::new(), + }; + state.discard(); + // This point is only reached if no destructor panics, so all messages + // have already been dropped. + mem::forget(state); + } + /// Returns `true` if the channel is disconnected. pub(crate) fn is_disconnected(&self) -> bool { self.tail.load(Ordering::SeqCst) & self.mark_bit != 0 @@ -483,23 +585,3 @@ impl Channel { head.wrapping_add(self.one_lap) == tail & !self.mark_bit } } - -impl Drop for Channel { - fn drop(&mut self) { - // Get the index of the head. - let hix = self.head.load(Ordering::Relaxed) & (self.mark_bit - 1); - - // Loop over all slots that hold a message and drop them. - for i in 0..self.len() { - // Compute the index of the next slot holding a message. - let index = if hix + i < self.cap { hix + i } else { hix + i - self.cap }; - - unsafe { - debug_assert!(index < self.buffer.len()); - let slot = self.buffer.get_unchecked_mut(index); - let msg = &mut *slot.msg.get(); - msg.as_mut_ptr().drop_in_place(); - } - } - } -} diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs index 7a602cecd3b8..2068dda393a2 100644 --- a/library/std/src/sync/mpmc/mod.rs +++ b/library/std/src/sync/mpmc/mod.rs @@ -227,7 +227,7 @@ impl Drop for Sender { fn drop(&mut self) { unsafe { match &self.flavor { - SenderFlavor::Array(chan) => chan.release(|c| c.disconnect()), + SenderFlavor::Array(chan) => chan.release(|c| c.disconnect_senders()), SenderFlavor::List(chan) => chan.release(|c| c.disconnect_senders()), SenderFlavor::Zero(chan) => chan.release(|c| c.disconnect()), } @@ -403,7 +403,7 @@ impl Drop for Receiver { fn drop(&mut self) { unsafe { match &self.flavor { - ReceiverFlavor::Array(chan) => chan.release(|c| c.disconnect()), + ReceiverFlavor::Array(chan) => chan.release(|c| c.disconnect_receivers()), ReceiverFlavor::List(chan) => chan.release(|c| c.disconnect_receivers()), ReceiverFlavor::Zero(chan) => chan.release(|c| c.disconnect()), } From 642a3247462a582ee97abea1c06c3fabac3bcb3f Mon Sep 17 00:00:00 2001 From: joboet Date: Fri, 17 Feb 2023 15:58:15 +0100 Subject: [PATCH 04/70] std: add regression test for #107466 Tests that messages are immediately dropped once the last receiver is destroyed. --- library/std/src/sync/mpsc/sync_tests.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/library/std/src/sync/mpsc/sync_tests.rs b/library/std/src/sync/mpsc/sync_tests.rs index 9d2f92ffc9b1..632709fd98d8 100644 --- a/library/std/src/sync/mpsc/sync_tests.rs +++ b/library/std/src/sync/mpsc/sync_tests.rs @@ -1,5 +1,6 @@ use super::*; use crate::env; +use crate::rc::Rc; use crate::sync::mpmc::SendTimeoutError; use crate::thread; use crate::time::Duration; @@ -656,3 +657,15 @@ fn issue_15761() { repro() } } + +#[test] +fn drop_unreceived() { + let (tx, rx) = sync_channel::>(1); + let msg = Rc::new(()); + let weak = Rc::downgrade(&msg); + assert!(tx.send(msg).is_ok()); + drop(rx); + // Messages should be dropped immediately when the last receiver is destroyed. + assert!(weak.upgrade().is_none()); + drop(tx); +} From 738c8b08d5edb4c9fff605533a6b186e57c9596e Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Mon, 16 Jan 2023 23:46:31 -0500 Subject: [PATCH 05/70] Remove the assume(!is_null) from Vec::as_ptr --- library/alloc/src/vec/mod.rs | 13 ++----------- tests/codegen/vec-as-ptr.rs | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 11 deletions(-) create mode 100644 tests/codegen/vec-as-ptr.rs diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index a07f3da78d33..0a20fd9a8ae0 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -59,7 +59,6 @@ use core::cmp::Ordering; use core::convert::TryFrom; use core::fmt; use core::hash::{Hash, Hasher}; -use core::intrinsics::assume; use core::iter; #[cfg(not(no_global_oom_handling))] use core::iter::FromIterator; @@ -1240,11 +1239,7 @@ impl Vec { pub fn as_ptr(&self) -> *const T { // We shadow the slice method of the same name to avoid going through // `deref`, which creates an intermediate reference. - let ptr = self.buf.ptr(); - unsafe { - assume(!ptr.is_null()); - } - ptr + self.buf.ptr() } /// Returns an unsafe mutable pointer to the vector's buffer, or a dangling @@ -1277,11 +1272,7 @@ impl Vec { pub fn as_mut_ptr(&mut self) -> *mut T { // We shadow the slice method of the same name to avoid going through // `deref_mut`, which creates an intermediate reference. - let ptr = self.buf.ptr(); - unsafe { - assume(!ptr.is_null()); - } - ptr + self.buf.ptr() } /// Returns a reference to the underlying allocator. diff --git a/tests/codegen/vec-as-ptr.rs b/tests/codegen/vec-as-ptr.rs new file mode 100644 index 000000000000..8ff7ba9cb64c --- /dev/null +++ b/tests/codegen/vec-as-ptr.rs @@ -0,0 +1,19 @@ +// compile-flags: -O -Zmerge-functions=disabled + +#![crate_type = "lib"] + +// Test that even though we return a *const u8 not a &[u8] or a NonNull, LLVM knows that this +// pointer is nonnull. +// CHECK: nonnull {{i8\*|ptr}} @vec_as_ptr +#[no_mangle] +pub fn vec_as_ptr(v: &Vec) -> *const u8 { + v.as_ptr() +} + +// Test that even though we return a *const u8 not a &[u8] or a NonNull, LLVM knows that this +// pointer is nonnull. +// CHECK: nonnull {{i8\*|ptr}} @vec_as_mut_ptr +#[no_mangle] +pub fn vec_as_mut_ptr(v: &mut Vec) -> *mut u8 { + v.as_mut_ptr() +} From 4e9e465bd4cbdfe3946ea6f0ff4786f2f495a020 Mon Sep 17 00:00:00 2001 From: joboet Date: Sun, 26 Feb 2023 11:57:27 +0100 Subject: [PATCH 06/70] std: disconnect senders before discarding messages --- library/std/src/sync/mpmc/array.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/library/std/src/sync/mpmc/array.rs b/library/std/src/sync/mpmc/array.rs index 703817600036..fb893695a9a5 100644 --- a/library/std/src/sync/mpmc/array.rs +++ b/library/std/src/sync/mpmc/array.rs @@ -464,14 +464,15 @@ impl Channel { /// ordering or stronger. pub(crate) unsafe fn disconnect_receivers(&self) -> bool { let tail = self.tail.fetch_or(self.mark_bit, Ordering::SeqCst); - self.discard_all_messages(tail); - - if tail & self.mark_bit == 0 { + let disconnected = if tail & self.mark_bit == 0 { self.senders.disconnect(); true } else { false - } + }; + + self.discard_all_messages(tail); + disconnected } /// Discards all messages. From d7049cabd0a370ac5af8b4f03ce836b3f9384d98 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 1 Mar 2023 14:47:55 +0100 Subject: [PATCH 07/70] add the --json flag to compiletest --- src/tools/compiletest/src/common.rs | 4 ++-- src/tools/compiletest/src/main.rs | 12 +++++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 7fe2e6257d9e..7691f5c32b21 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -9,7 +9,7 @@ use std::str::FromStr; use crate::util::{add_dylib_path, PathBufExt}; use lazycell::LazyCell; -use test::ColorConfig; +use test::{ColorConfig, OutputFormat}; #[derive(Clone, Copy, PartialEq, Debug)] pub enum Mode { @@ -337,7 +337,7 @@ pub struct Config { pub verbose: bool, /// Print one character per test instead of one line - pub quiet: bool, + pub format: OutputFormat, /// Whether to use colors in test. pub color: ColorConfig, diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 1760c29ec66b..167cd5c5dc17 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -114,6 +114,7 @@ pub fn parse_config(args: Vec) -> Config { ) .optflag("", "quiet", "print one character per test instead of one line") .optopt("", "color", "coloring: auto, always, never", "WHEN") + .optflag("", "json", "emit json output instead of plaintext output") .optopt("", "logfile", "file to log test execution to", "FILE") .optopt("", "target", "the target to build for", "TARGET") .optopt("", "host", "the host to build for", "HOST") @@ -281,7 +282,12 @@ pub fn parse_config(args: Vec) -> Config { && !opt_str2(matches.opt_str("adb-test-dir")).is_empty(), lldb_python_dir: matches.opt_str("lldb-python-dir"), verbose: matches.opt_present("verbose"), - quiet: matches.opt_present("quiet"), + format: match (matches.opt_present("quiet"), matches.opt_present("json")) { + (true, true) => panic!("--quiet and --json are incompatible"), + (true, false) => test::OutputFormat::Terse, + (false, true) => test::OutputFormat::Json, + (false, false) => test::OutputFormat::Pretty, + }, only_modified: matches.opt_present("only-modified"), color, remote_test_client: matches.opt_str("remote-test-client").map(PathBuf::from), @@ -339,7 +345,7 @@ pub fn log_config(config: &Config) { logv(c, format!("ar: {}", config.ar)); logv(c, format!("linker: {:?}", config.linker)); logv(c, format!("verbose: {}", config.verbose)); - logv(c, format!("quiet: {}", config.quiet)); + logv(c, format!("format: {:?}", config.format)); logv(c, "\n".to_string()); } @@ -501,7 +507,7 @@ pub fn test_opts(config: &Config) -> test::TestOpts { filters: config.filters.clone(), filter_exact: config.filter_exact, run_ignored: if config.run_ignored { test::RunIgnored::Yes } else { test::RunIgnored::No }, - format: if config.quiet { test::OutputFormat::Terse } else { test::OutputFormat::Pretty }, + format: config.format, logfile: config.logfile.clone(), run_tests: true, bench_benchmarks: true, From d2f38065f3fb89fb0361c7f1a1a34c070e10297a Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 2 Mar 2023 11:13:48 +0100 Subject: [PATCH 08/70] render compiletest output with render_tests --- src/bootstrap/lib.rs | 1 + src/bootstrap/render_tests.rs | 220 ++++++++++++++++++++++++++++++++++ src/bootstrap/test.rs | 8 +- 3 files changed, 224 insertions(+), 5 deletions(-) create mode 100644 src/bootstrap/render_tests.rs diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index f4abdf1cc575..f10d640a2090 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -55,6 +55,7 @@ mod format; mod install; mod metadata; mod native; +mod render_tests; mod run; mod sanity; mod setup; diff --git a/src/bootstrap/render_tests.rs b/src/bootstrap/render_tests.rs new file mode 100644 index 000000000000..6a0600fb708c --- /dev/null +++ b/src/bootstrap/render_tests.rs @@ -0,0 +1,220 @@ +//! This module renders the JSON output of libtest into a human-readable form, trying to be as +//! similar to libtest's native output as possible. +//! +//! This is needed because we need to use libtest in JSON mode to extract granluar information +//! about the executed tests. Doing so suppresses the human-readable output, and (compared to Cargo +//! and rustc) libtest doesn't include the rendered human-readable output as a JSON field. We had +//! to reimplement all the rendering logic in this module because of that. + +use crate::builder::Builder; +use std::io::{BufRead, BufReader}; +use std::process::{ChildStdout, Command, Stdio}; +use std::time::Duration; + +pub(crate) fn try_run_tests(builder: &Builder<'_>, cmd: &mut Command) -> bool { + if builder.config.dry_run() { + return true; + } + + if !run_tests(builder, cmd) { + if builder.fail_fast { + crate::detail_exit(1); + } else { + let mut failures = builder.delayed_failures.borrow_mut(); + failures.push(format!("{cmd:?}")); + false + } + } else { + true + } +} + +fn run_tests(builder: &Builder<'_>, cmd: &mut Command) -> bool { + cmd.stdout(Stdio::piped()); + + builder.verbose(&format!("running: {cmd:?}")); + + let mut process = cmd.spawn().unwrap(); + let stdout = process.stdout.take().unwrap(); + let handle = std::thread::spawn(move || Renderer::new(stdout).render_all()); + + let result = process.wait().unwrap(); + handle.join().expect("test formatter thread failed"); + + if !result.success() && builder.is_verbose() { + println!( + "\n\ncommand did not execute successfully: {cmd:?}\n\ + expected success, got: {result}" + ); + } + + result.success() +} + +struct Renderer { + stdout: BufReader, + failures: Vec, +} + +impl Renderer { + fn new(stdout: ChildStdout) -> Self { + Self { stdout: BufReader::new(stdout), failures: Vec::new() } + } + + fn render_all(mut self) { + let mut line = String::new(); + loop { + line.clear(); + match self.stdout.read_line(&mut line) { + Ok(_) => {} + Err(err) if err.kind() == std::io::ErrorKind::UnexpectedEof => break, + Err(err) => panic!("failed to read output of test runner: {err}"), + } + if line.is_empty() { + break; + } + + self.render_message(match serde_json::from_str(&line) { + Ok(parsed) => parsed, + Err(err) => { + panic!("failed to parse libtest json output; error: {err}, line: {line:?}"); + } + }); + } + } + + fn render_test_outcome(&self, outcome: Outcome<'_>, test: &TestOutcome) { + // TODO: add support for terse output + self.render_test_outcome_verbose(outcome, test); + } + + fn render_test_outcome_verbose(&self, outcome: Outcome<'_>, test: &TestOutcome) { + if let Some(exec_time) = test.exec_time { + println!( + "test {} ... {outcome} (in {:.2?})", + test.name, + Duration::from_secs_f64(exec_time) + ); + } else { + println!("test {} ... {outcome}", test.name); + } + } + + fn render_suite_outcome(&self, outcome: Outcome<'_>, suite: &SuiteOutcome) { + if !self.failures.is_empty() { + println!("\nfailures:\n"); + for failure in &self.failures { + if let Some(stdout) = &failure.stdout { + println!("---- {} stdout ----", failure.name); + println!("{stdout}"); + } + } + + println!("\nfailures:"); + for failure in &self.failures { + println!(" {}", failure.name); + } + } + + println!( + "\ntest result: {outcome}. {} passed; {} failed; {} ignored; {} measured; \ + {} filtered out; finished in {:.2?}\n", + suite.passed, + suite.failed, + suite.ignored, + suite.measured, + suite.filtered_out, + Duration::from_secs_f64(suite.exec_time) + ); + } + + fn render_message(&mut self, message: Message) { + match message { + Message::Suite(SuiteMessage::Started { test_count }) => { + println!("\nrunning {test_count} tests"); + } + Message::Suite(SuiteMessage::Ok(outcome)) => { + self.render_suite_outcome(Outcome::Ok, &outcome); + } + Message::Suite(SuiteMessage::Failed(outcome)) => { + self.render_suite_outcome(Outcome::Failed, &outcome); + } + Message::Test(TestMessage::Ok(outcome)) => { + self.render_test_outcome(Outcome::Ok, &outcome); + } + Message::Test(TestMessage::Ignored(outcome)) => { + self.render_test_outcome( + Outcome::Ignored { reason: outcome.reason.as_deref() }, + &outcome, + ); + } + Message::Test(TestMessage::Failed(outcome)) => { + self.render_test_outcome(Outcome::Failed, &outcome); + self.failures.push(outcome); + } + Message::Test(TestMessage::Started) => {} // Not useful + Message::Test(TestMessage::Bench) => todo!("benchmarks are not supported yet"), + } + } +} + +enum Outcome<'a> { + Ok, + Failed, + Ignored { reason: Option<&'a str> }, +} + +impl std::fmt::Display for Outcome<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Outcome::Ok => f.write_str("ok"), + Outcome::Failed => f.write_str("FAILED"), + Outcome::Ignored { reason: None } => f.write_str("ignored"), + Outcome::Ignored { reason: Some(reason) } => write!(f, "ignored, {reason}"), + } + } +} + +#[derive(serde_derive::Deserialize)] +#[serde(tag = "type", rename_all = "snake_case")] +enum Message { + Suite(SuiteMessage), + Test(TestMessage), +} + +#[derive(serde_derive::Deserialize)] +#[serde(tag = "event", rename_all = "snake_case")] +enum SuiteMessage { + Ok(SuiteOutcome), + Failed(SuiteOutcome), + Started { test_count: usize }, +} + +#[derive(serde_derive::Deserialize)] +struct SuiteOutcome { + passed: usize, + failed: usize, + ignored: usize, + measured: usize, + filtered_out: usize, + exec_time: f64, +} + +#[derive(serde_derive::Deserialize)] +#[serde(tag = "event", rename_all = "snake_case")] +enum TestMessage { + Ok(TestOutcome), + Failed(TestOutcome), + Ignored(TestOutcome), + // Ignored messages: + Bench, + Started, +} + +#[derive(serde_derive::Deserialize)] +struct TestOutcome { + name: String, + exec_time: Option, + stdout: Option, + reason: Option, +} diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index b4f1506dc8f3..1576326dfb04 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1616,9 +1616,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the cmd.arg("--verbose"); } - if !builder.config.verbose_tests { - cmd.arg("--quiet"); - } + cmd.arg("--json"); let mut llvm_components_passed = false; let mut copts_passed = false; @@ -1769,7 +1767,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the suite, mode, &compiler.host, target )); let _time = util::timeit(&builder); - try_run(builder, &mut cmd); + crate::render_tests::try_run_tests(builder, &mut cmd); if let Some(compare_mode) = compare_mode { cmd.arg("--compare-mode").arg(compare_mode); @@ -1778,7 +1776,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the suite, mode, compare_mode, &compiler.host, target )); let _time = util::timeit(&builder); - try_run(builder, &mut cmd); + crate::render_tests::try_run_tests(builder, &mut cmd); } } } From f96774bfbb0cfcb9d52d9bd0c0d14f30d3409232 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 2 Mar 2023 11:30:14 +0100 Subject: [PATCH 09/70] add support for terse output --- src/bootstrap/render_tests.rs | 63 +++++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/src/bootstrap/render_tests.rs b/src/bootstrap/render_tests.rs index 6a0600fb708c..ae2147f7550f 100644 --- a/src/bootstrap/render_tests.rs +++ b/src/bootstrap/render_tests.rs @@ -7,10 +7,12 @@ //! to reimplement all the rendering logic in this module because of that. use crate::builder::Builder; -use std::io::{BufRead, BufReader}; +use std::io::{BufRead, BufReader, Write}; use std::process::{ChildStdout, Command, Stdio}; use std::time::Duration; +const TERSE_TESTS_PER_LINE: usize = 88; + pub(crate) fn try_run_tests(builder: &Builder<'_>, cmd: &mut Command) -> bool { if builder.config.dry_run() { return true; @@ -36,7 +38,8 @@ fn run_tests(builder: &Builder<'_>, cmd: &mut Command) -> bool { let mut process = cmd.spawn().unwrap(); let stdout = process.stdout.take().unwrap(); - let handle = std::thread::spawn(move || Renderer::new(stdout).render_all()); + let verbose = builder.config.verbose_tests; + let handle = std::thread::spawn(move || Renderer::new(stdout, verbose).render_all()); let result = process.wait().unwrap(); handle.join().expect("test formatter thread failed"); @@ -54,11 +57,22 @@ fn run_tests(builder: &Builder<'_>, cmd: &mut Command) -> bool { struct Renderer { stdout: BufReader, failures: Vec, + verbose: bool, + tests_count: Option, + executed_tests: usize, + terse_tests_in_line: usize, } impl Renderer { - fn new(stdout: ChildStdout) -> Self { - Self { stdout: BufReader::new(stdout), failures: Vec::new() } + fn new(stdout: ChildStdout, verbose: bool) -> Self { + Self { + stdout: BufReader::new(stdout), + failures: Vec::new(), + verbose, + tests_count: None, + executed_tests: 0, + terse_tests_in_line: 0, + } } fn render_all(mut self) { @@ -83,9 +97,13 @@ impl Renderer { } } - fn render_test_outcome(&self, outcome: Outcome<'_>, test: &TestOutcome) { - // TODO: add support for terse output - self.render_test_outcome_verbose(outcome, test); + fn render_test_outcome(&mut self, outcome: Outcome<'_>, test: &TestOutcome) { + self.executed_tests += 1; + if self.verbose { + self.render_test_outcome_verbose(outcome, test); + } else { + self.render_test_outcome_terse(outcome, test); + } } fn render_test_outcome_verbose(&self, outcome: Outcome<'_>, test: &TestOutcome) { @@ -100,7 +118,35 @@ impl Renderer { } } + fn render_test_outcome_terse(&mut self, outcome: Outcome<'_>, _: &TestOutcome) { + if self.terse_tests_in_line != 0 && self.terse_tests_in_line % TERSE_TESTS_PER_LINE == 0 { + if let Some(total) = self.tests_count { + let total = total.to_string(); + let executed = format!("{:>width$}", self.executed_tests - 1, width = total.len()); + print!(" {executed}/{total}"); + } + println!(); + self.terse_tests_in_line = 0; + } + + self.terse_tests_in_line += 1; + print!( + "{}", + match outcome { + Outcome::Ok => ".", + Outcome::Failed => "F", + Outcome::Ignored { .. } => "i", + } + ); + let _ = std::io::stdout().flush(); + } + fn render_suite_outcome(&self, outcome: Outcome<'_>, suite: &SuiteOutcome) { + // The terse output doesn't end with a newline, so we need to add it ourselves. + if !self.verbose { + println!(); + } + if !self.failures.is_empty() { println!("\nfailures:\n"); for failure in &self.failures { @@ -132,6 +178,9 @@ impl Renderer { match message { Message::Suite(SuiteMessage::Started { test_count }) => { println!("\nrunning {test_count} tests"); + self.executed_tests = 0; + self.terse_tests_in_line = 0; + self.tests_count = Some(test_count); } Message::Suite(SuiteMessage::Ok(outcome)) => { self.render_suite_outcome(Outcome::Ok, &outcome); From f816d3a75479ba073570a4e998735be28770a307 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 2 Mar 2023 12:23:14 +0100 Subject: [PATCH 10/70] add a splash of color --- src/bootstrap/Cargo.lock | 22 ++++++++++++ src/bootstrap/Cargo.toml | 2 ++ src/bootstrap/config.rs | 6 ++++ src/bootstrap/lib.rs | 18 ++++++++++ src/bootstrap/render_tests.rs | 63 +++++++++++++++++++---------------- 5 files changed, 82 insertions(+), 29 deletions(-) diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index e861d520c534..8195823efaff 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -11,6 +11,17 @@ dependencies = [ "memchr", ] +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -36,6 +47,7 @@ dependencies = [ name = "bootstrap" version = "0.0.0" dependencies = [ + "atty", "build_helper", "cc", "cmake", @@ -59,6 +71,7 @@ dependencies = [ "walkdir", "winapi", "xz2", + "yansi-term", ] [[package]] @@ -800,3 +813,12 @@ name = "yansi" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + +[[package]] +name = "yansi-term" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1" +dependencies = [ + "winapi", +] diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 663987f113c8..e704799867b3 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -30,6 +30,7 @@ path = "bin/sccache-plus-cl.rs" test = false [dependencies] +atty = "0.2.14" build_helper = { path = "../tools/build_helper" } cmake = "0.1.38" fd-lock = "3.0.8" @@ -52,6 +53,7 @@ opener = "0.5" once_cell = "1.7.2" xz2 = "0.1" walkdir = "2" +yansi-term = "0.1.2" # Dependencies needed by the build-metrics feature sysinfo = { version = "0.26.0", optional = true } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 05e742549499..bfa237aa14d8 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -87,6 +87,9 @@ pub struct Config { pub patch_binaries_for_nix: bool, pub stage0_metadata: Stage0Metadata, + pub stdout_is_tty: bool, + pub stderr_is_tty: bool, + pub on_fail: Option, pub stage: u32, pub keep_stage: Vec, @@ -822,6 +825,9 @@ impl Config { config.deny_warnings = true; config.bindir = "bin".into(); + config.stdout_is_tty = atty::is(atty::Stream::Stdout); + config.stderr_is_tty = atty::is(atty::Stream::Stderr); + // set by build.rs config.build = TargetSelection::from_user(&env!("BUILD_TRIPLE")); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index f10d640a2090..0eff8769b609 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -89,6 +89,7 @@ pub use crate::builder::PathSet; use crate::cache::{Interned, INTERNER}; pub use crate::config::Config; pub use crate::flags::Subcommand; +use yansi_term::Color; const LLVM_TOOLS: &[&str] = &[ "llvm-cov", // used to generate coverage report @@ -1575,6 +1576,23 @@ to download LLVM rather than building it. self.config.ninja_in_file } + + pub fn color_for_stdout(&self, color: Color, message: &str) -> String { + self.color_for_inner(color, message, self.config.stdout_is_tty) + } + + pub fn color_for_stderr(&self, color: Color, message: &str) -> String { + self.color_for_inner(color, message, self.config.stderr_is_tty) + } + + fn color_for_inner(&self, color: Color, message: &str, is_tty: bool) -> String { + let use_color = match self.config.color { + flags::Color::Always => true, + flags::Color::Never => false, + flags::Color::Auto => is_tty, + }; + if use_color { color.paint(message).to_string() } else { message.to_string() } + } } #[cfg(unix)] diff --git a/src/bootstrap/render_tests.rs b/src/bootstrap/render_tests.rs index ae2147f7550f..b5ab486f3ac6 100644 --- a/src/bootstrap/render_tests.rs +++ b/src/bootstrap/render_tests.rs @@ -10,6 +10,7 @@ use crate::builder::Builder; use std::io::{BufRead, BufReader, Write}; use std::process::{ChildStdout, Command, Stdio}; use std::time::Duration; +use yansi_term::Color; const TERSE_TESTS_PER_LINE: usize = 88; @@ -37,13 +38,12 @@ fn run_tests(builder: &Builder<'_>, cmd: &mut Command) -> bool { builder.verbose(&format!("running: {cmd:?}")); let mut process = cmd.spawn().unwrap(); - let stdout = process.stdout.take().unwrap(); - let verbose = builder.config.verbose_tests; - let handle = std::thread::spawn(move || Renderer::new(stdout, verbose).render_all()); + + // This runs until the stdout of the child is closed, which means the child exited. We don't + // run this on another thread since the builder is not Sync. + Renderer::new(process.stdout.take().unwrap(), builder).render_all(); let result = process.wait().unwrap(); - handle.join().expect("test formatter thread failed"); - if !result.success() && builder.is_verbose() { println!( "\n\ncommand did not execute successfully: {cmd:?}\n\ @@ -54,21 +54,21 @@ fn run_tests(builder: &Builder<'_>, cmd: &mut Command) -> bool { result.success() } -struct Renderer { +struct Renderer<'a> { stdout: BufReader, failures: Vec, - verbose: bool, + builder: &'a Builder<'a>, tests_count: Option, executed_tests: usize, terse_tests_in_line: usize, } -impl Renderer { - fn new(stdout: ChildStdout, verbose: bool) -> Self { +impl<'a> Renderer<'a> { + fn new(stdout: ChildStdout, builder: &'a Builder<'a>) -> Self { Self { stdout: BufReader::new(stdout), failures: Vec::new(), - verbose, + builder, tests_count: None, executed_tests: 0, terse_tests_in_line: 0, @@ -99,7 +99,7 @@ impl Renderer { fn render_test_outcome(&mut self, outcome: Outcome<'_>, test: &TestOutcome) { self.executed_tests += 1; - if self.verbose { + if self.builder.config.verbose_tests { self.render_test_outcome_verbose(outcome, test); } else { self.render_test_outcome_terse(outcome, test); @@ -109,12 +109,13 @@ impl Renderer { fn render_test_outcome_verbose(&self, outcome: Outcome<'_>, test: &TestOutcome) { if let Some(exec_time) = test.exec_time { println!( - "test {} ... {outcome} (in {:.2?})", + "test {} ... {} (in {:.2?})", test.name, + outcome.long(self.builder), Duration::from_secs_f64(exec_time) ); } else { - println!("test {} ... {outcome}", test.name); + println!("test {} ... {}", test.name, outcome.long(self.builder)); } } @@ -130,20 +131,13 @@ impl Renderer { } self.terse_tests_in_line += 1; - print!( - "{}", - match outcome { - Outcome::Ok => ".", - Outcome::Failed => "F", - Outcome::Ignored { .. } => "i", - } - ); + print!("{}", outcome.short(self.builder)); let _ = std::io::stdout().flush(); } fn render_suite_outcome(&self, outcome: Outcome<'_>, suite: &SuiteOutcome) { // The terse output doesn't end with a newline, so we need to add it ourselves. - if !self.verbose { + if !self.builder.config.verbose_tests { println!(); } @@ -163,8 +157,9 @@ impl Renderer { } println!( - "\ntest result: {outcome}. {} passed; {} failed; {} ignored; {} measured; \ + "\ntest result: {}. {} passed; {} failed; {} ignored; {} measured; \ {} filtered out; finished in {:.2?}\n", + outcome.long(self.builder), suite.passed, suite.failed, suite.ignored, @@ -213,13 +208,23 @@ enum Outcome<'a> { Ignored { reason: Option<&'a str> }, } -impl std::fmt::Display for Outcome<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl Outcome<'_> { + fn short(&self, builder: &Builder<'_>) -> String { match self { - Outcome::Ok => f.write_str("ok"), - Outcome::Failed => f.write_str("FAILED"), - Outcome::Ignored { reason: None } => f.write_str("ignored"), - Outcome::Ignored { reason: Some(reason) } => write!(f, "ignored, {reason}"), + Outcome::Ok => builder.color_for_stdout(Color::Green, "."), + Outcome::Failed => builder.color_for_stdout(Color::Red, "F"), + Outcome::Ignored { .. } => builder.color_for_stdout(Color::Yellow, "i"), + } + } + + fn long(&self, builder: &Builder<'_>) -> String { + match self { + Outcome::Ok => builder.color_for_stdout(Color::Green, "ok"), + Outcome::Failed => builder.color_for_stdout(Color::Red, "FAILED"), + Outcome::Ignored { reason: None } => builder.color_for_stdout(Color::Yellow, "ignored"), + Outcome::Ignored { reason: Some(reason) } => { + builder.color_for_stdout(Color::Yellow, &format!("ignored, {reason}")) + } } } } From 9388c8e420d780b95c1286d0b17eed9b5446ee9a Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 2 Mar 2023 13:00:46 +0100 Subject: [PATCH 11/70] record tests in build metrics --- src/bootstrap/metrics.rs | 44 +++++++++++++++++++++++++++++++---- src/bootstrap/render_tests.rs | 13 +++++++++++ 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/metrics.rs b/src/bootstrap/metrics.rs index 2e62c950709d..5f254761aa19 100644 --- a/src/bootstrap/metrics.rs +++ b/src/bootstrap/metrics.rs @@ -51,6 +51,7 @@ impl BuildMetrics { duration_excluding_children_sec: Duration::ZERO, children: Vec::new(), + tests: Vec::new(), }); } @@ -72,6 +73,16 @@ impl BuildMetrics { } } + pub(crate) fn record_test(&self, name: &str, outcome: TestOutcome) { + let mut state = self.state.borrow_mut(); + state + .running_steps + .last_mut() + .unwrap() + .tests + .push(Test { name: name.to_string(), outcome }); + } + fn collect_stats(&self, state: &mut MetricsState) { let step = state.running_steps.last_mut().unwrap(); @@ -125,6 +136,14 @@ impl BuildMetrics { } fn prepare_json_step(&self, step: StepMetrics) -> JsonNode { + let mut children = Vec::new(); + children.extend(step.children.into_iter().map(|child| self.prepare_json_step(child))); + children.extend( + step.tests + .into_iter() + .map(|test| JsonNode::Test { name: test.name, outcome: test.outcome }), + ); + JsonNode::RustbuildStep { type_: step.type_, debug_repr: step.debug_repr, @@ -135,11 +154,7 @@ impl BuildMetrics { / step.duration_excluding_children_sec.as_secs_f64(), }, - children: step - .children - .into_iter() - .map(|child| self.prepare_json_step(child)) - .collect(), + children, } } } @@ -161,6 +176,12 @@ struct StepMetrics { duration_excluding_children_sec: Duration, children: Vec, + tests: Vec, +} + +struct Test { + name: String, + outcome: TestOutcome, } #[derive(Serialize, Deserialize)] @@ -190,6 +211,19 @@ enum JsonNode { children: Vec, }, + Test { + name: String, + #[serde(flatten)] + outcome: TestOutcome, + }, +} + +#[derive(Serialize, Deserialize)] +#[serde(tag = "outcome", rename_all = "snake_case")] +pub(crate) enum TestOutcome { + Passed, + Failed, + Ignored { ignore_reason: Option }, } #[derive(Serialize, Deserialize)] diff --git a/src/bootstrap/render_tests.rs b/src/bootstrap/render_tests.rs index b5ab486f3ac6..7c702f19c09f 100644 --- a/src/bootstrap/render_tests.rs +++ b/src/bootstrap/render_tests.rs @@ -99,6 +99,19 @@ impl<'a> Renderer<'a> { fn render_test_outcome(&mut self, outcome: Outcome<'_>, test: &TestOutcome) { self.executed_tests += 1; + + #[cfg(feature = "build-metrics")] + self.builder.metrics.record_test( + &test.name, + match outcome { + Outcome::Ok => crate::metrics::TestOutcome::Passed, + Outcome::Failed => crate::metrics::TestOutcome::Failed, + Outcome::Ignored { reason } => crate::metrics::TestOutcome::Ignored { + ignore_reason: reason.map(|s| s.to_string()), + }, + }, + ); + if self.builder.config.verbose_tests { self.render_test_outcome_verbose(outcome, test); } else { From b14b35555022b6df2fd6192693800f2032f61a33 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 2 Mar 2023 14:50:01 +0100 Subject: [PATCH 12/70] add support for benchmarks --- src/bootstrap/render_tests.rs | 53 ++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/render_tests.rs b/src/bootstrap/render_tests.rs index 7c702f19c09f..bc16ed9cbaf5 100644 --- a/src/bootstrap/render_tests.rs +++ b/src/bootstrap/render_tests.rs @@ -57,6 +57,7 @@ fn run_tests(builder: &Builder<'_>, cmd: &mut Command) -> bool { struct Renderer<'a> { stdout: BufReader, failures: Vec, + benches: Vec, builder: &'a Builder<'a>, tests_count: Option, executed_tests: usize, @@ -67,6 +68,7 @@ impl<'a> Renderer<'a> { fn new(stdout: ChildStdout, builder: &'a Builder<'a>) -> Self { Self { stdout: BufReader::new(stdout), + benches: Vec::new(), failures: Vec::new(), builder, tests_count: None, @@ -104,7 +106,7 @@ impl<'a> Renderer<'a> { self.builder.metrics.record_test( &test.name, match outcome { - Outcome::Ok => crate::metrics::TestOutcome::Passed, + Outcome::Ok | Outcome::BenchOk => crate::metrics::TestOutcome::Passed, Outcome::Failed => crate::metrics::TestOutcome::Failed, Outcome::Ignored { reason } => crate::metrics::TestOutcome::Ignored { ignore_reason: reason.map(|s| s.to_string()), @@ -169,6 +171,26 @@ impl<'a> Renderer<'a> { } } + if !self.benches.is_empty() { + println!("\nbenchmarks:"); + + let mut rows = Vec::new(); + for bench in &self.benches { + rows.push(( + &bench.name, + format!("{:.2?}/iter", Duration::from_nanos(bench.median)), + format!("+/- {:.2?}", Duration::from_nanos(bench.deviation)), + )); + } + + let max_0 = rows.iter().map(|r| r.0.len()).max().unwrap_or(0); + let max_1 = rows.iter().map(|r| r.1.len()).max().unwrap_or(0); + let max_2 = rows.iter().map(|r| r.2.len()).max().unwrap_or(0); + for row in &rows { + println!(" {:max_1$} {:>max_2$}", row.0, row.1, row.2); + } + } + println!( "\ntest result: {}. {} passed; {} failed; {} ignored; {} measured; \ {} filtered out; finished in {:.2?}\n", @@ -196,6 +218,21 @@ impl<'a> Renderer<'a> { Message::Suite(SuiteMessage::Failed(outcome)) => { self.render_suite_outcome(Outcome::Failed, &outcome); } + Message::Bench(outcome) => { + // The formatting for benchmarks doesn't replicate 1:1 the formatting libtest + // outputs, mostly because libtest's formatting is broken in terse mode, which is + // the default used by our monorepo. We use a different formatting instead: + // successful benchmarks are just showed as "benchmarked"/"b", and the details are + // outputted at the bottom like failures. + let fake_test_outcome = TestOutcome { + name: outcome.name.clone(), + exec_time: None, + stdout: None, + reason: None, + }; + self.render_test_outcome(Outcome::BenchOk, &fake_test_outcome); + self.benches.push(outcome); + } Message::Test(TestMessage::Ok(outcome)) => { self.render_test_outcome(Outcome::Ok, &outcome); } @@ -210,13 +247,13 @@ impl<'a> Renderer<'a> { self.failures.push(outcome); } Message::Test(TestMessage::Started) => {} // Not useful - Message::Test(TestMessage::Bench) => todo!("benchmarks are not supported yet"), } } } enum Outcome<'a> { Ok, + BenchOk, Failed, Ignored { reason: Option<&'a str> }, } @@ -225,6 +262,7 @@ impl Outcome<'_> { fn short(&self, builder: &Builder<'_>) -> String { match self { Outcome::Ok => builder.color_for_stdout(Color::Green, "."), + Outcome::BenchOk => builder.color_for_stdout(Color::Cyan, "b"), Outcome::Failed => builder.color_for_stdout(Color::Red, "F"), Outcome::Ignored { .. } => builder.color_for_stdout(Color::Yellow, "i"), } @@ -233,6 +271,7 @@ impl Outcome<'_> { fn long(&self, builder: &Builder<'_>) -> String { match self { Outcome::Ok => builder.color_for_stdout(Color::Green, "ok"), + Outcome::BenchOk => builder.color_for_stdout(Color::Cyan, "benchmarked"), Outcome::Failed => builder.color_for_stdout(Color::Red, "FAILED"), Outcome::Ignored { reason: None } => builder.color_for_stdout(Color::Yellow, "ignored"), Outcome::Ignored { reason: Some(reason) } => { @@ -247,6 +286,7 @@ impl Outcome<'_> { enum Message { Suite(SuiteMessage), Test(TestMessage), + Bench(BenchOutcome), } #[derive(serde_derive::Deserialize)] @@ -273,11 +313,16 @@ enum TestMessage { Ok(TestOutcome), Failed(TestOutcome), Ignored(TestOutcome), - // Ignored messages: - Bench, Started, } +#[derive(serde_derive::Deserialize)] +struct BenchOutcome { + name: String, + median: u64, + deviation: u64, +} + #[derive(serde_derive::Deserialize)] struct TestOutcome { name: String, From 50b35836956bd39e4bb3144b9139317bc84caf4e Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 2 Mar 2023 15:36:13 +0100 Subject: [PATCH 13/70] switch all tests to use render_tests --- src/bootstrap/render_tests.rs | 9 ++++++++ src/bootstrap/test.rs | 41 +++++++++++++++-------------------- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/src/bootstrap/render_tests.rs b/src/bootstrap/render_tests.rs index bc16ed9cbaf5..b9aa378064c0 100644 --- a/src/bootstrap/render_tests.rs +++ b/src/bootstrap/render_tests.rs @@ -14,6 +14,15 @@ use yansi_term::Color; const TERSE_TESTS_PER_LINE: usize = 88; +pub(crate) fn add_flags_and_try_run_tests(builder: &Builder<'_>, cmd: &mut Command) -> bool { + if cmd.get_args().position(|arg| arg == "--").is_none() { + cmd.arg("--"); + } + cmd.args(&["-Z", "unstable-options", "--format", "json"]); + + try_run_tests(builder, cmd) +} + pub(crate) fn try_run_tests(builder: &Builder<'_>, cmd: &mut Command) -> bool { if builder.config.dry_run() { return true; diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 1576326dfb04..754bd6c9c8ce 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -20,6 +20,7 @@ use crate::dist; use crate::doc::DocumentationFormat; use crate::flags::Subcommand; use crate::native; +use crate::render_tests::add_flags_and_try_run_tests; use crate::tool::{self, SourceType, Tool}; use crate::toolstate::ToolState; use crate::util::{self, add_link_lib_path, dylib_path, dylib_path_var, output, t}; @@ -123,7 +124,7 @@ impl Step for CrateJsonDocLint { SourceType::InTree, &[], ); - try_run(builder, &mut cargo.into()); + add_flags_and_try_run_tests(builder, &mut cargo.into()); } } @@ -172,7 +173,7 @@ You can skip linkcheck with --exclude src/tools/linkchecker" SourceType::InTree, &[], ); - try_run(builder, &mut cargo.into()); + add_flags_and_try_run_tests(builder, &mut cargo.into()); // Build all the default documentation. builder.default_doc(&[]); @@ -333,7 +334,7 @@ impl Step for Cargo { cargo.env("PATH", &path_for_cargo(builder, compiler)); - try_run(builder, &mut cargo.into()); + add_flags_and_try_run_tests(builder, &mut cargo.into()); } } @@ -392,7 +393,7 @@ impl Step for RustAnalyzer { cargo.add_rustc_lib_path(builder, compiler); cargo.arg("--").args(builder.config.cmd.test_args()); - builder.run(&mut cargo.into()); + add_flags_and_try_run_tests(builder, &mut cargo.into()); } } @@ -445,7 +446,7 @@ impl Step for Rustfmt { cargo.add_rustc_lib_path(builder, compiler); - builder.run(&mut cargo.into()); + add_flags_and_try_run_tests(builder, &mut cargo.into()); } } @@ -496,7 +497,7 @@ impl Step for RustDemangler { cargo.add_rustc_lib_path(builder, compiler); - builder.run(&mut cargo.into()); + add_flags_and_try_run_tests(builder, &mut cargo.into()); } } @@ -637,8 +638,7 @@ impl Step for Miri { // Forward test filters. cargo.arg("--").args(builder.config.cmd.test_args()); - let mut cargo = Command::from(cargo); - builder.run(&mut cargo); + add_flags_and_try_run_tests(builder, &mut cargo.into()); // # Run `cargo miri test`. // This is just a smoke test (Miri's own CI invokes this in a bunch of different ways and ensures @@ -711,7 +711,7 @@ impl Step for CompiletestTest { ); cargo.allow_features("test"); - try_run(builder, &mut cargo.into()); + add_flags_and_try_run_tests(builder, &mut cargo.into()); } } @@ -767,7 +767,7 @@ impl Step for Clippy { cargo.add_rustc_lib_path(builder, compiler); - if builder.try_run(&mut cargo.into()) { + if add_flags_and_try_run_tests(builder, &mut cargo.into()) { // The tests succeeded; nothing to do. return; } @@ -1189,7 +1189,7 @@ impl Step for TidySelfTest { SourceType::InTree, &[], ); - try_run(builder, &mut cargo.into()); + add_flags_and_try_run_tests(builder, &mut cargo.into()); } } @@ -2178,9 +2178,8 @@ impl Step for Crate { cargo.arg("--"); cargo.args(&builder.config.cmd.test_args()); - if !builder.config.verbose_tests { - cargo.arg("--quiet"); - } + cargo.arg("-Z").arg("unstable-options"); + cargo.arg("--format").arg("json"); if target.contains("emscripten") { cargo.env( @@ -2208,7 +2207,7 @@ impl Step for Crate { target )); let _time = util::timeit(&builder); - try_run(builder, &mut cargo.into()); + crate::render_tests::try_run_tests(builder, &mut cargo.into()); } } @@ -2328,7 +2327,7 @@ impl Step for CrateRustdoc { )); let _time = util::timeit(&builder); - try_run(builder, &mut cargo.into()); + add_flags_and_try_run_tests(builder, &mut cargo.into()); } } @@ -2389,17 +2388,13 @@ impl Step for CrateRustdocJsonTypes { cargo.arg("'-Ctarget-feature=-crt-static'"); } - if !builder.config.verbose_tests { - cargo.arg("--quiet"); - } - builder.info(&format!( "{} rustdoc-json-types stage{} ({} -> {})", test_kind, compiler.stage, &compiler.host, target )); let _time = util::timeit(&builder); - try_run(builder, &mut cargo.into()); + add_flags_and_try_run_tests(builder, &mut cargo.into()); } } @@ -2568,7 +2563,7 @@ impl Step for Bootstrap { // rustbuild tests are racy on directory creation so just run them one at a time. // Since there's not many this shouldn't be a problem. cmd.arg("--test-threads=1"); - try_run(builder, &mut cmd); + add_flags_and_try_run_tests(builder, &mut cmd); } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -2649,7 +2644,7 @@ impl Step for ReplacePlaceholderTest { SourceType::InTree, &[], ); - try_run(builder, &mut cargo.into()); + add_flags_and_try_run_tests(builder, &mut cargo.into()); } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { From ad9a4442418deb24cbb107d0a56026d005bfa859 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 2 Mar 2023 16:20:18 +0100 Subject: [PATCH 14/70] avoid overlapping stderr --- src/bootstrap/render_tests.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/render_tests.rs b/src/bootstrap/render_tests.rs index b9aa378064c0..bdcd39e6b83e 100644 --- a/src/bootstrap/render_tests.rs +++ b/src/bootstrap/render_tests.rs @@ -7,7 +7,7 @@ //! to reimplement all the rendering logic in this module because of that. use crate::builder::Builder; -use std::io::{BufRead, BufReader, Write}; +use std::io::{BufRead, BufReader, Cursor, Write}; use std::process::{ChildStdout, Command, Stdio}; use std::time::Duration; use yansi_term::Color; @@ -43,6 +43,7 @@ pub(crate) fn try_run_tests(builder: &Builder<'_>, cmd: &mut Command) -> bool { fn run_tests(builder: &Builder<'_>, cmd: &mut Command) -> bool { cmd.stdout(Stdio::piped()); + cmd.stderr(Stdio::piped()); builder.verbose(&format!("running: {cmd:?}")); @@ -52,15 +53,20 @@ fn run_tests(builder: &Builder<'_>, cmd: &mut Command) -> bool { // run this on another thread since the builder is not Sync. Renderer::new(process.stdout.take().unwrap(), builder).render_all(); - let result = process.wait().unwrap(); - if !result.success() && builder.is_verbose() { + let result = process.wait_with_output().unwrap(); + if !result.status.success() && builder.is_verbose() { println!( "\n\ncommand did not execute successfully: {cmd:?}\n\ - expected success, got: {result}" + expected success, got: {}", + result.status ); } - result.success() + // Show the stderr emitted by the test runner at the end. As of 2023-03-02 this is only the + // message at the end of a failed compiletest run. + std::io::copy(&mut Cursor::new(&result.stderr), &mut std::io::stderr().lock()).unwrap(); + + result.status.success() } struct Renderer<'a> { From f23e20569c5beedc3739e97d8a43bc9a53b9e3c9 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 2 Mar 2023 17:10:29 +0100 Subject: [PATCH 15/70] do not use render_tests for clippy Behind the scenes Clippy uses compiletest-rs, which doesn't support the --json flag we added to Rust's compiletest. --- src/bootstrap/test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 754bd6c9c8ce..71e83e741e12 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -767,7 +767,7 @@ impl Step for Clippy { cargo.add_rustc_lib_path(builder, compiler); - if add_flags_and_try_run_tests(builder, &mut cargo.into()) { + if builder.try_run(&mut cargo.into()) { // The tests succeeded; nothing to do. return; } From 9a1ff1b95808c6639b8d00f46f675daafad566e7 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Fri, 3 Mar 2023 10:03:23 +0100 Subject: [PATCH 16/70] handle non-json output in stdout --- src/bootstrap/render_tests.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/bootstrap/render_tests.rs b/src/bootstrap/render_tests.rs index bdcd39e6b83e..1d8e8827e385 100644 --- a/src/bootstrap/render_tests.rs +++ b/src/bootstrap/render_tests.rs @@ -105,12 +105,19 @@ impl<'a> Renderer<'a> { break; } - self.render_message(match serde_json::from_str(&line) { - Ok(parsed) => parsed, - Err(err) => { - panic!("failed to parse libtest json output; error: {err}, line: {line:?}"); - } - }); + let trimmed = line.trim(); + if trimmed.starts_with("{") && trimmed.ends_with("}") { + self.render_message(match serde_json::from_str(&trimmed) { + Ok(parsed) => parsed, + Err(err) => { + panic!("failed to parse libtest json output; error: {err}, line: {line:?}"); + } + }); + } else { + // Handle non-JSON output, for example when --nocapture is passed. + print!("{line}"); + let _ = std::io::stdout().flush(); + } } } From 49582725603102c9734bdcb44608a725d5c963b3 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Fri, 3 Mar 2023 11:09:47 +0100 Subject: [PATCH 17/70] change approach to prevent interleaving compiletest message --- src/bootstrap/render_tests.rs | 7 +------ src/tools/compiletest/src/main.rs | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/bootstrap/render_tests.rs b/src/bootstrap/render_tests.rs index 1d8e8827e385..cdc40d831516 100644 --- a/src/bootstrap/render_tests.rs +++ b/src/bootstrap/render_tests.rs @@ -7,7 +7,7 @@ //! to reimplement all the rendering logic in this module because of that. use crate::builder::Builder; -use std::io::{BufRead, BufReader, Cursor, Write}; +use std::io::{BufRead, BufReader, Write}; use std::process::{ChildStdout, Command, Stdio}; use std::time::Duration; use yansi_term::Color; @@ -43,7 +43,6 @@ pub(crate) fn try_run_tests(builder: &Builder<'_>, cmd: &mut Command) -> bool { fn run_tests(builder: &Builder<'_>, cmd: &mut Command) -> bool { cmd.stdout(Stdio::piped()); - cmd.stderr(Stdio::piped()); builder.verbose(&format!("running: {cmd:?}")); @@ -62,10 +61,6 @@ fn run_tests(builder: &Builder<'_>, cmd: &mut Command) -> bool { ); } - // Show the stderr emitted by the test runner at the end. As of 2023-03-02 this is only the - // message at the end of a failed compiletest run. - std::io::copy(&mut Cursor::new(&result.stderr), &mut std::io::stderr().lock()).unwrap(); - result.status.success() } diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 167cd5c5dc17..cbaa599f7930 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -422,7 +422,7 @@ pub fn run_tests(config: Config) { // easy to miss which tests failed, and as such fail to reproduce // the failure locally. - eprintln!( + println!( "Some tests failed in compiletest suite={}{} mode={} host={} target={}", config.suite, config.compare_mode.map(|c| format!(" compare_mode={:?}", c)).unwrap_or_default(), From 3248ab758a43844ae69172cb7d082735e473ad29 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Mon, 6 Mar 2023 09:59:43 +0100 Subject: [PATCH 18/70] fix name of the field containing the ignore reason --- src/bootstrap/render_tests.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/render_tests.rs b/src/bootstrap/render_tests.rs index cdc40d831516..4e7b85d97ee5 100644 --- a/src/bootstrap/render_tests.rs +++ b/src/bootstrap/render_tests.rs @@ -245,7 +245,7 @@ impl<'a> Renderer<'a> { name: outcome.name.clone(), exec_time: None, stdout: None, - reason: None, + message: None, }; self.render_test_outcome(Outcome::BenchOk, &fake_test_outcome); self.benches.push(outcome); @@ -255,7 +255,7 @@ impl<'a> Renderer<'a> { } Message::Test(TestMessage::Ignored(outcome)) => { self.render_test_outcome( - Outcome::Ignored { reason: outcome.reason.as_deref() }, + Outcome::Ignored { reason: outcome.message.as_deref() }, &outcome, ); } @@ -345,5 +345,5 @@ struct TestOutcome { name: String, exec_time: Option, stdout: Option, - reason: Option, + message: Option, } From defa2456246a8272ceace9c1cdccdf2e4c36175e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Tue, 21 Feb 2023 00:00:00 +0000 Subject: [PATCH 19/70] Implement read_buf for a few more types Implement read_buf for TcpStream, Stdin, StdinLock, ChildStdout, ChildStderr (and internally for AnonPipe, Handle, Socket), so that it skips buffer initialization. The other provided methods like read_to_string and read_to_end are implemented in terms of read_buf and so benefit from the optimization as well. This commit also implements read_vectored and is_read_vectored where applicable. --- library/std/src/fs/tests.rs | 20 ++++++++++++++- library/std/src/io/stdio.rs | 13 +++++++++- library/std/src/net/tcp.rs | 10 +++++++- library/std/src/net/tcp/tests.rs | 28 +++++++++++++++++++- library/std/src/process.rs | 10 +++++++- library/std/src/process/tests.rs | 34 ++++++++++++++++++++++++- library/std/src/sys/sgx/fd.rs | 6 ++++- library/std/src/sys/sgx/net.rs | 6 ++++- library/std/src/sys/unix/fd.rs | 9 +++++++ library/std/src/sys/unix/net.rs | 28 +++++++++++++++----- library/std/src/sys/unix/pipe.rs | 6 ++++- library/std/src/sys/unix/stdio.rs | 6 ++++- library/std/src/sys/unsupported/net.rs | 6 ++++- library/std/src/sys/unsupported/pipe.rs | 6 ++++- library/std/src/sys/wasi/fd.rs | 18 ++++++++++++- library/std/src/sys/wasi/fs.rs | 2 +- library/std/src/sys/wasi/net.rs | 6 ++++- library/std/src/sys/windows/handle.rs | 9 +++++++ library/std/src/sys/windows/net.rs | 28 ++++++++++++++------ library/std/src/sys/windows/pipe.rs | 24 ++++++++++++++++- library/std/src/sys_common/net.rs | 6 ++++- 21 files changed, 250 insertions(+), 31 deletions(-) diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 909d9bf4093b..401def184582 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -2,7 +2,8 @@ use crate::io::prelude::*; use crate::env; use crate::fs::{self, File, OpenOptions}; -use crate::io::{ErrorKind, SeekFrom}; +use crate::io::{BorrowedBuf, ErrorKind, SeekFrom}; +use crate::mem::MaybeUninit; use crate::path::Path; use crate::str; use crate::sync::Arc; @@ -401,6 +402,23 @@ fn file_test_io_seek_read_write() { check!(fs::remove_file(&filename)); } +#[test] +fn file_test_read_buf() { + let tmpdir = tmpdir(); + let filename = &tmpdir.join("test"); + check!(fs::write(filename, &[1, 2, 3, 4])); + + let mut buf: [MaybeUninit; 128] = MaybeUninit::uninit_array(); + let mut buf = BorrowedBuf::from(buf.as_mut_slice()); + let mut file = check!(File::open(filename)); + check!(file.read_buf(buf.unfilled())); + assert_eq!(buf.filled(), &[1, 2, 3, 4]); + // File::read_buf should omit buffer initialization. + assert_eq!(buf.init_len(), 4); + + check!(fs::remove_file(filename)); +} + #[test] fn file_test_stat_is_correct_on_is_file() { let tmpdir = tmpdir(); diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 14bfef4c7aad..0455a00956e6 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -8,7 +8,7 @@ use crate::io::prelude::*; use crate::cell::{Cell, RefCell}; use crate::fmt; use crate::fs::File; -use crate::io::{self, BufReader, IoSlice, IoSliceMut, LineWriter, Lines}; +use crate::io::{self, BorrowedCursor, BufReader, IoSlice, IoSliceMut, LineWriter, Lines}; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sync::{Arc, Mutex, MutexGuard, OnceLock, ReentrantMutex, ReentrantMutexGuard}; use crate::sys::stdio; @@ -97,6 +97,10 @@ impl Read for StdinRaw { handle_ebadf(self.0.read(buf), 0) } + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + handle_ebadf(self.0.read_buf(buf), ()) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { handle_ebadf(self.0.read_vectored(bufs), 0) } @@ -418,6 +422,9 @@ impl Read for Stdin { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.lock().read(buf) } + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.lock().read_buf(buf) + } fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.lock().read_vectored(bufs) } @@ -450,6 +457,10 @@ impl Read for StdinLock<'_> { self.inner.read(buf) } + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.inner.read_buf(buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.inner.read_vectored(bufs) } diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index ac09a805975e..3982d3636614 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -6,7 +6,7 @@ mod tests; use crate::io::prelude::*; use crate::fmt; -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::iter::FusedIterator; use crate::net::{Shutdown, SocketAddr, ToSocketAddrs}; use crate::sys_common::net as net_imp; @@ -619,6 +619,10 @@ impl Read for TcpStream { self.0.read(buf) } + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.0.read_buf(buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.0.read_vectored(bufs) } @@ -653,6 +657,10 @@ impl Read for &TcpStream { self.0.read(buf) } + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.0.read_buf(buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.0.read_vectored(bufs) } diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs index e019bc0b67a1..7a3c66e45045 100644 --- a/library/std/src/net/tcp/tests.rs +++ b/library/std/src/net/tcp/tests.rs @@ -1,6 +1,7 @@ use crate::fmt; use crate::io::prelude::*; -use crate::io::{ErrorKind, IoSlice, IoSliceMut}; +use crate::io::{BorrowedBuf, ErrorKind, IoSlice, IoSliceMut}; +use crate::mem::MaybeUninit; use crate::net::test::{next_test_ip4, next_test_ip6}; use crate::net::*; use crate::sync::mpsc::channel; @@ -279,6 +280,31 @@ fn partial_read() { }) } +#[test] +fn read_buf() { + each_ip(&mut |addr| { + let srv = t!(TcpListener::bind(&addr)); + let t = thread::spawn(move || { + let mut s = t!(TcpStream::connect(&addr)); + s.write_all(&[1, 2, 3, 4]).unwrap(); + }); + + let mut s = t!(srv.accept()).0; + let mut buf: [MaybeUninit; 128] = MaybeUninit::uninit_array(); + let mut buf = BorrowedBuf::from(buf.as_mut_slice()); + t!(s.read_buf(buf.unfilled())); + assert_eq!(buf.filled(), &[1, 2, 3, 4]); + + // FIXME: sgx uses default_read_buf that initializes the buffer. + if cfg!(not(target_env = "sgx")) { + // TcpStream::read_buf should omit buffer initialization. + assert_eq!(buf.init_len(), 4); + } + + t.join().ok().expect("thread panicked"); + }) +} + #[test] fn read_vectored() { each_ip(&mut |addr| { diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 1952e19e6072..80d73084c4f0 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -110,7 +110,7 @@ use crate::convert::Infallible; use crate::ffi::OsStr; use crate::fmt; use crate::fs; -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::num::NonZeroI32; use crate::path::Path; use crate::str; @@ -354,6 +354,10 @@ impl Read for ChildStdout { self.inner.read(buf) } + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.inner.read_buf(buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.inner.read_vectored(bufs) } @@ -419,6 +423,10 @@ impl Read for ChildStderr { self.inner.read(buf) } + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.inner.read_buf(buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.inner.read_vectored(bufs) } diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs index b4f6cc2dabae..d7f4d335de3e 100644 --- a/library/std/src/process/tests.rs +++ b/library/std/src/process/tests.rs @@ -1,7 +1,8 @@ use crate::io::prelude::*; use super::{Command, Output, Stdio}; -use crate::io::ErrorKind; +use crate::io::{BorrowedBuf, ErrorKind}; +use crate::mem::MaybeUninit; use crate::str; fn known_command() -> Command { @@ -119,6 +120,37 @@ fn stdin_works() { assert_eq!(out, "foobar\n"); } +#[test] +#[cfg_attr(any(target_os = "vxworks"), ignore)] +fn child_stdout_read_buf() { + let mut cmd = if cfg!(target_os = "windows") { + let mut cmd = Command::new("cmd"); + cmd.arg("/C").arg("echo abc"); + cmd + } else { + let mut cmd = shell_cmd(); + cmd.arg("-c").arg("echo abc"); + cmd + }; + cmd.stdin(Stdio::null()); + cmd.stdout(Stdio::piped()); + let child = cmd.spawn().unwrap(); + + let mut stdout = child.stdout.unwrap(); + let mut buf: [MaybeUninit; 128] = MaybeUninit::uninit_array(); + let mut buf = BorrowedBuf::from(buf.as_mut_slice()); + stdout.read_buf(buf.unfilled()).unwrap(); + + // ChildStdout::read_buf should omit buffer initialization. + if cfg!(target_os = "windows") { + assert_eq!(buf.filled(), b"abc\r\n"); + assert_eq!(buf.init_len(), 5); + } else { + assert_eq!(buf.filled(), b"abc\n"); + assert_eq!(buf.init_len(), 4); + }; +} + #[test] #[cfg_attr(any(target_os = "vxworks"), ignore)] fn test_process_status() { diff --git a/library/std/src/sys/sgx/fd.rs b/library/std/src/sys/sgx/fd.rs index e5dc5b5adaa9..0c02a107691c 100644 --- a/library/std/src/sys/sgx/fd.rs +++ b/library/std/src/sys/sgx/fd.rs @@ -1,7 +1,7 @@ use fortanix_sgx_abi::Fd; use super::abi::usercalls; -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::mem; use crate::sys::{AsInner, FromInner, IntoInner}; @@ -30,6 +30,10 @@ impl FileDesc { usercalls::read(self.fd, &mut [IoSliceMut::new(buf)]) } + pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> { + crate::io::default_read_buf(|b| self.read(b), buf) + } + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { usercalls::read(self.fd, bufs) } diff --git a/library/std/src/sys/sgx/net.rs b/library/std/src/sys/sgx/net.rs index 4c4cd7d1d1d8..923be5eb944e 100644 --- a/library/std/src/sys/sgx/net.rs +++ b/library/std/src/sys/sgx/net.rs @@ -1,6 +1,6 @@ use crate::error; use crate::fmt; -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs}; use crate::sync::Arc; use crate::sys::fd::FileDesc; @@ -144,6 +144,10 @@ impl TcpStream { self.inner.inner.read(buf) } + pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.inner.inner.read_buf(buf) + } + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.inner.inner.read_vectored(bufs) } diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index 9874af4d3e24..ce5c048f252a 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -469,6 +469,15 @@ impl<'a> Read for &'a FileDesc { fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { (**self).read_buf(cursor) } + + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + (**self).read_vectored(bufs) + } + + #[inline] + fn is_read_vectored(&self) -> bool { + (**self).is_read_vectored() + } } impl AsInner for FileDesc { diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index 8e05b618daa0..f84240d268fe 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -1,6 +1,6 @@ use crate::cmp; use crate::ffi::CStr; -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut}; use crate::mem; use crate::net::{Shutdown, SocketAddr}; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; @@ -242,19 +242,35 @@ impl Socket { self.0.duplicate().map(Socket) } - fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result { + fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Result<()> { let ret = cvt(unsafe { - libc::recv(self.as_raw_fd(), buf.as_mut_ptr() as *mut c_void, buf.len(), flags) + libc::recv( + self.as_raw_fd(), + buf.as_mut().as_mut_ptr() as *mut c_void, + buf.capacity(), + flags, + ) })?; - Ok(ret as usize) + unsafe { + buf.advance(ret as usize); + } + Ok(()) } pub fn read(&self, buf: &mut [u8]) -> io::Result { - self.recv_with_flags(buf, 0) + let mut buf = BorrowedBuf::from(buf); + self.recv_with_flags(buf.unfilled(), 0)?; + Ok(buf.len()) } pub fn peek(&self, buf: &mut [u8]) -> io::Result { - self.recv_with_flags(buf, MSG_PEEK) + let mut buf = BorrowedBuf::from(buf); + self.recv_with_flags(buf.unfilled(), MSG_PEEK)?; + Ok(buf.len()) + } + + pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.recv_with_flags(buf, 0) } pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { diff --git a/library/std/src/sys/unix/pipe.rs b/library/std/src/sys/unix/pipe.rs index a744d0ab6404..dc17c9fac460 100644 --- a/library/std/src/sys/unix/pipe.rs +++ b/library/std/src/sys/unix/pipe.rs @@ -1,4 +1,4 @@ -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::mem; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::sys::fd::FileDesc; @@ -49,6 +49,10 @@ impl AnonPipe { self.0.read(buf) } + pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.0.read_buf(buf) + } + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.0.read_vectored(bufs) } diff --git a/library/std/src/sys/unix/stdio.rs b/library/std/src/sys/unix/stdio.rs index b3626c564e86..a26f20795a19 100644 --- a/library/std/src/sys/unix/stdio.rs +++ b/library/std/src/sys/unix/stdio.rs @@ -1,4 +1,4 @@ -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::mem::ManuallyDrop; use crate::os::unix::io::FromRawFd; use crate::sys::fd::FileDesc; @@ -18,6 +18,10 @@ impl io::Read for Stdin { unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDIN_FILENO)).read(buf) } } + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDIN_FILENO)).read_buf(buf) } + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDIN_FILENO)).read_vectored(bufs) } } diff --git a/library/std/src/sys/unsupported/net.rs b/library/std/src/sys/unsupported/net.rs index a5204a084537..bbc52703f963 100644 --- a/library/std/src/sys/unsupported/net.rs +++ b/library/std/src/sys/unsupported/net.rs @@ -1,5 +1,5 @@ use crate::fmt; -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; use crate::sys::unsupported; use crate::time::Duration; @@ -39,6 +39,10 @@ impl TcpStream { self.0 } + pub fn read_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> { + self.0 + } + pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result { self.0 } diff --git a/library/std/src/sys/unsupported/pipe.rs b/library/std/src/sys/unsupported/pipe.rs index 0bba673b458c..d7d8f297ae58 100644 --- a/library/std/src/sys/unsupported/pipe.rs +++ b/library/std/src/sys/unsupported/pipe.rs @@ -1,4 +1,4 @@ -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; pub struct AnonPipe(!); @@ -7,6 +7,10 @@ impl AnonPipe { self.0 } + pub fn read_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> { + self.0 + } + pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.0 } diff --git a/library/std/src/sys/wasi/fd.rs b/library/std/src/sys/wasi/fd.rs index 0b9c8e61db84..191db4b60f72 100644 --- a/library/std/src/sys/wasi/fd.rs +++ b/library/std/src/sys/wasi/fd.rs @@ -2,7 +2,7 @@ #![allow(dead_code)] use super::err2io; -use crate::io::{self, IoSlice, IoSliceMut, SeekFrom}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; use crate::mem; use crate::net::Shutdown; use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; @@ -46,6 +46,22 @@ impl WasiFd { unsafe { wasi::fd_read(self.as_raw_fd() as wasi::Fd, iovec(bufs)).map_err(err2io) } } + pub fn read_buf(&self, mut buf: BorrowedCursor<'_>) -> io::Result<()> { + unsafe { + let bufs = [wasi::Iovec { + buf: buf.as_mut().as_mut_ptr() as *mut u8, + buf_len: buf.capacity(), + }]; + match wasi::fd_read(self.as_raw_fd() as wasi::Fd, &bufs) { + Ok(n) => { + buf.advance(n); + Ok(()) + } + Err(e) => Err(err2io(e)), + } + } + } + pub fn write(&self, bufs: &[IoSlice<'_>]) -> io::Result { unsafe { wasi::fd_write(self.as_raw_fd() as wasi::Fd, ciovec(bufs)).map_err(err2io) } } diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs index d4866bbc32ba..3a205267e346 100644 --- a/library/std/src/sys/wasi/fs.rs +++ b/library/std/src/sys/wasi/fs.rs @@ -441,7 +441,7 @@ impl File { } pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> { - crate::io::default_read_buf(|buf| self.read(buf), cursor) + self.fd.read_buf(cursor) } pub fn write(&self, buf: &[u8]) -> io::Result { diff --git a/library/std/src/sys/wasi/net.rs b/library/std/src/sys/wasi/net.rs index cf4ebba1a39a..59d94a3686dc 100644 --- a/library/std/src/sys/wasi/net.rs +++ b/library/std/src/sys/wasi/net.rs @@ -3,7 +3,7 @@ use super::err2io; use super::fd::WasiFd; use crate::fmt; -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::sys::unsupported; @@ -91,6 +91,10 @@ impl TcpStream { self.read_vectored(&mut [IoSliceMut::new(buf)]) } + pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.socket().as_inner().read_buf(buf) + } + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.socket().as_inner().read(bufs) } diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs index ae33d48c612e..b290f4070e8f 100644 --- a/library/std/src/sys/windows/handle.rs +++ b/library/std/src/sys/windows/handle.rs @@ -327,7 +327,16 @@ impl<'a> Read for &'a Handle { (**self).read(buf) } + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + (**self).read_buf(buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { (**self).read_vectored(bufs) } + + #[inline] + fn is_read_vectored(&self) -> bool { + (**self).is_read_vectored() + } } diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs index e0701a498fad..ee1f5482b47e 100644 --- a/library/std/src/sys/windows/net.rs +++ b/library/std/src/sys/windows/net.rs @@ -1,7 +1,7 @@ #![unstable(issue = "none", feature = "windows_net")] use crate::cmp; -use crate::io::{self, IoSlice, IoSliceMut, Read}; +use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut, Read}; use crate::mem; use crate::net::{Shutdown, SocketAddr}; use crate::os::windows::io::{ @@ -214,28 +214,38 @@ impl Socket { Ok(Self(self.0.try_clone()?)) } - fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result { + fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Result<()> { // On unix when a socket is shut down all further reads return 0, so we // do the same on windows to map a shut down socket to returning EOF. - let length = cmp::min(buf.len(), i32::MAX as usize) as i32; - let result = - unsafe { c::recv(self.as_raw_socket(), buf.as_mut_ptr() as *mut _, length, flags) }; + let length = cmp::min(buf.capacity(), i32::MAX as usize) as i32; + let result = unsafe { + c::recv(self.as_raw_socket(), buf.as_mut().as_mut_ptr() as *mut _, length, flags) + }; match result { c::SOCKET_ERROR => { let error = unsafe { c::WSAGetLastError() }; if error == c::WSAESHUTDOWN { - Ok(0) + Ok(()) } else { Err(io::Error::from_raw_os_error(error)) } } - _ => Ok(result as usize), + _ => { + unsafe { buf.advance(result as usize) }; + Ok(()) + } } } pub fn read(&self, buf: &mut [u8]) -> io::Result { + let mut buf = BorrowedBuf::from(buf); + self.recv_with_flags(buf.unfilled(), 0)?; + Ok(buf.len()) + } + + pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> { self.recv_with_flags(buf, 0) } @@ -277,7 +287,9 @@ impl Socket { } pub fn peek(&self, buf: &mut [u8]) -> io::Result { - self.recv_with_flags(buf, c::MSG_PEEK) + let mut buf = BorrowedBuf::from(buf); + self.recv_with_flags(buf.unfilled(), c::MSG_PEEK)?; + Ok(buf.len()) } fn recv_from_with_flags( diff --git a/library/std/src/sys/windows/pipe.rs b/library/std/src/sys/windows/pipe.rs index 7b25edaa556f..0780b29584da 100644 --- a/library/std/src/sys/windows/pipe.rs +++ b/library/std/src/sys/windows/pipe.rs @@ -1,7 +1,7 @@ use crate::os::windows::prelude::*; use crate::ffi::OsStr; -use crate::io::{self, IoSlice, IoSliceMut, Read}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read}; use crate::mem; use crate::path::Path; use crate::ptr; @@ -252,6 +252,28 @@ impl AnonPipe { } } + pub fn read_buf(&self, mut buf: BorrowedCursor<'_>) -> io::Result<()> { + let result = unsafe { + let len = crate::cmp::min(buf.capacity(), c::DWORD::MAX as usize) as c::DWORD; + self.alertable_io_internal(c::ReadFileEx, buf.as_mut().as_mut_ptr() as _, len) + }; + + match result { + // The special treatment of BrokenPipe is to deal with Windows + // pipe semantics, which yields this error when *reading* from + // a pipe after the other end has closed; we interpret that as + // EOF on the pipe. + Err(ref e) if e.kind() == io::ErrorKind::BrokenPipe => Ok(()), + Err(e) => Err(e), + Ok(n) => { + unsafe { + buf.advance(n); + } + Ok(()) + } + } + } + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.inner.read_vectored(bufs) } diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 85ecc1def3a2..eb427dbda239 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -4,7 +4,7 @@ mod tests; use crate::cmp; use crate::convert::{TryFrom, TryInto}; use crate::fmt; -use crate::io::{self, ErrorKind, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut}; use crate::mem; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; use crate::ptr; @@ -272,6 +272,10 @@ impl TcpStream { self.inner.read(buf) } + pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.inner.read_buf(buf) + } + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.inner.read_vectored(bufs) } From c015d0d2faf88683678572bcf31c5bdff955d267 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Tue, 7 Mar 2023 10:21:25 +0100 Subject: [PATCH 20/70] switch to termcolor --- src/bootstrap/Cargo.lock | 20 ++++----- src/bootstrap/Cargo.toml | 2 +- src/bootstrap/lib.rs | 30 ++++++++----- src/bootstrap/render_tests.rs | 81 ++++++++++++++++++++++------------- 4 files changed, 82 insertions(+), 51 deletions(-) diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 8195823efaff..69bb98135ca1 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -67,11 +67,11 @@ dependencies = [ "sha2", "sysinfo", "tar", + "termcolor", "toml", "walkdir", "winapi", "xz2", - "yansi-term", ] [[package]] @@ -649,6 +649,15 @@ dependencies = [ "xattr", ] +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + [[package]] name = "thread_local" version = "1.1.4" @@ -813,12 +822,3 @@ name = "yansi" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" - -[[package]] -name = "yansi-term" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1" -dependencies = [ - "winapi", -] diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index e704799867b3..83e63df50147 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -47,13 +47,13 @@ serde_derive = "1.0.137" serde_json = "1.0.2" sha2 = "0.10" tar = "0.4" +termcolor = "1.2.0" toml = "0.5" ignore = "0.4.10" opener = "0.5" once_cell = "1.7.2" xz2 = "0.1" walkdir = "2" -yansi-term = "0.1.2" # Dependencies needed by the build-metrics feature sysinfo = { version = "0.26.0", optional = true } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 0eff8769b609..9e1d88a6aefc 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -89,7 +89,7 @@ pub use crate::builder::PathSet; use crate::cache::{Interned, INTERNER}; pub use crate::config::Config; pub use crate::flags::Subcommand; -use yansi_term::Color; +use termcolor::{ColorChoice, StandardStream, WriteColor}; const LLVM_TOOLS: &[&str] = &[ "llvm-cov", // used to generate coverage report @@ -1577,21 +1577,29 @@ to download LLVM rather than building it. self.config.ninja_in_file } - pub fn color_for_stdout(&self, color: Color, message: &str) -> String { - self.color_for_inner(color, message, self.config.stdout_is_tty) + pub fn colored_stdout R>(&self, f: F) -> R { + self.colored_stream_inner(StandardStream::stdout, self.config.stdout_is_tty, f) } - pub fn color_for_stderr(&self, color: Color, message: &str) -> String { - self.color_for_inner(color, message, self.config.stderr_is_tty) + pub fn colored_stderr R>(&self, f: F) -> R { + self.colored_stream_inner(StandardStream::stderr, self.config.stderr_is_tty, f) } - fn color_for_inner(&self, color: Color, message: &str, is_tty: bool) -> String { - let use_color = match self.config.color { - flags::Color::Always => true, - flags::Color::Never => false, - flags::Color::Auto => is_tty, + fn colored_stream_inner(&self, constructor: C, is_tty: bool, f: F) -> R + where + C: Fn(ColorChoice) -> StandardStream, + F: FnOnce(&mut dyn WriteColor) -> R, + { + let choice = match self.config.color { + flags::Color::Always => ColorChoice::Always, + flags::Color::Never => ColorChoice::Never, + flags::Color::Auto if !is_tty => ColorChoice::Never, + flags::Color::Auto => ColorChoice::Auto, }; - if use_color { color.paint(message).to_string() } else { message.to_string() } + let mut stream = constructor(choice); + let result = f(&mut stream); + stream.reset().unwrap(); + result } } diff --git a/src/bootstrap/render_tests.rs b/src/bootstrap/render_tests.rs index 4e7b85d97ee5..fd78e449a49b 100644 --- a/src/bootstrap/render_tests.rs +++ b/src/bootstrap/render_tests.rs @@ -10,7 +10,7 @@ use crate::builder::Builder; use std::io::{BufRead, BufReader, Write}; use std::process::{ChildStdout, Command, Stdio}; use std::time::Duration; -use yansi_term::Color; +use termcolor::{Color, ColorSpec, WriteColor}; const TERSE_TESTS_PER_LINE: usize = 88; @@ -139,16 +139,12 @@ impl<'a> Renderer<'a> { } fn render_test_outcome_verbose(&self, outcome: Outcome<'_>, test: &TestOutcome) { + print!("test {} ... ", test.name); + self.builder.colored_stdout(|stdout| outcome.write_long(stdout)).unwrap(); if let Some(exec_time) = test.exec_time { - println!( - "test {} ... {} (in {:.2?})", - test.name, - outcome.long(self.builder), - Duration::from_secs_f64(exec_time) - ); - } else { - println!("test {} ... {}", test.name, outcome.long(self.builder)); + print!(" ({exec_time:.2?})"); } + println!(); } fn render_test_outcome_terse(&mut self, outcome: Outcome<'_>, _: &TestOutcome) { @@ -163,7 +159,7 @@ impl<'a> Renderer<'a> { } self.terse_tests_in_line += 1; - print!("{}", outcome.short(self.builder)); + self.builder.colored_stdout(|stdout| outcome.write_short(stdout)).unwrap(); let _ = std::io::stdout().flush(); } @@ -208,10 +204,11 @@ impl<'a> Renderer<'a> { } } + print!("\ntest result: "); + self.builder.colored_stdout(|stdout| outcome.write_long(stdout)).unwrap(); println!( - "\ntest result: {}. {} passed; {} failed; {} ignored; {} measured; \ - {} filtered out; finished in {:.2?}\n", - outcome.long(self.builder), + ". {} passed; {} failed; {} ignored; {} measured; {} filtered out; \ + finished in {:.2?}\n", suite.passed, suite.failed, suite.ignored, @@ -276,25 +273,51 @@ enum Outcome<'a> { } impl Outcome<'_> { - fn short(&self, builder: &Builder<'_>) -> String { + fn write_short(&self, writer: &mut dyn WriteColor) -> Result<(), std::io::Error> { match self { - Outcome::Ok => builder.color_for_stdout(Color::Green, "."), - Outcome::BenchOk => builder.color_for_stdout(Color::Cyan, "b"), - Outcome::Failed => builder.color_for_stdout(Color::Red, "F"), - Outcome::Ignored { .. } => builder.color_for_stdout(Color::Yellow, "i"), - } - } - - fn long(&self, builder: &Builder<'_>) -> String { - match self { - Outcome::Ok => builder.color_for_stdout(Color::Green, "ok"), - Outcome::BenchOk => builder.color_for_stdout(Color::Cyan, "benchmarked"), - Outcome::Failed => builder.color_for_stdout(Color::Red, "FAILED"), - Outcome::Ignored { reason: None } => builder.color_for_stdout(Color::Yellow, "ignored"), - Outcome::Ignored { reason: Some(reason) } => { - builder.color_for_stdout(Color::Yellow, &format!("ignored, {reason}")) + Outcome::Ok => { + writer.set_color(&ColorSpec::new().set_fg(Some(Color::Green)))?; + write!(writer, ".")?; + } + Outcome::BenchOk => { + writer.set_color(&ColorSpec::new().set_fg(Some(Color::Cyan)))?; + write!(writer, "b")?; + } + Outcome::Failed => { + writer.set_color(&ColorSpec::new().set_fg(Some(Color::Red)))?; + write!(writer, "F")?; + } + Outcome::Ignored { .. } => { + writer.set_color(&ColorSpec::new().set_fg(Some(Color::Yellow)))?; + write!(writer, "i")?; } } + writer.reset() + } + + fn write_long(&self, writer: &mut dyn WriteColor) -> Result<(), std::io::Error> { + match self { + Outcome::Ok => { + writer.set_color(&ColorSpec::new().set_fg(Some(Color::Green)))?; + write!(writer, "ok")?; + } + Outcome::BenchOk => { + writer.set_color(&ColorSpec::new().set_fg(Some(Color::Cyan)))?; + write!(writer, "benchmarked")?; + } + Outcome::Failed => { + writer.set_color(&ColorSpec::new().set_fg(Some(Color::Red)))?; + write!(writer, "FAILED")?; + } + Outcome::Ignored { reason } => { + writer.set_color(&ColorSpec::new().set_fg(Some(Color::Yellow)))?; + write!(writer, "ignored")?; + if let Some(reason) = reason { + write!(writer, ", {reason}")?; + } + } + } + writer.reset() } } From 0a1b9834b3d71953ff0b22b48237e23d5fa9fd3f Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Tue, 14 Mar 2023 15:30:42 +0100 Subject: [PATCH 21/70] add dist.compression-profile option to control compression speed --- config.example.toml | 6 + src/bootstrap/config.rs | 4 + src/bootstrap/tarball.rs | 1 + src/tools/rust-installer/src/combiner.rs | 7 +- src/tools/rust-installer/src/compression.rs | 128 ++++++++++++++------ src/tools/rust-installer/src/generator.rs | 7 +- src/tools/rust-installer/src/tarballer.rs | 8 +- 7 files changed, 118 insertions(+), 43 deletions(-) diff --git a/config.example.toml b/config.example.toml index dee0d8f254b6..67916049e4ac 100644 --- a/config.example.toml +++ b/config.example.toml @@ -803,3 +803,9 @@ changelog-seen = 2 # # This list must be non-empty. #compression-formats = ["gz", "xz"] + +# How much time should be spent compressing the tarballs. The better the +# compression profile, the longer compression will take. +# +# Available options: fast, balanced, best +#compression-profile = "balanced" diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index fc5aa8a245d2..939853a76d83 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -190,6 +190,7 @@ pub struct Config { pub dist_sign_folder: Option, pub dist_upload_addr: Option, pub dist_compression_formats: Option>, + pub dist_compression_profile: String, pub dist_include_mingw_linker: bool, // libstd features @@ -701,6 +702,7 @@ define_config! { src_tarball: Option = "src-tarball", missing_tools: Option = "missing-tools", compression_formats: Option> = "compression-formats", + compression_profile: Option = "compression-profile", include_mingw_linker: Option = "include-mingw-linker", } } @@ -819,6 +821,7 @@ impl Config { config.deny_warnings = true; config.bindir = "bin".into(); config.dist_include_mingw_linker = true; + config.dist_compression_profile = "balanced".into(); // set by build.rs config.build = TargetSelection::from_user(&env!("BUILD_TRIPLE")); @@ -1300,6 +1303,7 @@ impl Config { config.dist_sign_folder = t.sign_folder.map(PathBuf::from); config.dist_upload_addr = t.upload_addr; config.dist_compression_formats = t.compression_formats; + set(&mut config.dist_compression_profile, t.compression_profile); set(&mut config.rust_dist_src, t.src_tarball); set(&mut config.missing_tools, t.missing_tools); set(&mut config.dist_include_mingw_linker, t.include_mingw_linker) diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/tarball.rs index fc850a22b2f6..7fa8a4d9d7f8 100644 --- a/src/bootstrap/tarball.rs +++ b/src/bootstrap/tarball.rs @@ -318,6 +318,7 @@ impl<'a> Tarball<'a> { assert!(!formats.is_empty(), "dist.compression-formats can't be empty"); cmd.arg("--compression-formats").arg(formats.join(",")); } + cmd.args(&["--compression-profile", &self.builder.config.dist_compression_profile]); self.builder.run(&mut cmd); // Ensure there are no symbolic links in the tarball. In particular, diff --git a/src/tools/rust-installer/src/combiner.rs b/src/tools/rust-installer/src/combiner.rs index 2ec09d67e3e6..abcf59cfe36c 100644 --- a/src/tools/rust-installer/src/combiner.rs +++ b/src/tools/rust-installer/src/combiner.rs @@ -1,7 +1,7 @@ use super::Scripter; use super::Tarballer; use crate::{ - compression::{CompressionFormat, CompressionFormats}, + compression::{CompressionFormat, CompressionFormats, CompressionProfile}, util::*, }; use anyhow::{bail, Context, Result}; @@ -48,6 +48,10 @@ actor! { #[clap(value_name = "DIR")] output_dir: String = "./dist", + /// The profile used to compress the tarball. + #[clap(value_name = "FORMAT", default_value_t)] + compression_profile: CompressionProfile, + /// The formats used to compress the tarball #[clap(value_name = "FORMAT", default_value_t)] compression_formats: CompressionFormats, @@ -153,6 +157,7 @@ impl Combiner { .work_dir(self.work_dir) .input(self.package_name) .output(path_to_str(&output)?.into()) + .compression_profile(self.compression_profile) .compression_formats(self.compression_formats.clone()); tarballer.run()?; diff --git a/src/tools/rust-installer/src/compression.rs b/src/tools/rust-installer/src/compression.rs index 013e05fda581..510c914163c7 100644 --- a/src/tools/rust-installer/src/compression.rs +++ b/src/tools/rust-installer/src/compression.rs @@ -4,6 +4,37 @@ use rayon::prelude::*; use std::{convert::TryFrom, fmt, io::Read, io::Write, path::Path, str::FromStr}; use xz2::{read::XzDecoder, write::XzEncoder}; +#[derive(Default, Debug, Copy, Clone)] +pub enum CompressionProfile { + Fast, + #[default] + Balanced, + Best, +} + +impl FromStr for CompressionProfile { + type Err = Error; + + fn from_str(input: &str) -> Result { + Ok(match input { + "fast" => Self::Fast, + "balanced" => Self::Balanced, + "best" => Self::Best, + other => anyhow::bail!("invalid compression profile: {other}"), + }) + } +} + +impl fmt::Display for CompressionProfile { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + CompressionProfile::Fast => f.write_str("fast"), + CompressionProfile::Balanced => f.write_str("balanced"), + CompressionProfile::Best => f.write_str("best"), + } + } +} + #[derive(Debug, Copy, Clone)] pub enum CompressionFormat { Gz, @@ -26,7 +57,11 @@ impl CompressionFormat { } } - pub(crate) fn encode(&self, path: impl AsRef) -> Result, Error> { + pub(crate) fn encode( + &self, + path: impl AsRef, + profile: CompressionProfile, + ) -> Result, Error> { let mut os = path.as_ref().as_os_str().to_os_string(); os.push(format!(".{}", self.extension())); let path = Path::new(&os); @@ -37,49 +72,64 @@ impl CompressionFormat { let file = crate::util::create_new_file(path)?; Ok(match self { - CompressionFormat::Gz => Box::new(GzEncoder::new(file, flate2::Compression::best())), + CompressionFormat::Gz => Box::new(GzEncoder::new( + file, + match profile { + CompressionProfile::Fast => flate2::Compression::fast(), + CompressionProfile::Balanced => flate2::Compression::new(6), + CompressionProfile::Best => flate2::Compression::best(), + }, + )), CompressionFormat::Xz => { - let mut filters = xz2::stream::Filters::new(); - // the preset is overridden by the other options so it doesn't matter - let mut lzma_ops = xz2::stream::LzmaOptions::new_preset(9).unwrap(); - // This sets the overall dictionary size, which is also how much memory (baseline) - // is needed for decompression. - lzma_ops.dict_size(64 * 1024 * 1024); - // Use the best match finder for compression ratio. - lzma_ops.match_finder(xz2::stream::MatchFinder::BinaryTree4); - lzma_ops.mode(xz2::stream::Mode::Normal); - // Set nice len to the maximum for best compression ratio - lzma_ops.nice_len(273); - // Set depth to a reasonable value, 0 means auto, 1000 is somwhat high but gives - // good results. - lzma_ops.depth(1000); - // 2 is the default and does well for most files - lzma_ops.position_bits(2); - // 0 is the default and does well for most files - lzma_ops.literal_position_bits(0); - // 3 is the default and does well for most files - lzma_ops.literal_context_bits(3); + let encoder = match profile { + CompressionProfile::Fast => { + xz2::stream::MtStreamBuilder::new().threads(6).preset(1).encoder().unwrap() + } + CompressionProfile::Balanced => { + xz2::stream::MtStreamBuilder::new().threads(6).preset(6).encoder().unwrap() + } + CompressionProfile::Best => { + let mut filters = xz2::stream::Filters::new(); + // the preset is overridden by the other options so it doesn't matter + let mut lzma_ops = xz2::stream::LzmaOptions::new_preset(9).unwrap(); + // This sets the overall dictionary size, which is also how much memory (baseline) + // is needed for decompression. + lzma_ops.dict_size(64 * 1024 * 1024); + // Use the best match finder for compression ratio. + lzma_ops.match_finder(xz2::stream::MatchFinder::BinaryTree4); + lzma_ops.mode(xz2::stream::Mode::Normal); + // Set nice len to the maximum for best compression ratio + lzma_ops.nice_len(273); + // Set depth to a reasonable value, 0 means auto, 1000 is somwhat high but gives + // good results. + lzma_ops.depth(1000); + // 2 is the default and does well for most files + lzma_ops.position_bits(2); + // 0 is the default and does well for most files + lzma_ops.literal_position_bits(0); + // 3 is the default and does well for most files + lzma_ops.literal_context_bits(3); - filters.lzma2(&lzma_ops); + filters.lzma2(&lzma_ops); - let mut builder = xz2::stream::MtStreamBuilder::new(); - builder.filters(filters); + let mut builder = xz2::stream::MtStreamBuilder::new(); + builder.filters(filters); - // On 32-bit platforms limit ourselves to 3 threads, otherwise we exceed memory - // usage this process can take. In the future we'll likely only do super-fast - // compression in CI and move this heavyweight processing to promote-release (which - // is always 64-bit and can run on big-memory machines) but for now this lets us - // move forward. - if std::mem::size_of::() == 4 { - builder.threads(3); - } else { - builder.threads(6); - } + // On 32-bit platforms limit ourselves to 3 threads, otherwise we exceed memory + // usage this process can take. In the future we'll likely only do super-fast + // compression in CI and move this heavyweight processing to promote-release (which + // is always 64-bit and can run on big-memory machines) but for now this lets us + // move forward. + if std::mem::size_of::() == 4 { + builder.threads(3); + } else { + builder.threads(6); + } + builder.encoder().unwrap() + } + }; - let compressor = XzEncoder::new_stream( - std::io::BufWriter::new(file), - builder.encoder().unwrap(), - ); + let compressor = XzEncoder::new_stream(std::io::BufWriter::new(file), encoder); Box::new(compressor) } }) diff --git a/src/tools/rust-installer/src/generator.rs b/src/tools/rust-installer/src/generator.rs index 1e4d00b0553a..ddd1052599d5 100644 --- a/src/tools/rust-installer/src/generator.rs +++ b/src/tools/rust-installer/src/generator.rs @@ -1,6 +1,6 @@ use super::Scripter; use super::Tarballer; -use crate::compression::CompressionFormats; +use crate::compression::{CompressionFormats, CompressionProfile}; use crate::util::*; use anyhow::{bail, format_err, Context, Result}; use std::collections::BTreeSet; @@ -54,6 +54,10 @@ actor! { #[clap(value_name = "DIR")] output_dir: String = "./dist", + /// The profile used to compress the tarball. + #[clap(value_name = "FORMAT", default_value_t)] + compression_profile: CompressionProfile, + /// The formats used to compress the tarball #[clap(value_name = "FORMAT", default_value_t)] compression_formats: CompressionFormats, @@ -113,6 +117,7 @@ impl Generator { .work_dir(self.work_dir) .input(self.package_name) .output(path_to_str(&output)?.into()) + .compression_profile(self.compression_profile) .compression_formats(self.compression_formats.clone()); tarballer.run()?; diff --git a/src/tools/rust-installer/src/tarballer.rs b/src/tools/rust-installer/src/tarballer.rs index 76f5af3fa539..592eba8f6985 100644 --- a/src/tools/rust-installer/src/tarballer.rs +++ b/src/tools/rust-installer/src/tarballer.rs @@ -6,7 +6,7 @@ use tar::{Builder, Header}; use walkdir::WalkDir; use crate::{ - compression::{CombinedEncoder, CompressionFormats}, + compression::{CombinedEncoder, CompressionFormats, CompressionProfile}, util::*, }; @@ -25,6 +25,10 @@ actor! { #[clap(value_name = "DIR")] work_dir: String = "./workdir", + /// The profile used to compress the tarball. + #[clap(value_name = "FORMAT", default_value_t)] + compression_profile: CompressionProfile, + /// The formats used to compress the tarball. #[clap(value_name = "FORMAT", default_value_t)] compression_formats: CompressionFormats, @@ -38,7 +42,7 @@ impl Tarballer { let encoder = CombinedEncoder::new( self.compression_formats .iter() - .map(|f| f.encode(&tarball_name)) + .map(|f| f.encode(&tarball_name, self.compression_profile)) .collect::>>()?, ); From 4556037806cde7018848bb5730a75a665c0924d8 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Tue, 14 Mar 2023 16:42:28 +0100 Subject: [PATCH 22/70] use the best compression profile in CI --- src/ci/run.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ci/run.sh b/src/ci/run.sh index 93dccb54c4e3..8ca22d6e68fd 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -58,6 +58,7 @@ RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-manage-submodules" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-locked-deps" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-cargo-native-static" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.codegen-units-std=1" +RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set dist.compression-profile=best" # Only produce xz tarballs on CI. gz tarballs will be generated by the release # process by recompressing the existing xz ones. This decreases the storage From 34aa87292c5cd45c88a72235dad6e973a9f2b62f Mon Sep 17 00:00:00 2001 From: joboet Date: Tue, 14 Mar 2023 16:42:34 +0100 Subject: [PATCH 23/70] std: leak remaining messages in bounded channel if message destructor panics --- library/std/src/sync/mpmc/array.rs | 102 +++++++++++------------------ 1 file changed, 39 insertions(+), 63 deletions(-) diff --git a/library/std/src/sync/mpmc/array.rs b/library/std/src/sync/mpmc/array.rs index fb893695a9a5..492e21d9bdb6 100644 --- a/library/std/src/sync/mpmc/array.rs +++ b/library/std/src/sync/mpmc/array.rs @@ -15,7 +15,7 @@ use super::utils::{Backoff, CachePadded}; use super::waker::SyncWaker; use crate::cell::UnsafeCell; -use crate::mem::{self, MaybeUninit}; +use crate::mem::MaybeUninit; use crate::ptr; use crate::sync::atomic::{self, AtomicUsize, Ordering}; use crate::time::Instant; @@ -479,6 +479,10 @@ impl Channel { /// /// `tail` should be the current (and therefore last) value of `tail`. /// + /// # Panicking + /// If a destructor panics, the remaining messages are leaked, matching the + /// behaviour of the unbounded channel. + /// /// # Safety /// This method must only be called when dropping the last receiver. The /// destruction of all other receivers must have been observed with acquire @@ -486,75 +490,47 @@ impl Channel { unsafe fn discard_all_messages(&self, tail: usize) { debug_assert!(self.is_disconnected()); - /// Use a helper struct with a custom `Drop` to ensure all messages are - /// dropped, even if a destructor panicks. - struct DiscardState<'a, T> { - channel: &'a Channel, - head: usize, - tail: usize, - backoff: Backoff, - } + // Only receivers modify `head`, so since we are the last one, + // this value will not change and will not be observed (since + // no new messages can be sent after disconnection). + let mut head = self.head.load(Ordering::Relaxed); + let tail = tail & !self.mark_bit; - impl<'a, T> DiscardState<'a, T> { - fn discard(&mut self) { - loop { - // Deconstruct the head. - let index = self.head & (self.channel.mark_bit - 1); - let lap = self.head & !(self.channel.one_lap - 1); + let backoff = Backoff::new(); + loop { + // Deconstruct the head. + let index = head & (self.mark_bit - 1); + let lap = head & !(self.one_lap - 1); - // Inspect the corresponding slot. - debug_assert!(index < self.channel.buffer.len()); - let slot = unsafe { self.channel.buffer.get_unchecked(index) }; - let stamp = slot.stamp.load(Ordering::Acquire); + // Inspect the corresponding slot. + debug_assert!(index < self.buffer.len()); + let slot = unsafe { self.buffer.get_unchecked(index) }; + let stamp = slot.stamp.load(Ordering::Acquire); - // If the stamp is ahead of the head by 1, we may drop the message. - if self.head + 1 == stamp { - self.head = if index + 1 < self.channel.cap { - // Same lap, incremented index. - // Set to `{ lap: lap, mark: 0, index: index + 1 }`. - self.head + 1 - } else { - // One lap forward, index wraps around to zero. - // Set to `{ lap: lap.wrapping_add(1), mark: 0, index: 0 }`. - lap.wrapping_add(self.channel.one_lap) - }; + // If the stamp is ahead of the head by 1, we may drop the message. + if head + 1 == stamp { + head = if index + 1 < self.cap { + // Same lap, incremented index. + // Set to `{ lap: lap, mark: 0, index: index + 1 }`. + head + 1 + } else { + // One lap forward, index wraps around to zero. + // Set to `{ lap: lap.wrapping_add(1), mark: 0, index: 0 }`. + lap.wrapping_add(self.one_lap) + }; - // We updated the head, so even if this descrutor panics, - // we will not attempt to destroy the slot again. - unsafe { - (*slot.msg.get()).assume_init_drop(); - } - // If the tail equals the head, that means the channel is empty. - } else if self.tail == self.head { - return; - // Otherwise, a sender is about to write into the slot, so we need - // to wait for it to update the stamp. - } else { - self.backoff.spin_heavy(); - } + unsafe { + (*slot.msg.get()).assume_init_drop(); } + // If the tail equals the head, that means the channel is empty. + } else if tail == head { + return; + // Otherwise, a sender is about to write into the slot, so we need + // to wait for it to update the stamp. + } else { + backoff.spin_heavy(); } } - - impl<'a, T> Drop for DiscardState<'a, T> { - fn drop(&mut self) { - self.discard(); - } - } - - let mut state = DiscardState { - channel: self, - // Only receivers modify `head`, so since we are the last one, - // this value will not change and will not be observed (since - // no new messages can be sent after disconnection). - head: self.head.load(Ordering::Relaxed), - tail: tail & !self.mark_bit, - backoff: Backoff::new(), - }; - state.discard(); - // This point is only reached if no destructor panics, so all messages - // have already been dropped. - mem::forget(state); } /// Returns `true` if the channel is disconnected. From c4939f1eb21ebfd0903ad2be751064029289fab9 Mon Sep 17 00:00:00 2001 From: hi-rustin Date: Wed, 15 Mar 2023 20:11:52 +0800 Subject: [PATCH 24/70] Add RANLIB_x86_64_unknown_illumos env for dist-x86_64-illumos dockerfile Signed-off-by: hi-rustin --- src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile index 4e46bdee5acb..2089bf387162 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile @@ -9,10 +9,10 @@ RUN bash /tmp/cross-apt-packages.sh # Required for cross-build gcc RUN apt-get update && \ apt-get install -y --no-install-recommends \ - libgmp-dev \ - libmpfr-dev \ - libmpc-dev \ - && rm -rf /var/lib/apt/lists/* + libgmp-dev \ + libmpfr-dev \ + libmpc-dev \ + && rm -rf /var/lib/apt/lists/* COPY scripts/illumos-toolchain.sh /tmp/ @@ -28,6 +28,7 @@ RUN /scripts/cmake.sh ENV \ AR_x86_64_unknown_illumos=x86_64-illumos-ar \ + RANLIB_x86_64_unknown_illumos=x86_64-illumos-ranlib \ CC_x86_64_unknown_illumos=x86_64-illumos-gcc \ CXX_x86_64_unknown_illumos=x86_64-illumos-g++ From ed63201224308614ed20ff0cdd0bb2cd3c753fa7 Mon Sep 17 00:00:00 2001 From: Boxy Date: Thu, 16 Mar 2023 14:58:26 +0000 Subject: [PATCH 25/70] replace usage of `evaluate_goal` with a new `add_goal` --- .../src/solve/assembly.rs | 45 ++--- .../src/solve/canonical/mod.rs | 17 +- .../src/solve/eval_ctxt.rs | 60 +++++- .../rustc_trait_selection/src/solve/mod.rs | 187 ++++++++++++------ .../src/solve/project_goals.rs | 149 +++++--------- .../src/solve/search_graph/mod.rs | 4 +- .../src/solve/trait_goals.rs | 122 ++++++------ .../solve/trait_goals/structural_traits.rs | 2 +- 8 files changed, 334 insertions(+), 252 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index 891ea0cdebe5..76cde1a66922 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -224,7 +224,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { if goal.predicate.self_ty().is_ty_var() { return vec![Candidate { source: CandidateSource::BuiltinImpl, - result: self.make_canonical_response(Certainty::AMBIGUOUS).unwrap(), + result: self + .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + .unwrap(), }]; } @@ -261,8 +263,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let &ty::Alias(ty::Projection, projection_ty) = goal.predicate.self_ty().kind() else { return }; - self.probe(|this| { - let normalized_ty = this.next_ty_infer(); + + self.probe(|ecx| { + let normalized_ty = ecx.next_ty_infer(); let normalizes_to_goal = goal.with( tcx, ty::Binder::dummy(ty::ProjectionPredicate { @@ -270,28 +273,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { term: normalized_ty.into(), }), ); - let normalization_certainty = match this.evaluate_goal(normalizes_to_goal) { - Ok((_, certainty)) => certainty, - Err(NoSolution) => return, - }; - let normalized_ty = this.resolve_vars_if_possible(normalized_ty); + ecx.add_goal(normalizes_to_goal); + if let Ok(_) = ecx.try_evaluate_added_goals() { + let normalized_ty = ecx.resolve_vars_if_possible(normalized_ty); - // NOTE: Alternatively we could call `evaluate_goal` here and only have a `Normalized` candidate. - // This doesn't work as long as we use `CandidateSource` in winnowing. - let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty)); - let normalized_candidates = this.assemble_and_evaluate_candidates(goal); - for mut normalized_candidate in normalized_candidates { - normalized_candidate.result = - normalized_candidate.result.unchecked_map(|mut response| { - // FIXME: This currently hides overflow in the normalization step of the self type - // which is probably wrong. Maybe `unify_and` should actually keep overflow as - // we treat it as non-fatal anyways. - response.certainty = response.certainty.unify_and(normalization_certainty); - response - }); - candidates.push(normalized_candidate); + // NOTE: Alternatively we could call `evaluate_goal` here and only have a `Normalized` candidate. + // This doesn't work as long as we use `CandidateSource` in winnowing. + let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty)); + candidates.extend(ecx.assemble_and_evaluate_candidates(goal)); } - }) + }); } fn assemble_impl_candidates>( @@ -516,7 +507,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } else { Certainty::AMBIGUOUS }; - return self.make_canonical_response(certainty); + return self.evaluate_added_goals_and_make_canonical_response(certainty); } } @@ -538,14 +529,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } - fn discard_reservation_impl(&self, mut candidate: Candidate<'tcx>) -> Candidate<'tcx> { + fn discard_reservation_impl(&mut self, mut candidate: Candidate<'tcx>) -> Candidate<'tcx> { if let CandidateSource::Impl(def_id) = candidate.source { if let ty::ImplPolarity::Reservation = self.tcx().impl_polarity(def_id) { debug!("Selected reservation impl"); // We assemble all candidates inside of a probe so by // making a new canonical response here our result will // have no constraints. - candidate.result = self.make_canonical_response(Certainty::AMBIGUOUS).unwrap(); + candidate.result = self + .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + .unwrap(); } } diff --git a/compiler/rustc_trait_selection/src/solve/canonical/mod.rs b/compiler/rustc_trait_selection/src/solve/canonical/mod.rs index 8c3be8da16b5..01a011a000ef 100644 --- a/compiler/rustc_trait_selection/src/solve/canonical/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/canonical/mod.rs @@ -48,7 +48,20 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { /// - `external_constraints`: additional constraints which aren't expressable /// using simple unification of inference variables. #[instrument(level = "debug", skip(self))] - pub(super) fn make_canonical_response(&self, certainty: Certainty) -> QueryResult<'tcx> { + pub(super) fn evaluate_added_goals_and_make_canonical_response( + &mut self, + certainty: Certainty, + ) -> QueryResult<'tcx> { + let goals_certainty = self.try_evaluate_added_goals()?; + let certainty = certainty.unify_and(goals_certainty); + + if let Certainty::Yes = certainty { + assert!( + self.nested_goals.is_empty(), + "Cannot be certain of query response if unevaluated goals exist" + ); + } + let external_constraints = self.compute_external_query_constraints()?; let response = Response { var_values: self.var_values, external_constraints, certainty }; @@ -209,7 +222,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // FIXME: To deal with #105787 I also expect us to emit nested obligations here at // some point. We can figure out how to deal with this once we actually have // an ICE. - let nested_goals = self.eq(param_env, orig, response)?; + let nested_goals = self.eq_and_get_goals(param_env, orig, response)?; assert!(nested_goals.is_empty(), "{nested_goals:?}"); } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index 856f1eec4433..1e481f165bec 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -13,8 +13,7 @@ use rustc_middle::ty::{ use rustc_span::DUMMY_SP; use std::ops::ControlFlow; -use super::search_graph::SearchGraph; -use super::Goal; +use super::{search_graph::SearchGraph, Goal}; pub struct EvalCtxt<'a, 'tcx> { // FIXME: should be private. @@ -33,14 +32,35 @@ pub struct EvalCtxt<'a, 'tcx> { pub(super) search_graph: &'a mut SearchGraph<'tcx>, - /// This field is used by a debug assertion in [`EvalCtxt::evaluate_goal`], - /// see the comment in that method for more details. - pub in_projection_eq_hack: bool, + pub(super) nested_goals: NestedGoals<'tcx>, +} + +#[derive(Debug, Clone)] +pub(super) struct NestedGoals<'tcx> { + pub(super) projection_eq_hack_goal: Option>>, + pub(super) goals: Vec>>, +} + +impl NestedGoals<'_> { + pub(super) fn new() -> Self { + Self { projection_eq_hack_goal: None, goals: Vec::new() } + } + + pub(super) fn is_empty(&self) -> bool { + self.projection_eq_hack_goal.is_none() && self.goals.is_empty() + } } impl<'tcx> EvalCtxt<'_, 'tcx> { pub(super) fn probe(&mut self, f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> T) -> T { - self.infcx.probe(|_| f(self)) + let mut ecx = EvalCtxt { + infcx: self.infcx, + var_values: self.var_values, + max_input_universe: self.max_input_universe, + search_graph: self.search_graph, + nested_goals: self.nested_goals.clone(), + }; + self.infcx.probe(|_| f(&mut ecx)) } pub(super) fn tcx(&self) -> TyCtxt<'tcx> { @@ -61,6 +81,15 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ) } + /// Returns a ty infer or a const infer depending on whether `kind` is a `Ty` or `Const`. + /// If `kind` is an integer inference variable this will still return a ty infer var. + pub(super) fn next_term_infer_of_kind(&self, kind: ty::Term<'tcx>) -> ty::Term<'tcx> { + match kind.unpack() { + ty::TermKind::Ty(_) => self.next_ty_infer().into(), + ty::TermKind::Const(ct) => self.next_const_infer(ct.ty()).into(), + } + } + /// Is the projection predicate is of the form `exists ::Assoc = T`. /// /// This is the case if the `term` is an inference variable in the innermost universe @@ -137,6 +166,25 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { #[instrument(level = "debug", skip(self, param_env), ret)] pub(super) fn eq>( + &mut self, + param_env: ty::ParamEnv<'tcx>, + lhs: T, + rhs: T, + ) -> Result<(), NoSolution> { + self.infcx + .at(&ObligationCause::dummy(), param_env) + .eq(DefineOpaqueTypes::No, lhs, rhs) + .map(|InferOk { value: (), obligations }| { + self.add_goals(obligations.into_iter().map(|o| o.into())); + }) + .map_err(|e| { + debug!(?e, "failed to equate"); + NoSolution + }) + } + + #[instrument(level = "debug", skip(self, param_env), ret)] + pub(super) fn eq_and_get_goals>( &self, param_env: ty::ParamEnv<'tcx>, lhs: T, diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index a873060687d3..79e295f6b534 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -45,6 +45,8 @@ mod trait_goals; pub use eval_ctxt::EvalCtxt; pub use fulfill::FulfillmentCtxt; +use self::eval_ctxt::NestedGoals; + trait CanonicalResponseExt { fn has_no_inference_or_external_constraints(&self) -> bool; } @@ -69,6 +71,7 @@ pub trait InferCtxtEvalExt<'tcx> { } impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { + #[instrument(level = "debug", skip(self))] fn evaluate_root_goal( &self, goal: Goal<'tcx, ty::Predicate<'tcx>>, @@ -81,9 +84,9 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { // Only relevant when canonicalizing the response. max_input_universe: ty::UniverseIndex::ROOT, var_values: CanonicalVarValues::dummy(), - in_projection_eq_hack: false, + nested_goals: NestedGoals::new(), } - .evaluate_goal(goal); + .evaluate_goal(false, goal); assert!(search_graph.is_empty()); result @@ -117,7 +120,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { var_values, max_input_universe: canonical_goal.max_universe, search_graph, - in_projection_eq_hack: false, + nested_goals: NestedGoals::new(), }; ecx.compute_goal(goal) }) @@ -127,6 +130,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { /// been constrained and the certainty of the result. fn evaluate_goal( &mut self, + is_projection_eq_hack_goal: bool, goal: Goal<'tcx, ty::Predicate<'tcx>>, ) -> Result<(bool, Certainty), NoSolution> { let (orig_values, canonical_goal) = self.canonicalize_goal(goal); @@ -149,10 +153,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { // solver cycle. if cfg!(debug_assertions) && has_changed - && !self.in_projection_eq_hack + && !is_projection_eq_hack_goal && !self.search_graph.in_cycle() - && false { + debug!("rerunning goal to check result is stable"); let (_orig_values, canonical_goal) = self.canonicalize_goal(goal); let canonical_response = EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?; @@ -202,10 +206,12 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { ty::PredicateKind::WellFormed(arg) => { self.compute_well_formed_goal(Goal { param_env, predicate: arg }) } - ty::PredicateKind::Ambiguous => self.make_canonical_response(Certainty::AMBIGUOUS), + ty::PredicateKind::Ambiguous => { + self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + } // FIXME: implement these predicates :) ty::PredicateKind::ConstEvaluatable(_) | ty::PredicateKind::ConstEquate(_, _) => { - self.make_canonical_response(Certainty::Yes) + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("TypeWellFormedFromEnv is only used for Chalk") @@ -217,20 +223,25 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { } else { let kind = self.infcx.instantiate_binder_with_placeholders(kind); let goal = goal.with(self.tcx(), ty::Binder::dummy(kind)); - let (_, certainty) = self.evaluate_goal(goal)?; - self.make_canonical_response(certainty) + // `false` is fine to use as if this were a projection goal from the hack there would not be + // a binder as the real projection goal that is the parent of the hack goal would have already + // had its binder replaced with placeholders. + let (_, certainty) = self.evaluate_goal(false, goal)?; + self.evaluate_added_goals_and_make_canonical_response(certainty) } } + #[instrument(level = "debug", skip(self))] fn compute_type_outlives_goal( &mut self, goal: Goal<'tcx, TypeOutlivesPredicate<'tcx>>, ) -> QueryResult<'tcx> { let ty::OutlivesPredicate(ty, lt) = goal.predicate; self.infcx.register_region_obligation_with_cause(ty, lt, &ObligationCause::dummy()); - self.make_canonical_response(Certainty::Yes) + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } + #[instrument(level = "debug", skip(self))] fn compute_region_outlives_goal( &mut self, goal: Goal<'tcx, RegionOutlivesPredicate<'tcx>>, @@ -239,9 +250,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { &ObligationCause::dummy(), ty::Binder::dummy(goal.predicate), ); - self.make_canonical_response(Certainty::Yes) + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } + #[instrument(level = "debug", skip(self))] fn compute_coerce_goal( &mut self, goal: Goal<'tcx, CoercePredicate<'tcx>>, @@ -256,6 +268,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { }) } + #[instrument(level = "debug", skip(self))] fn compute_subtype_goal( &mut self, goal: Goal<'tcx, SubtypePredicate<'tcx>>, @@ -263,18 +276,18 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { if goal.predicate.a.is_ty_var() && goal.predicate.b.is_ty_var() { // FIXME: Do we want to register a subtype relation between these vars? // That won't actually reflect in the query response, so it seems moot. - self.make_canonical_response(Certainty::AMBIGUOUS) + self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) } else { let InferOk { value: (), obligations } = self .infcx .at(&ObligationCause::dummy(), goal.param_env) .sub(DefineOpaqueTypes::No, goal.predicate.a, goal.predicate.b)?; - self.evaluate_all_and_make_canonical_response( - obligations.into_iter().map(|pred| pred.into()).collect(), - ) + self.add_goals(obligations.into_iter().map(|pred| pred.into())); + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } + #[instrument(level = "debug", skip(self))] fn compute_closure_kind_goal( &mut self, goal: Goal<'tcx, (DefId, ty::SubstsRef<'tcx>, ty::ClosureKind)>, @@ -283,23 +296,25 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { let found_kind = substs.as_closure().kind_ty().to_opt_closure_kind(); let Some(found_kind) = found_kind else { - return self.make_canonical_response(Certainty::AMBIGUOUS); + return self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); }; if found_kind.extends(expected_kind) { - self.make_canonical_response(Certainty::Yes) + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else { Err(NoSolution) } } + #[instrument(level = "debug", skip(self))] fn compute_object_safe_goal(&mut self, trait_def_id: DefId) -> QueryResult<'tcx> { if self.tcx().check_is_object_safe(trait_def_id) { - self.make_canonical_response(Certainty::Yes) + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else { Err(NoSolution) } } + #[instrument(level = "debug", skip(self))] fn compute_well_formed_goal( &mut self, goal: Goal<'tcx, ty::GenericArg<'tcx>>, @@ -309,10 +324,11 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { goal.param_env, goal.predicate, ) { - Some(obligations) => self.evaluate_all_and_make_canonical_response( - obligations.into_iter().map(|o| o.into()).collect(), - ), - None => self.make_canonical_response(Certainty::AMBIGUOUS), + Some(obligations) => { + self.add_goals(obligations.into_iter().map(|o| o.into())); + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + None => self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS), } } @@ -326,14 +342,14 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { let evaluate_normalizes_to = |ecx: &mut EvalCtxt<'_, 'tcx>, alias, other| { debug!("evaluate_normalizes_to(alias={:?}, other={:?})", alias, other); let r = ecx.probe(|ecx| { - let (_, certainty) = ecx.evaluate_goal(goal.with( + ecx.add_goal(goal.with( tcx, ty::Binder::dummy(ty::ProjectionPredicate { projection_ty: alias, term: other, }), - ))?; - ecx.make_canonical_response(certainty) + )); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }); debug!("evaluate_normalizes_to(..) -> {:?}", r); r @@ -360,10 +376,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { // Evaluate all 3 potential candidates for the alias' being equal candidates.push(evaluate_normalizes_to(self, alias_lhs, goal.predicate.1)); candidates.push(evaluate_normalizes_to(self, alias_rhs, goal.predicate.0)); - candidates.push(self.probe(|this| { + candidates.push(self.probe(|ecx| { debug!("compute_alias_eq_goal: alias defids are equal, equating substs"); - let nested_goals = this.eq(goal.param_env, alias_lhs, alias_rhs)?; - this.evaluate_all_and_make_canonical_response(nested_goals) + ecx.eq(goal.param_env, alias_lhs, alias_rhs)?; + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) })); debug!(?candidates); @@ -379,25 +395,92 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { goal: Goal<'tcx, (ty::Const<'tcx>, Ty<'tcx>)>, ) -> QueryResult<'tcx> { let (ct, ty) = goal.predicate; - let nested_goals = self.eq(goal.param_env, ct.ty(), ty)?; - self.evaluate_all_and_make_canonical_response(nested_goals) + self.eq(goal.param_env, ct.ty(), ty)?; + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } impl<'tcx> EvalCtxt<'_, 'tcx> { - // Recursively evaluates a list of goals to completion, returning the certainty - // of all of the goals. - fn evaluate_all( - &mut self, - mut goals: Vec>>, - ) -> Result { - let mut new_goals = Vec::new(); - self.repeat_while_none( + #[instrument(level = "debug", skip(self))] + fn set_projection_eq_hack_goal(&mut self, goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>) { + assert!( + self.nested_goals.projection_eq_hack_goal.is_none(), + "attempted to set the projection eq hack goal when one already exists" + ); + self.nested_goals.projection_eq_hack_goal = Some(goal); + } + + #[instrument(level = "debug", skip(self))] + fn add_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) { + self.nested_goals.goals.push(goal); + } + + #[instrument(level = "debug", skip(self, goals))] + fn add_goals(&mut self, goals: impl IntoIterator>>) { + let current_len = self.nested_goals.goals.len(); + self.nested_goals.goals.extend(goals); + debug!("added_goals={:?}", &self.nested_goals.goals[current_len..]); + } + + // Recursively evaluates all the goals added to this `EvalCtxt` to completion, returning + // the certainty of all the goals. + #[instrument(level = "debug", skip(self))] + fn try_evaluate_added_goals(&mut self) -> Result { + let mut goals = core::mem::replace(&mut self.nested_goals, NestedGoals::new()); + let mut new_goals = NestedGoals::new(); + + let response = self.repeat_while_none( |_| Ok(Certainty::Maybe(MaybeCause::Overflow)), |this| { let mut has_changed = Err(Certainty::Yes); - for goal in goals.drain(..) { - let (changed, certainty) = match this.evaluate_goal(goal) { + + if let Some(goal) = goals.projection_eq_hack_goal.take() { + let (_, certainty) = match this.evaluate_goal( + true, + goal.with(this.tcx(), ty::Binder::dummy(goal.predicate)), + ) { + Ok(r) => r, + Err(NoSolution) => return Some(Err(NoSolution)), + }; + + if goal.predicate.projection_ty + != this.resolve_vars_if_possible(goal.predicate.projection_ty) + { + has_changed = Ok(()) + } + + match certainty { + Certainty::Yes => {} + Certainty::Maybe(_) => { + let goal = this.resolve_vars_if_possible(goal); + + // The rhs of this `normalizes-to` must always be an unconstrained infer var as it is + // the hack used by `normalizes-to` to ensure that every `normalizes-to` behaves the same + // regardless of the rhs. + // + // However it is important not to unconditionally replace the rhs with a new infer var + // as otherwise we may replace the original unconstrained infer var with a new infer var + // and never propagate any constraints on the new var back to the original var. + let term = this + .term_is_fully_unconstrained(goal) + .then_some(goal.predicate.term) + .unwrap_or_else(|| { + this.next_term_infer_of_kind(goal.predicate.term) + }); + let projection_pred = ty::ProjectionPredicate { + term, + projection_ty: goal.predicate.projection_ty, + }; + new_goals.projection_eq_hack_goal = + Some(goal.with(this.tcx(), projection_pred)); + + has_changed = has_changed.map_err(|c| c.unify_and(certainty)); + } + } + } + + for nested_goal in goals.goals.drain(..) { + let (changed, certainty) = match this.evaluate_goal(false, nested_goal) { Ok(result) => result, Err(NoSolution) => return Some(Err(NoSolution)), }; @@ -409,32 +492,22 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { match certainty { Certainty::Yes => {} Certainty::Maybe(_) => { - new_goals.push(goal); + new_goals.goals.push(nested_goal); has_changed = has_changed.map_err(|c| c.unify_and(certainty)); } } } + mem::swap(&mut new_goals, &mut goals); match has_changed { - Ok(()) => { - mem::swap(&mut new_goals, &mut goals); - None - } + Ok(()) => None, Err(certainty) => Some(Ok(certainty)), } }, - ) - } + ); - // Recursively evaluates a list of goals to completion, making a query response. - // - // This is just a convenient way of calling [`EvalCtxt::evaluate_all`], - // then [`EvalCtxt::make_canonical_response`]. - fn evaluate_all_and_make_canonical_response( - &mut self, - goals: Vec>>, - ) -> QueryResult<'tcx> { - self.evaluate_all(goals).and_then(|certainty| self.make_canonical_response(certainty)) + self.nested_goals = goals; + response } fn try_merge_responses( @@ -466,7 +539,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { }); // FIXME(-Ztrait-solver=next): We should take the intersection of the constraints on all the // responses and use that for the constraints of this ambiguous response. - let response = self.make_canonical_response(certainty); + let response = self.evaluate_added_goals_and_make_canonical_response(certainty); if let Ok(response) = &response { assert!(response.has_no_inference_or_external_constraints()); } diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index dbb8e722c8f6..b054a2bda1fe 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -20,6 +20,7 @@ use rustc_span::{sym, DUMMY_SP}; use std::iter; impl<'tcx> EvalCtxt<'_, 'tcx> { + #[instrument(level = "debug", skip(self), ret)] pub(super) fn compute_projection_goal( &mut self, goal: Goal<'tcx, ProjectionPredicate<'tcx>>, @@ -36,54 +37,18 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.merge_candidates_and_discard_reservation_impls(candidates) } else { let predicate = goal.predicate; - let unconstrained_rhs = match predicate.term.unpack() { - ty::TermKind::Ty(_) => self.next_ty_infer().into(), - ty::TermKind::Const(ct) => self.next_const_infer(ct.ty()).into(), - }; - let unconstrained_predicate = ty::Clause::Projection(ProjectionPredicate { + let unconstrained_rhs = self.next_term_infer_of_kind(predicate.term); + let unconstrained_predicate = ProjectionPredicate { projection_ty: goal.predicate.projection_ty, term: unconstrained_rhs, - }); - let (_has_changed, normalize_certainty) = self.in_projection_eq_hack(|this| { - this.evaluate_goal(goal.with(this.tcx(), unconstrained_predicate)) - })?; + }; - let nested_eq_goals = self.eq(goal.param_env, unconstrained_rhs, predicate.term)?; - let eval_certainty = self.evaluate_all(nested_eq_goals)?; - self.make_canonical_response(normalize_certainty.unify_and(eval_certainty)) + self.set_projection_eq_hack_goal(goal.with(self.tcx(), unconstrained_predicate)); + self.try_evaluate_added_goals()?; + self.eq(goal.param_env, unconstrained_rhs, predicate.term)?; + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } - - /// This sets a flag used by a debug assert in [`EvalCtxt::evaluate_goal`], - /// see the comment in that method for more details. - fn in_projection_eq_hack(&mut self, f: impl FnOnce(&mut Self) -> T) -> T { - self.in_projection_eq_hack = true; - let result = f(self); - self.in_projection_eq_hack = false; - result - } - - /// After normalizing the projection to `normalized_alias` with the given - /// `normalization_certainty`, constrain the inference variable `term` to it - /// and return a query response. - fn eq_term_and_make_canonical_response( - &mut self, - goal: Goal<'tcx, ProjectionPredicate<'tcx>>, - normalization_certainty: Certainty, - normalized_alias: impl Into>, - ) -> QueryResult<'tcx> { - // The term of our goal should be fully unconstrained, so this should never fail. - // - // It can however be ambiguous when the `normalized_alias` contains a projection. - let nested_goals = self - .eq(goal.param_env, goal.predicate.term, normalized_alias.into()) - .expect("failed to unify with unconstrained term"); - - let unify_certainty = - self.evaluate_all(nested_goals).expect("failed to unify with unconstrained term"); - - self.make_canonical_response(normalization_certainty.unify_and(unify_certainty)) - } } impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { @@ -111,19 +76,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ecx.probe(|ecx| { let assumption_projection_pred = ecx.instantiate_binder_with_infer(poly_projection_pred); - let mut nested_goals = ecx.eq( + ecx.eq( goal.param_env, goal.predicate.projection_ty, assumption_projection_pred.projection_ty, )?; - nested_goals.extend(requirements); - let subst_certainty = ecx.evaluate_all(nested_goals)?; - - ecx.eq_term_and_make_canonical_response( - goal, - subst_certainty, - assumption_projection_pred.term, - ) + ecx.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term)?; + ecx.add_goals(requirements); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } else { Err(NoSolution) @@ -139,21 +99,22 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { && poly_projection_pred.projection_def_id() == goal.predicate.def_id() { ecx.probe(|ecx| { + let tcx = ecx.tcx(); + let assumption_projection_pred = ecx.instantiate_binder_with_infer(poly_projection_pred); - let mut nested_goals = ecx.eq( + ecx.eq( goal.param_env, goal.predicate.projection_ty, assumption_projection_pred.projection_ty, )?; - let tcx = ecx.tcx(); let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else { bug!("expected object type in `consider_object_bound_candidate`"); }; - nested_goals.extend( + ecx.add_goals( structural_traits::predicates_for_object_candidate( - ecx, + &ecx, goal.param_env, goal.predicate.projection_ty.trait_ref(tcx), bounds, @@ -161,14 +122,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { .into_iter() .map(|pred| goal.with(tcx, pred)), ); - - let subst_certainty = ecx.evaluate_all(nested_goals)?; - - ecx.eq_term_and_make_canonical_response( - goal, - subst_certainty, - assumption_projection_pred.term, - ) + ecx.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term)?; + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } else { Err(NoSolution) @@ -195,16 +150,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { let impl_substs = ecx.fresh_substs_for_item(impl_def_id); let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); - let mut nested_goals = ecx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?; + ecx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?; + let where_clause_bounds = tcx .predicates_of(impl_def_id) .instantiate(tcx, impl_substs) .predicates .into_iter() .map(|pred| goal.with(tcx, pred)); - - nested_goals.extend(where_clause_bounds); - let match_impl_certainty = ecx.evaluate_all(nested_goals)?; + ecx.add_goals(where_clause_bounds); // In case the associated item is hidden due to specialization, we have to // return ambiguity this would otherwise be incomplete, resulting in @@ -216,7 +170,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { goal.predicate.def_id(), impl_def_id )? else { - return ecx.make_canonical_response(match_impl_certainty.unify_and(Certainty::AMBIGUOUS)); + return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); }; if !assoc_def.item.defaultness(tcx).has_value() { @@ -263,7 +217,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ty.map_bound(|ty| ty.into()) }; - ecx.eq_term_and_make_canonical_response(goal, match_impl_certainty, term.subst(tcx, substs)) + ecx.eq(goal.param_env, goal.predicate.term, term.subst(tcx, substs))?; + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } @@ -308,14 +263,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { goal_kind: ty::ClosureKind, ) -> QueryResult<'tcx> { let tcx = ecx.tcx(); - let Some(tupled_inputs_and_output) = - structural_traits::extract_tupled_inputs_and_output_from_callable( - tcx, - goal.predicate.self_ty(), - goal_kind, - )? else { - return ecx.make_canonical_response(Certainty::AMBIGUOUS); - }; + let tupled_inputs_and_output = + match structural_traits::extract_tupled_inputs_and_output_from_callable( + tcx, + goal.predicate.self_ty(), + goal_kind, + )? { + Some(tupled_inputs_and_output) => tupled_inputs_and_output, + None => { + return ecx + .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); + } + }; let output_is_sized_pred = tupled_inputs_and_output .map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output])); @@ -380,13 +339,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { [ty::GenericArg::from(goal.predicate.self_ty())], )); - let (_, is_sized_certainty) = - ecx.evaluate_goal(goal.with(tcx, sized_predicate))?; - return ecx.eq_term_and_make_canonical_response( - goal, - is_sized_certainty, - tcx.types.unit, - ); + ecx.add_goal(goal.with(tcx, sized_predicate)); + ecx.eq(goal.param_env, goal.predicate.term, tcx.types.unit.into())?; + return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); } ty::Adt(def, substs) if def.is_struct() => { @@ -394,12 +349,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { None => tcx.types.unit, Some(field_def) => { let self_ty = field_def.ty(tcx, substs); - let new_goal = goal.with( + ecx.add_goal(goal.with( tcx, ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)), - ); - let (_, certainty) = ecx.evaluate_goal(new_goal)?; - return ecx.make_canonical_response(certainty); + )); + return ecx + .evaluate_added_goals_and_make_canonical_response(Certainty::Yes); } } } @@ -408,12 +363,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ty::Tuple(elements) => match elements.last() { None => tcx.types.unit, Some(&self_ty) => { - let new_goal = goal.with( + ecx.add_goal(goal.with( tcx, ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)), - ); - let (_, certainty) = ecx.evaluate_goal(new_goal)?; - return ecx.make_canonical_response(certainty); + )); + return ecx + .evaluate_added_goals_and_make_canonical_response(Certainty::Yes); } }, @@ -426,7 +381,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ), }; - ecx.eq_term_and_make_canonical_response(goal, Certainty::Yes, metadata_ty) + ecx.eq(goal.param_env, goal.predicate.term, metadata_ty.into())?; + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } @@ -522,7 +478,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { let discriminant = goal.predicate.self_ty().discriminant_ty(ecx.tcx()); - ecx.probe(|ecx| ecx.eq_term_and_make_canonical_response(goal, Certainty::Yes, discriminant)) + ecx.probe(|ecx| { + ecx.eq(goal.param_env, goal.predicate.term, discriminant.into())?; + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) } } diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs index f1b840aac556..83d77a69c002 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs @@ -39,9 +39,7 @@ impl<'tcx> SearchGraph<'tcx> { } pub(super) fn is_empty(&self) -> bool { - self.stack.is_empty() - && self.provisional_cache.is_empty() - && !self.overflow_data.did_overflow() + self.stack.is_empty() && self.provisional_cache.is_empty() } /// Whether we're currently in a cycle. This should only be used diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 7878539817cf..108e1d0b13ff 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -47,16 +47,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { let impl_substs = ecx.fresh_substs_for_item(impl_def_id); let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); - let mut nested_goals = - ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?; + ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?; let where_clause_bounds = tcx .predicates_of(impl_def_id) .instantiate(tcx, impl_substs) .predicates .into_iter() .map(|pred| goal.with(tcx, pred)); - nested_goals.extend(where_clause_bounds); - ecx.evaluate_all_and_make_canonical_response(nested_goals) + ecx.add_goals(where_clause_bounds); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } @@ -73,13 +72,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx.probe(|ecx| { let assumption_trait_pred = ecx.instantiate_binder_with_infer(poly_trait_pred); - let mut nested_goals = ecx.eq( + ecx.eq( goal.param_env, goal.predicate.trait_ref, assumption_trait_pred.trait_ref, )?; - nested_goals.extend(requirements); - ecx.evaluate_all_and_make_canonical_response(nested_goals) + ecx.add_goals(requirements); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } else { Err(NoSolution) @@ -98,7 +97,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx.probe(|ecx| { let assumption_trait_pred = ecx.instantiate_binder_with_infer(poly_trait_pred); - let mut nested_goals = ecx.eq( + ecx.eq( goal.param_env, goal.predicate.trait_ref, assumption_trait_pred.trait_ref, @@ -108,9 +107,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else { bug!("expected object type in `consider_object_bound_candidate`"); }; - nested_goals.extend( + ecx.add_goals( structural_traits::predicates_for_object_candidate( - ecx, + &ecx, goal.param_env, goal.predicate.trait_ref, bounds, @@ -118,8 +117,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { .into_iter() .map(|pred| goal.with(tcx, pred)), ); - - ecx.evaluate_all_and_make_canonical_response(nested_goals) + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } else { Err(NoSolution) @@ -166,9 +164,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { let nested_obligations = tcx .predicates_of(goal.predicate.def_id()) .instantiate(tcx, goal.predicate.trait_ref.substs); - ecx.evaluate_all_and_make_canonical_response( - nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p)).collect(), - ) + ecx.add_goals(nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p))); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } @@ -197,7 +194,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { if goal.predicate.self_ty().has_non_region_infer() { - return ecx.make_canonical_response(Certainty::AMBIGUOUS); + return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); } let tcx = ecx.tcx(); @@ -209,7 +206,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { && layout.layout.align().abi == usize_layout.align().abi { // FIXME: We could make this faster by making a no-constraints response - ecx.make_canonical_response(Certainty::Yes) + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else { Err(NoSolution) } @@ -227,7 +224,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { goal.predicate.self_ty(), goal_kind, )? else { - return ecx.make_canonical_response(Certainty::AMBIGUOUS); + return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); }; let output_is_sized_pred = tupled_inputs_and_output .map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output])); @@ -247,7 +244,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { if let ty::Tuple(..) = goal.predicate.self_ty().kind() { - ecx.make_canonical_response(Certainty::Yes) + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else { Err(NoSolution) } @@ -257,7 +254,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, _goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { - ecx.make_canonical_response(Certainty::Yes) + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } fn consider_builtin_future_candidate( @@ -277,7 +274,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { // Async generator unconditionally implement `Future` // Technically, we need to check that the future output type is Sized, // but that's already proven by the generator being WF. - ecx.make_canonical_response(Certainty::Yes) + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } fn consider_builtin_generator_candidate( @@ -317,7 +314,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { let a_ty = goal.predicate.self_ty(); let b_ty = goal.predicate.trait_ref.substs.type_at(1); if b_ty.is_ty_var() { - return ecx.make_canonical_response(Certainty::AMBIGUOUS); + return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); } ecx.probe(|ecx| { match (a_ty.kind(), b_ty.kind()) { @@ -326,7 +323,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { // Dyn upcasting is handled separately, since due to upcasting, // when there are two supertraits that differ by substs, we // may return more than one query response. - return Err(NoSolution); + Err(NoSolution) } // `T` -> `dyn Trait` unsizing (_, &ty::Dynamic(data, region, ty::Dyn)) => { @@ -341,29 +338,31 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { let Some(sized_def_id) = tcx.lang_items().sized_trait() else { return Err(NoSolution); }; - let nested_goals: Vec<_> = data - .iter() - // Check that the type implements all of the predicates of the def-id. - // (i.e. the principal, all of the associated types match, and any auto traits) - .map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))) - .chain([ - // The type must be Sized to be unsized. - goal.with( - tcx, - ty::Binder::dummy(tcx.mk_trait_ref(sized_def_id, [a_ty])), - ), - // The type must outlive the lifetime of the `dyn` we're unsizing into. - goal.with(tcx, ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region))), - ]) - .collect(); - - ecx.evaluate_all_and_make_canonical_response(nested_goals) + ecx.add_goals( + data.iter() + // Check that the type implements all of the predicates of the def-id. + // (i.e. the principal, all of the associated types match, and any auto traits) + .map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))) + .chain([ + // The type must be Sized to be unsized. + goal.with( + tcx, + ty::Binder::dummy(tcx.mk_trait_ref(sized_def_id, [a_ty])), + ), + // The type must outlive the lifetime of the `dyn` we're unsizing into. + goal.with( + tcx, + ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region)), + ), + ]), + ); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } // `[T; n]` -> `[T]` unsizing (&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => { // We just require that the element type stays the same - let nested_goals = ecx.eq(goal.param_env, a_elem_ty, b_elem_ty)?; - ecx.evaluate_all_and_make_canonical_response(nested_goals) + ecx.eq(goal.param_env, a_elem_ty, b_elem_ty)?; + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } // Struct unsizing `Struct` -> `Struct` where `T: Unsize` (&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs)) @@ -397,15 +396,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { // Finally, we require that `TailA: Unsize` for the tail field // types. - let mut nested_goals = ecx.eq(goal.param_env, unsized_a_ty, b_ty)?; - nested_goals.push(goal.with( + ecx.eq(goal.param_env, unsized_a_ty, b_ty)?; + ecx.add_goal(goal.with( tcx, ty::Binder::dummy( tcx.mk_trait_ref(goal.predicate.def_id(), [a_tail_ty, b_tail_ty]), ), )); - - ecx.evaluate_all_and_make_canonical_response(nested_goals) + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } // Tuple unsizing `(.., T)` -> `(.., U)` where `T: Unsize` (&ty::Tuple(a_tys), &ty::Tuple(b_tys)) @@ -417,17 +415,16 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { // Substitute just the tail field of B., and require that they're equal. let unsized_a_ty = tcx.mk_tup_from_iter(a_rest_tys.iter().chain([b_last_ty]).copied()); - let mut nested_goals = ecx.eq(goal.param_env, unsized_a_ty, b_ty)?; + ecx.eq(goal.param_env, unsized_a_ty, b_ty)?; // Similar to ADTs, require that the rest of the fields are equal. - nested_goals.push(goal.with( + ecx.add_goal(goal.with( tcx, ty::Binder::dummy( tcx.mk_trait_ref(goal.predicate.def_id(), [*a_last_ty, *b_last_ty]), ), )); - - ecx.evaluate_all_and_make_canonical_response(nested_goals) + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } _ => Err(NoSolution), } @@ -477,12 +474,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { let new_a_ty = tcx.mk_dynamic(new_a_data, b_region, ty::Dyn); // We also require that A's lifetime outlives B's lifetime. - let mut nested_obligations = ecx.eq(goal.param_env, new_a_ty, b_ty)?; - nested_obligations.push( + ecx.eq(goal.param_env, new_a_ty, b_ty)?; + ecx.add_goal( goal.with(tcx, ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region))), ); - - ecx.evaluate_all_and_make_canonical_response(nested_obligations) + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) }; @@ -516,7 +512,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { _goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { // `DiscriminantKind` is automatically implemented for every type. - ecx.make_canonical_response(Certainty::Yes) + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } @@ -530,21 +526,23 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { goal: Goal<'tcx, TraitPredicate<'tcx>>, constituent_tys: impl Fn(&EvalCtxt<'_, 'tcx>, Ty<'tcx>) -> Result>, NoSolution>, ) -> QueryResult<'tcx> { - self.probe(|this| { - this.evaluate_all_and_make_canonical_response( - constituent_tys(this, goal.predicate.self_ty())? + self.probe(|ecx| { + ecx.add_goals( + constituent_tys(ecx, goal.predicate.self_ty())? .into_iter() .map(|ty| { goal.with( - this.tcx(), - ty::Binder::dummy(goal.predicate.with_self_ty(this.tcx(), ty)), + ecx.tcx(), + ty::Binder::dummy(goal.predicate.with_self_ty(ecx.tcx(), ty)), ) }) - .collect(), - ) + .collect::>(), + ); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } + #[instrument(level = "debug", skip(self))] pub(super) fn compute_trait_goal( &mut self, goal: Goal<'tcx, TraitPredicate<'tcx>>, diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs index d7d93377cf16..871e7c2cc5ac 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs @@ -333,7 +333,7 @@ impl<'tcx> TypeFolder> for ReplaceProjectionWith<'_, 'tcx> { // FIXME: Technically this folder could be fallible? let nested = self .ecx - .eq(self.param_env, alias_ty, proj.projection_ty) + .eq_and_get_goals(self.param_env, alias_ty, proj.projection_ty) .expect("expected to be able to unify goal projection with dyn's projection"); // FIXME: Technically we could register these too.. assert!(nested.is_empty(), "did not expect unification to have any nested goals"); From ee31e5fc57499cd7a97b7e0564425324b0186688 Mon Sep 17 00:00:00 2001 From: Boxy Date: Fri, 17 Mar 2023 13:33:27 +0000 Subject: [PATCH 26/70] review nits --- .../src/solve/eval_ctxt.rs | 6 +++++ .../rustc_trait_selection/src/solve/mod.rs | 26 +++++++++---------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index 1e481f165bec..20ed572df80d 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -35,6 +35,12 @@ pub struct EvalCtxt<'a, 'tcx> { pub(super) nested_goals: NestedGoals<'tcx>, } +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub(super) enum IsNormalizesToHack { + Yes, + No, +} + #[derive(Debug, Clone)] pub(super) struct NestedGoals<'tcx> { pub(super) projection_eq_hack_goal: Option>>, diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 79e295f6b534..089c5f8fb4df 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -45,7 +45,7 @@ mod trait_goals; pub use eval_ctxt::EvalCtxt; pub use fulfill::FulfillmentCtxt; -use self::eval_ctxt::NestedGoals; +use self::eval_ctxt::{IsNormalizesToHack, NestedGoals}; trait CanonicalResponseExt { fn has_no_inference_or_external_constraints(&self) -> bool; @@ -86,7 +86,7 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { var_values: CanonicalVarValues::dummy(), nested_goals: NestedGoals::new(), } - .evaluate_goal(false, goal); + .evaluate_goal(IsNormalizesToHack::No, goal); assert!(search_graph.is_empty()); result @@ -130,7 +130,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { /// been constrained and the certainty of the result. fn evaluate_goal( &mut self, - is_projection_eq_hack_goal: bool, + is_normalizes_to_hack: IsNormalizesToHack, goal: Goal<'tcx, ty::Predicate<'tcx>>, ) -> Result<(bool, Certainty), NoSolution> { let (orig_values, canonical_goal) = self.canonicalize_goal(goal); @@ -153,7 +153,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { // solver cycle. if cfg!(debug_assertions) && has_changed - && !is_projection_eq_hack_goal + && is_normalizes_to_hack == IsNormalizesToHack::No && !self.search_graph.in_cycle() { debug!("rerunning goal to check result is stable"); @@ -223,11 +223,8 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { } else { let kind = self.infcx.instantiate_binder_with_placeholders(kind); let goal = goal.with(self.tcx(), ty::Binder::dummy(kind)); - // `false` is fine to use as if this were a projection goal from the hack there would not be - // a binder as the real projection goal that is the parent of the hack goal would have already - // had its binder replaced with placeholders. - let (_, certainty) = self.evaluate_goal(false, goal)?; - self.evaluate_added_goals_and_make_canonical_response(certainty) + self.add_goal(goal); + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } @@ -436,7 +433,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { if let Some(goal) = goals.projection_eq_hack_goal.take() { let (_, certainty) = match this.evaluate_goal( - true, + IsNormalizesToHack::Yes, goal.with(this.tcx(), ty::Binder::dummy(goal.predicate)), ) { Ok(r) => r, @@ -480,10 +477,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } for nested_goal in goals.goals.drain(..) { - let (changed, certainty) = match this.evaluate_goal(false, nested_goal) { - Ok(result) => result, - Err(NoSolution) => return Some(Err(NoSolution)), - }; + let (changed, certainty) = + match this.evaluate_goal(IsNormalizesToHack::No, nested_goal) { + Ok(result) => result, + Err(NoSolution) => return Some(Err(NoSolution)), + }; if changed { has_changed = Ok(()); From ea08d3a47cee34f9943a2ca850ac7b3435fb499e Mon Sep 17 00:00:00 2001 From: Boxy Date: Fri, 17 Mar 2023 13:37:47 +0000 Subject: [PATCH 27/70] add assert --- compiler/rustc_trait_selection/src/solve/mod.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 089c5f8fb4df..ba68ff1c2e33 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -78,15 +78,22 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { ) -> Result<(bool, Certainty), NoSolution> { let mut search_graph = search_graph::SearchGraph::new(self.tcx); - let result = EvalCtxt { + let mut ecx = EvalCtxt { search_graph: &mut search_graph, infcx: self, // Only relevant when canonicalizing the response. max_input_universe: ty::UniverseIndex::ROOT, var_values: CanonicalVarValues::dummy(), nested_goals: NestedGoals::new(), + }; + let result = ecx.evaluate_goal(IsNormalizesToHack::No, goal); + + if let Ok((_, Certainty::Yes)) = result { + assert!( + ecx.nested_goals.is_empty(), + "Cannot be certain of query response if unevaluated goals exist" + ); } - .evaluate_goal(IsNormalizesToHack::No, goal); assert!(search_graph.is_empty()); result From ce14a1eba0a9dd4c4bc5394ee53a8d1756796a9e Mon Sep 17 00:00:00 2001 From: Boxy Date: Fri, 17 Mar 2023 13:34:20 +0000 Subject: [PATCH 28/70] add comments Co-authored-by: lcnr --- compiler/rustc_trait_selection/src/solve/eval_ctxt.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index 20ed572df80d..be138e0ab54b 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -189,6 +189,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { }) } + /// Equates two values returning the nested goals without adding them + /// to the nested goals of the `EvalCtxt`. + /// + /// If possible, try using `eq` instead which automatically handles nested + /// goals correctly. #[instrument(level = "debug", skip(self, param_env), ret)] pub(super) fn eq_and_get_goals>( &self, From e06c62cd5bd84e109f8fe409102c446f53b7f4c9 Mon Sep 17 00:00:00 2001 From: Boxy Date: Fri, 17 Mar 2023 14:04:39 +0000 Subject: [PATCH 29/70] UNACEPTABLE --- compiler/rustc_trait_selection/src/solve/eval_ctxt.rs | 6 +++--- compiler/rustc_trait_selection/src/solve/mod.rs | 10 +++++----- .../rustc_trait_selection/src/solve/project_goals.rs | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index be138e0ab54b..80828d5c1d5a 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -43,17 +43,17 @@ pub(super) enum IsNormalizesToHack { #[derive(Debug, Clone)] pub(super) struct NestedGoals<'tcx> { - pub(super) projection_eq_hack_goal: Option>>, + pub(super) normalizes_to_hack_goal: Option>>, pub(super) goals: Vec>>, } impl NestedGoals<'_> { pub(super) fn new() -> Self { - Self { projection_eq_hack_goal: None, goals: Vec::new() } + Self { normalizes_to_hack_goal: None, goals: Vec::new() } } pub(super) fn is_empty(&self) -> bool { - self.projection_eq_hack_goal.is_none() && self.goals.is_empty() + self.normalizes_to_hack_goal.is_none() && self.goals.is_empty() } } diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index ba68ff1c2e33..13d6602b7e12 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -406,12 +406,12 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { impl<'tcx> EvalCtxt<'_, 'tcx> { #[instrument(level = "debug", skip(self))] - fn set_projection_eq_hack_goal(&mut self, goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>) { + fn set_normalizes_to_hack_goal(&mut self, goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>) { assert!( - self.nested_goals.projection_eq_hack_goal.is_none(), + self.nested_goals.normalizes_to_hack_goal.is_none(), "attempted to set the projection eq hack goal when one already exists" ); - self.nested_goals.projection_eq_hack_goal = Some(goal); + self.nested_goals.normalizes_to_hack_goal = Some(goal); } #[instrument(level = "debug", skip(self))] @@ -438,7 +438,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { |this| { let mut has_changed = Err(Certainty::Yes); - if let Some(goal) = goals.projection_eq_hack_goal.take() { + if let Some(goal) = goals.normalizes_to_hack_goal.take() { let (_, certainty) = match this.evaluate_goal( IsNormalizesToHack::Yes, goal.with(this.tcx(), ty::Binder::dummy(goal.predicate)), @@ -475,7 +475,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { term, projection_ty: goal.predicate.projection_ty, }; - new_goals.projection_eq_hack_goal = + new_goals.normalizes_to_hack_goal = Some(goal.with(this.tcx(), projection_pred)); has_changed = has_changed.map_err(|c| c.unify_and(certainty)); diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index b054a2bda1fe..93d77c39f958 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -43,7 +43,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { term: unconstrained_rhs, }; - self.set_projection_eq_hack_goal(goal.with(self.tcx(), unconstrained_predicate)); + self.set_normalizes_to_hack_goal(goal.with(self.tcx(), unconstrained_predicate)); self.try_evaluate_added_goals()?; self.eq(goal.param_env, unconstrained_rhs, predicate.term)?; self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) From aa8de179283b4c9aac6039ad2b04529ed6055680 Mon Sep 17 00:00:00 2001 From: Boxy Date: Fri, 17 Mar 2023 14:12:59 +0000 Subject: [PATCH 30/70] fix let else unformatting --- .../rustc_trait_selection/src/solve/trait_goals.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 108e1d0b13ff..9951c87f4fc3 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -218,14 +218,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { goal_kind: ty::ClosureKind, ) -> QueryResult<'tcx> { let tcx = ecx.tcx(); - let Some(tupled_inputs_and_output) = - structural_traits::extract_tupled_inputs_and_output_from_callable( + let tupled_inputs_and_output = + match structural_traits::extract_tupled_inputs_and_output_from_callable( tcx, goal.predicate.self_ty(), goal_kind, - )? else { - return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); - }; + )? { + Some(a) => a, + None => { + return ecx + .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); + } + }; let output_is_sized_pred = tupled_inputs_and_output .map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output])); From e624ef4d64cc800b9d69104bd3f77fc10d65080b Mon Sep 17 00:00:00 2001 From: Boxy Date: Fri, 17 Mar 2023 14:35:12 +0000 Subject: [PATCH 31/70] replace chain with two `add_goal` --- .../src/solve/trait_goals.rs | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 9951c87f4fc3..8ab55c79fc45 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -342,23 +342,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { let Some(sized_def_id) = tcx.lang_items().sized_trait() else { return Err(NoSolution); }; + // Check that the type implements all of the predicates of the def-id. + // (i.e. the principal, all of the associated types match, and any auto traits) ecx.add_goals( - data.iter() - // Check that the type implements all of the predicates of the def-id. - // (i.e. the principal, all of the associated types match, and any auto traits) - .map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))) - .chain([ - // The type must be Sized to be unsized. - goal.with( - tcx, - ty::Binder::dummy(tcx.mk_trait_ref(sized_def_id, [a_ty])), - ), - // The type must outlive the lifetime of the `dyn` we're unsizing into. - goal.with( - tcx, - ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region)), - ), - ]), + data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))), + ); + // The type must be Sized to be unsized. + ecx.add_goal( + goal.with(tcx, ty::Binder::dummy(tcx.mk_trait_ref(sized_def_id, [a_ty]))), + ); + // The type must outlive the lifetime of the `dyn` we're unsizing into. + ecx.add_goal( + goal.with(tcx, ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region))), ); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } From 9df35a5050e49b17bae559a074cb30798f8ca6da Mon Sep 17 00:00:00 2001 From: Boxy Date: Fri, 17 Mar 2023 14:40:16 +0000 Subject: [PATCH 32/70] fix bad assertion --- .../rustc_trait_selection/src/solve/canonical/mod.rs | 7 ------- compiler/rustc_trait_selection/src/solve/mod.rs | 10 ++++------ 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/canonical/mod.rs b/compiler/rustc_trait_selection/src/solve/canonical/mod.rs index 01a011a000ef..9d45e78ebab0 100644 --- a/compiler/rustc_trait_selection/src/solve/canonical/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/canonical/mod.rs @@ -55,13 +55,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let goals_certainty = self.try_evaluate_added_goals()?; let certainty = certainty.unify_and(goals_certainty); - if let Certainty::Yes = certainty { - assert!( - self.nested_goals.is_empty(), - "Cannot be certain of query response if unevaluated goals exist" - ); - } - let external_constraints = self.compute_external_query_constraints()?; let response = Response { var_values: self.var_values, external_constraints, certainty }; diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 13d6602b7e12..5986b40d9a98 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -88,12 +88,10 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { }; let result = ecx.evaluate_goal(IsNormalizesToHack::No, goal); - if let Ok((_, Certainty::Yes)) = result { - assert!( - ecx.nested_goals.is_empty(), - "Cannot be certain of query response if unevaluated goals exist" - ); - } + assert!( + ecx.nested_goals.is_empty(), + "root `EvalCtxt` should not have any goals added to it" + ); assert!(search_graph.is_empty()); result From b85bc19705c68372c1554b13ec4bf5dd5797753f Mon Sep 17 00:00:00 2001 From: Boxy Date: Fri, 17 Mar 2023 15:02:24 +0000 Subject: [PATCH 33/70] move `compute_goal` and `evaluate_x` methods to inner module --- .../src/solve/eval_ctxt.rs | 270 ++++++++++++++++- .../rustc_trait_selection/src/solve/mod.rs | 274 +----------------- 2 files changed, 272 insertions(+), 272 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index 80828d5c1d5a..954129223579 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -2,8 +2,11 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::canonical::CanonicalVarValues; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk, LateBoundRegionConversionTime}; +use rustc_infer::infer::{ + DefineOpaqueTypes, InferCtxt, InferOk, LateBoundRegionConversionTime, TyCtxtInferExt, +}; use rustc_infer::traits::query::NoSolution; +use rustc_infer::traits::solve::{CanonicalGoal, Certainty, MaybeCause, QueryResult}; use rustc_infer::traits::ObligationCause; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::ty::{ @@ -13,6 +16,7 @@ use rustc_middle::ty::{ use rustc_span::DUMMY_SP; use std::ops::ControlFlow; +use super::search_graph::{self, OverflowHandler}; use super::{search_graph::SearchGraph, Goal}; pub struct EvalCtxt<'a, 'tcx> { @@ -57,6 +61,270 @@ impl NestedGoals<'_> { } } +pub trait InferCtxtEvalExt<'tcx> { + /// Evaluates a goal from **outside** of the trait solver. + /// + /// Using this while inside of the solver is wrong as it uses a new + /// search graph which would break cycle detection. + fn evaluate_root_goal( + &self, + goal: Goal<'tcx, ty::Predicate<'tcx>>, + ) -> Result<(bool, Certainty), NoSolution>; +} + +impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { + #[instrument(level = "debug", skip(self))] + fn evaluate_root_goal( + &self, + goal: Goal<'tcx, ty::Predicate<'tcx>>, + ) -> Result<(bool, Certainty), NoSolution> { + let mut search_graph = search_graph::SearchGraph::new(self.tcx); + + let mut ecx = EvalCtxt { + search_graph: &mut search_graph, + infcx: self, + // Only relevant when canonicalizing the response. + max_input_universe: ty::UniverseIndex::ROOT, + var_values: CanonicalVarValues::dummy(), + nested_goals: NestedGoals::new(), + }; + let result = ecx.evaluate_goal(IsNormalizesToHack::No, goal); + + assert!( + ecx.nested_goals.is_empty(), + "root `EvalCtxt` should not have any goals added to it" + ); + + assert!(search_graph.is_empty()); + result + } +} + +impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { + /// The entry point of the solver. + /// + /// This function deals with (coinductive) cycles, overflow, and caching + /// and then calls [`EvalCtxt::compute_goal`] which contains the actual + /// logic of the solver. + /// + /// Instead of calling this function directly, use either [EvalCtxt::evaluate_goal] + /// if you're inside of the solver or [InferCtxtEvalExt::evaluate_root_goal] if you're + /// outside of it. + #[instrument(level = "debug", skip(tcx, search_graph), ret)] + fn evaluate_canonical_goal( + tcx: TyCtxt<'tcx>, + search_graph: &'a mut search_graph::SearchGraph<'tcx>, + canonical_goal: CanonicalGoal<'tcx>, + ) -> QueryResult<'tcx> { + // Deal with overflow, caching, and coinduction. + // + // The actual solver logic happens in `ecx.compute_goal`. + search_graph.with_new_goal(tcx, canonical_goal, |search_graph| { + let (ref infcx, goal, var_values) = + tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal); + let mut ecx = EvalCtxt { + infcx, + var_values, + max_input_universe: canonical_goal.max_universe, + search_graph, + nested_goals: NestedGoals::new(), + }; + ecx.compute_goal(goal) + }) + } + + /// Recursively evaluates `goal`, returning whether any inference vars have + /// been constrained and the certainty of the result. + fn evaluate_goal( + &mut self, + is_normalizes_to_hack: IsNormalizesToHack, + goal: Goal<'tcx, ty::Predicate<'tcx>>, + ) -> Result<(bool, Certainty), NoSolution> { + let (orig_values, canonical_goal) = self.canonicalize_goal(goal); + let canonical_response = + EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?; + + let has_changed = !canonical_response.value.var_values.is_identity(); + let certainty = self.instantiate_and_apply_query_response( + goal.param_env, + orig_values, + canonical_response, + )?; + + // Check that rerunning this query with its inference constraints applied + // doesn't result in new inference constraints and has the same result. + // + // If we have projection goals like `::Assoc == u32` we recursively + // call `exists ::Assoc == U` to enable better caching. This goal + // could constrain `U` to `u32` which would cause this check to result in a + // solver cycle. + if cfg!(debug_assertions) + && has_changed + && is_normalizes_to_hack == IsNormalizesToHack::No + && !self.search_graph.in_cycle() + { + debug!("rerunning goal to check result is stable"); + let (_orig_values, canonical_goal) = self.canonicalize_goal(goal); + let canonical_response = + EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?; + if !canonical_response.value.var_values.is_identity() { + bug!("unstable result: {goal:?} {canonical_goal:?} {canonical_response:?}"); + } + assert_eq!(certainty, canonical_response.value.certainty); + } + + Ok((has_changed, certainty)) + } + + fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult<'tcx> { + let Goal { param_env, predicate } = goal; + let kind = predicate.kind(); + if let Some(kind) = kind.no_bound_vars() { + match kind { + ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) => { + self.compute_trait_goal(Goal { param_env, predicate }) + } + ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) => { + self.compute_projection_goal(Goal { param_env, predicate }) + } + ty::PredicateKind::Clause(ty::Clause::TypeOutlives(predicate)) => { + self.compute_type_outlives_goal(Goal { param_env, predicate }) + } + ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => { + self.compute_region_outlives_goal(Goal { param_env, predicate }) + } + ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + self.compute_const_arg_has_type_goal(Goal { param_env, predicate: (ct, ty) }) + } + ty::PredicateKind::Subtype(predicate) => { + self.compute_subtype_goal(Goal { param_env, predicate }) + } + ty::PredicateKind::Coerce(predicate) => { + self.compute_coerce_goal(Goal { param_env, predicate }) + } + ty::PredicateKind::ClosureKind(def_id, substs, kind) => self + .compute_closure_kind_goal(Goal { + param_env, + predicate: (def_id, substs, kind), + }), + ty::PredicateKind::ObjectSafe(trait_def_id) => { + self.compute_object_safe_goal(trait_def_id) + } + ty::PredicateKind::WellFormed(arg) => { + self.compute_well_formed_goal(Goal { param_env, predicate: arg }) + } + ty::PredicateKind::Ambiguous => { + self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + } + // FIXME: implement these predicates :) + ty::PredicateKind::ConstEvaluatable(_) | ty::PredicateKind::ConstEquate(_, _) => { + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + ty::PredicateKind::TypeWellFormedFromEnv(..) => { + bug!("TypeWellFormedFromEnv is only used for Chalk") + } + ty::PredicateKind::AliasEq(lhs, rhs) => { + self.compute_alias_eq_goal(Goal { param_env, predicate: (lhs, rhs) }) + } + } + } else { + let kind = self.infcx.instantiate_binder_with_placeholders(kind); + let goal = goal.with(self.tcx(), ty::Binder::dummy(kind)); + self.add_goal(goal); + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + } + + // Recursively evaluates all the goals added to this `EvalCtxt` to completion, returning + // the certainty of all the goals. + #[instrument(level = "debug", skip(self))] + pub(super) fn try_evaluate_added_goals(&mut self) -> Result { + let mut goals = core::mem::replace(&mut self.nested_goals, NestedGoals::new()); + let mut new_goals = NestedGoals::new(); + + let response = self.repeat_while_none( + |_| Ok(Certainty::Maybe(MaybeCause::Overflow)), + |this| { + let mut has_changed = Err(Certainty::Yes); + + if let Some(goal) = goals.normalizes_to_hack_goal.take() { + let (_, certainty) = match this.evaluate_goal( + IsNormalizesToHack::Yes, + goal.with(this.tcx(), ty::Binder::dummy(goal.predicate)), + ) { + Ok(r) => r, + Err(NoSolution) => return Some(Err(NoSolution)), + }; + + if goal.predicate.projection_ty + != this.resolve_vars_if_possible(goal.predicate.projection_ty) + { + has_changed = Ok(()) + } + + match certainty { + Certainty::Yes => {} + Certainty::Maybe(_) => { + let goal = this.resolve_vars_if_possible(goal); + + // The rhs of this `normalizes-to` must always be an unconstrained infer var as it is + // the hack used by `normalizes-to` to ensure that every `normalizes-to` behaves the same + // regardless of the rhs. + // + // However it is important not to unconditionally replace the rhs with a new infer var + // as otherwise we may replace the original unconstrained infer var with a new infer var + // and never propagate any constraints on the new var back to the original var. + let term = this + .term_is_fully_unconstrained(goal) + .then_some(goal.predicate.term) + .unwrap_or_else(|| { + this.next_term_infer_of_kind(goal.predicate.term) + }); + let projection_pred = ty::ProjectionPredicate { + term, + projection_ty: goal.predicate.projection_ty, + }; + new_goals.normalizes_to_hack_goal = + Some(goal.with(this.tcx(), projection_pred)); + + has_changed = has_changed.map_err(|c| c.unify_and(certainty)); + } + } + } + + for nested_goal in goals.goals.drain(..) { + let (changed, certainty) = + match this.evaluate_goal(IsNormalizesToHack::No, nested_goal) { + Ok(result) => result, + Err(NoSolution) => return Some(Err(NoSolution)), + }; + + if changed { + has_changed = Ok(()); + } + + match certainty { + Certainty::Yes => {} + Certainty::Maybe(_) => { + new_goals.goals.push(nested_goal); + has_changed = has_changed.map_err(|c| c.unify_and(certainty)); + } + } + } + + core::mem::swap(&mut new_goals, &mut goals); + match has_changed { + Ok(()) => None, + Err(certainty) => Some(Ok(certainty)), + } + }, + ); + + self.nested_goals = goals; + response + } +} + impl<'tcx> EvalCtxt<'_, 'tcx> { pub(super) fn probe(&mut self, f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> T) -> T { let mut ecx = EvalCtxt { diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 5986b40d9a98..606c2eaa5105 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -15,23 +15,19 @@ // FIXME: uses of `infcx.at` need to enable deferred projection equality once that's implemented. -use std::mem; - use rustc_hir::def_id::DefId; use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues}; -use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk, TyCtxtInferExt}; +use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; use rustc_infer::traits::query::NoSolution; use rustc_middle::traits::solve::{ CanonicalGoal, CanonicalResponse, Certainty, ExternalConstraints, ExternalConstraintsData, - Goal, MaybeCause, QueryResult, Response, + Goal, QueryResult, Response, }; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{ CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate, }; -use rustc_span::DUMMY_SP; -use crate::solve::search_graph::OverflowHandler; use crate::traits::ObligationCause; mod assembly; @@ -42,11 +38,9 @@ mod project_goals; mod search_graph; mod trait_goals; -pub use eval_ctxt::EvalCtxt; +pub use eval_ctxt::{EvalCtxt, InferCtxtEvalExt}; pub use fulfill::FulfillmentCtxt; -use self::eval_ctxt::{IsNormalizesToHack, NestedGoals}; - trait CanonicalResponseExt { fn has_no_inference_or_external_constraints(&self) -> bool; } @@ -59,180 +53,7 @@ impl<'tcx> CanonicalResponseExt for Canonical<'tcx, Response<'tcx>> { } } -pub trait InferCtxtEvalExt<'tcx> { - /// Evaluates a goal from **outside** of the trait solver. - /// - /// Using this while inside of the solver is wrong as it uses a new - /// search graph which would break cycle detection. - fn evaluate_root_goal( - &self, - goal: Goal<'tcx, ty::Predicate<'tcx>>, - ) -> Result<(bool, Certainty), NoSolution>; -} - -impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { - #[instrument(level = "debug", skip(self))] - fn evaluate_root_goal( - &self, - goal: Goal<'tcx, ty::Predicate<'tcx>>, - ) -> Result<(bool, Certainty), NoSolution> { - let mut search_graph = search_graph::SearchGraph::new(self.tcx); - - let mut ecx = EvalCtxt { - search_graph: &mut search_graph, - infcx: self, - // Only relevant when canonicalizing the response. - max_input_universe: ty::UniverseIndex::ROOT, - var_values: CanonicalVarValues::dummy(), - nested_goals: NestedGoals::new(), - }; - let result = ecx.evaluate_goal(IsNormalizesToHack::No, goal); - - assert!( - ecx.nested_goals.is_empty(), - "root `EvalCtxt` should not have any goals added to it" - ); - - assert!(search_graph.is_empty()); - result - } -} - impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { - /// The entry point of the solver. - /// - /// This function deals with (coinductive) cycles, overflow, and caching - /// and then calls [`EvalCtxt::compute_goal`] which contains the actual - /// logic of the solver. - /// - /// Instead of calling this function directly, use either [EvalCtxt::evaluate_goal] - /// if you're inside of the solver or [InferCtxtEvalExt::evaluate_root_goal] if you're - /// outside of it. - #[instrument(level = "debug", skip(tcx, search_graph), ret)] - fn evaluate_canonical_goal( - tcx: TyCtxt<'tcx>, - search_graph: &'a mut search_graph::SearchGraph<'tcx>, - canonical_goal: CanonicalGoal<'tcx>, - ) -> QueryResult<'tcx> { - // Deal with overflow, caching, and coinduction. - // - // The actual solver logic happens in `ecx.compute_goal`. - search_graph.with_new_goal(tcx, canonical_goal, |search_graph| { - let (ref infcx, goal, var_values) = - tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal); - let mut ecx = EvalCtxt { - infcx, - var_values, - max_input_universe: canonical_goal.max_universe, - search_graph, - nested_goals: NestedGoals::new(), - }; - ecx.compute_goal(goal) - }) - } - - /// Recursively evaluates `goal`, returning whether any inference vars have - /// been constrained and the certainty of the result. - fn evaluate_goal( - &mut self, - is_normalizes_to_hack: IsNormalizesToHack, - goal: Goal<'tcx, ty::Predicate<'tcx>>, - ) -> Result<(bool, Certainty), NoSolution> { - let (orig_values, canonical_goal) = self.canonicalize_goal(goal); - let canonical_response = - EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?; - - let has_changed = !canonical_response.value.var_values.is_identity(); - let certainty = self.instantiate_and_apply_query_response( - goal.param_env, - orig_values, - canonical_response, - )?; - - // Check that rerunning this query with its inference constraints applied - // doesn't result in new inference constraints and has the same result. - // - // If we have projection goals like `::Assoc == u32` we recursively - // call `exists ::Assoc == U` to enable better caching. This goal - // could constrain `U` to `u32` which would cause this check to result in a - // solver cycle. - if cfg!(debug_assertions) - && has_changed - && is_normalizes_to_hack == IsNormalizesToHack::No - && !self.search_graph.in_cycle() - { - debug!("rerunning goal to check result is stable"); - let (_orig_values, canonical_goal) = self.canonicalize_goal(goal); - let canonical_response = - EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?; - if !canonical_response.value.var_values.is_identity() { - bug!("unstable result: {goal:?} {canonical_goal:?} {canonical_response:?}"); - } - assert_eq!(certainty, canonical_response.value.certainty); - } - - Ok((has_changed, certainty)) - } - - fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult<'tcx> { - let Goal { param_env, predicate } = goal; - let kind = predicate.kind(); - if let Some(kind) = kind.no_bound_vars() { - match kind { - ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) => { - self.compute_trait_goal(Goal { param_env, predicate }) - } - ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) => { - self.compute_projection_goal(Goal { param_env, predicate }) - } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(predicate)) => { - self.compute_type_outlives_goal(Goal { param_env, predicate }) - } - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => { - self.compute_region_outlives_goal(Goal { param_env, predicate }) - } - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { - self.compute_const_arg_has_type_goal(Goal { param_env, predicate: (ct, ty) }) - } - ty::PredicateKind::Subtype(predicate) => { - self.compute_subtype_goal(Goal { param_env, predicate }) - } - ty::PredicateKind::Coerce(predicate) => { - self.compute_coerce_goal(Goal { param_env, predicate }) - } - ty::PredicateKind::ClosureKind(def_id, substs, kind) => self - .compute_closure_kind_goal(Goal { - param_env, - predicate: (def_id, substs, kind), - }), - ty::PredicateKind::ObjectSafe(trait_def_id) => { - self.compute_object_safe_goal(trait_def_id) - } - ty::PredicateKind::WellFormed(arg) => { - self.compute_well_formed_goal(Goal { param_env, predicate: arg }) - } - ty::PredicateKind::Ambiguous => { - self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) - } - // FIXME: implement these predicates :) - ty::PredicateKind::ConstEvaluatable(_) | ty::PredicateKind::ConstEquate(_, _) => { - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - } - ty::PredicateKind::TypeWellFormedFromEnv(..) => { - bug!("TypeWellFormedFromEnv is only used for Chalk") - } - ty::PredicateKind::AliasEq(lhs, rhs) => { - self.compute_alias_eq_goal(Goal { param_env, predicate: (lhs, rhs) }) - } - } - } else { - let kind = self.infcx.instantiate_binder_with_placeholders(kind); - let goal = goal.with(self.tcx(), ty::Binder::dummy(kind)); - self.add_goal(goal); - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - } - } - #[instrument(level = "debug", skip(self))] fn compute_type_outlives_goal( &mut self, @@ -424,95 +245,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { debug!("added_goals={:?}", &self.nested_goals.goals[current_len..]); } - // Recursively evaluates all the goals added to this `EvalCtxt` to completion, returning - // the certainty of all the goals. - #[instrument(level = "debug", skip(self))] - fn try_evaluate_added_goals(&mut self) -> Result { - let mut goals = core::mem::replace(&mut self.nested_goals, NestedGoals::new()); - let mut new_goals = NestedGoals::new(); - - let response = self.repeat_while_none( - |_| Ok(Certainty::Maybe(MaybeCause::Overflow)), - |this| { - let mut has_changed = Err(Certainty::Yes); - - if let Some(goal) = goals.normalizes_to_hack_goal.take() { - let (_, certainty) = match this.evaluate_goal( - IsNormalizesToHack::Yes, - goal.with(this.tcx(), ty::Binder::dummy(goal.predicate)), - ) { - Ok(r) => r, - Err(NoSolution) => return Some(Err(NoSolution)), - }; - - if goal.predicate.projection_ty - != this.resolve_vars_if_possible(goal.predicate.projection_ty) - { - has_changed = Ok(()) - } - - match certainty { - Certainty::Yes => {} - Certainty::Maybe(_) => { - let goal = this.resolve_vars_if_possible(goal); - - // The rhs of this `normalizes-to` must always be an unconstrained infer var as it is - // the hack used by `normalizes-to` to ensure that every `normalizes-to` behaves the same - // regardless of the rhs. - // - // However it is important not to unconditionally replace the rhs with a new infer var - // as otherwise we may replace the original unconstrained infer var with a new infer var - // and never propagate any constraints on the new var back to the original var. - let term = this - .term_is_fully_unconstrained(goal) - .then_some(goal.predicate.term) - .unwrap_or_else(|| { - this.next_term_infer_of_kind(goal.predicate.term) - }); - let projection_pred = ty::ProjectionPredicate { - term, - projection_ty: goal.predicate.projection_ty, - }; - new_goals.normalizes_to_hack_goal = - Some(goal.with(this.tcx(), projection_pred)); - - has_changed = has_changed.map_err(|c| c.unify_and(certainty)); - } - } - } - - for nested_goal in goals.goals.drain(..) { - let (changed, certainty) = - match this.evaluate_goal(IsNormalizesToHack::No, nested_goal) { - Ok(result) => result, - Err(NoSolution) => return Some(Err(NoSolution)), - }; - - if changed { - has_changed = Ok(()); - } - - match certainty { - Certainty::Yes => {} - Certainty::Maybe(_) => { - new_goals.goals.push(nested_goal); - has_changed = has_changed.map_err(|c| c.unify_and(certainty)); - } - } - } - - mem::swap(&mut new_goals, &mut goals); - match has_changed { - Ok(()) => None, - Err(certainty) => Some(Ok(certainty)), - } - }, - ); - - self.nested_goals = goals; - response - } - fn try_merge_responses( &mut self, responses: impl Iterator>, From 322c7b6269f0a2147b85f4cc38006afca22a0d31 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 19 Mar 2023 02:17:44 +0000 Subject: [PATCH 34/70] Constrain const vars to error if const types are mismatched --- compiler/rustc_infer/src/infer/combine.rs | 17 +++++++++++++---- tests/ui/const-generics/bad-subst-const-kind.rs | 13 +++++++++++++ .../const-generics/bad-subst-const-kind.stderr | 9 +++++++++ .../bad-const-wf-doesnt-specialize.rs | 4 ++-- .../bad-const-wf-doesnt-specialize.stderr | 4 ++-- 5 files changed, 39 insertions(+), 8 deletions(-) create mode 100644 tests/ui/const-generics/bad-subst-const-kind.rs create mode 100644 tests/ui/const-generics/bad-subst-const-kind.stderr diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index bb6fdd2ffc2c..4503af03ca34 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -189,10 +189,19 @@ impl<'tcx> InferCtxt<'tcx> { // the expected const's type. Specifically, we don't want const infer vars // to do any type shapeshifting before and after resolution. if let Err(guar) = compatible_types { - return Ok(self.tcx.const_error_with_guaranteed( - if relation.a_is_expected() { a.ty() } else { b.ty() }, - guar, - )); + // HACK: equating both sides with `[const error]` eagerly prevents us + // from leaving unconstrained inference vars during things like impl + // matching in the solver. + let a_error = self.tcx.const_error_with_guaranteed(a.ty(), guar); + if let ty::ConstKind::Infer(InferConst::Var(vid)) = a.kind() { + return self.unify_const_variable(vid, a_error); + } + let b_error = self.tcx.const_error_with_guaranteed(b.ty(), guar); + if let ty::ConstKind::Infer(InferConst::Var(vid)) = b.kind() { + return self.unify_const_variable(vid, b_error); + } + + return Ok(if relation.a_is_expected() { a_error } else { b_error }); } match (a.kind(), b.kind()) { diff --git a/tests/ui/const-generics/bad-subst-const-kind.rs b/tests/ui/const-generics/bad-subst-const-kind.rs new file mode 100644 index 000000000000..e13dfbacd242 --- /dev/null +++ b/tests/ui/const-generics/bad-subst-const-kind.rs @@ -0,0 +1,13 @@ +// incremental +#![crate_type = "lib"] + +trait Q { + const ASSOC: usize; +} + +impl Q for [u8; N] { + //~^ ERROR mismatched types + const ASSOC: usize = 1; +} + +pub fn test() -> [u8; <[u8; 13] as Q>::ASSOC] { todo!() } diff --git a/tests/ui/const-generics/bad-subst-const-kind.stderr b/tests/ui/const-generics/bad-subst-const-kind.stderr new file mode 100644 index 000000000000..bd24f9140e4e --- /dev/null +++ b/tests/ui/const-generics/bad-subst-const-kind.stderr @@ -0,0 +1,9 @@ +error[E0308]: mismatched types + --> $DIR/bad-subst-const-kind.rs:8:31 + | +LL | impl Q for [u8; N] { + | ^ expected `usize`, found `u64` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs index 582b480aa25b..6bad87d3d374 100644 --- a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs +++ b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs @@ -2,11 +2,11 @@ // An impl that has an erroneous const substitution should not specialize one // that is well-formed. - +#[derive(Clone)] struct S; impl Copy for S {} impl Copy for S {} -//~^ ERROR conflicting implementations of trait `Copy` for type `S<_>` +//~^ ERROR conflicting implementations of trait `Copy` for type `S<[const error]>` fn main() {} diff --git a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr index a3906a9a22fe..35848db9b56b 100644 --- a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr +++ b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr @@ -1,10 +1,10 @@ -error[E0119]: conflicting implementations of trait `Copy` for type `S<_>` +error[E0119]: conflicting implementations of trait `Copy` for type `S<[const error]>` --> $DIR/bad-const-wf-doesnt-specialize.rs:9:1 | LL | impl Copy for S {} | -------------------------------- first implementation here LL | impl Copy for S {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `S<_>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `S<[const error]>` error: aborting due to previous error From 9174edbae9d3f95b9e1d89ebf4921b761e333204 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 19 Mar 2023 02:20:15 +0000 Subject: [PATCH 35/70] Delay overlap errors if errors are involved --- .../src/traits/specialize/mod.rs | 6 +++++- .../bad-const-wf-doesnt-specialize.rs | 2 +- .../bad-const-wf-doesnt-specialize.stderr | 15 +++++++++------ 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 8e229dd8d6b9..8546bbe52dcc 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -22,7 +22,7 @@ use crate::traits::{ use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{error_code, DelayDm, Diagnostic}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt}; +use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{InternalSubsts, SubstsRef}; use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK; use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS; @@ -350,6 +350,10 @@ fn report_conflicting_impls<'tcx>( impl_span: Span, err: &mut Diagnostic, ) { + if (overlap.trait_ref, overlap.self_ty).references_error() { + err.downgrade_to_delayed_bug(); + } + match tcx.span_of_impl(overlap.with_impl) { Ok(span) => { err.span_label(span, "first implementation here"); diff --git a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs index 6bad87d3d374..5fd7c647c253 100644 --- a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs +++ b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs @@ -6,7 +6,7 @@ struct S; impl Copy for S {} +//~^ ERROR the constant `N` is not of type `usize` impl Copy for S {} -//~^ ERROR conflicting implementations of trait `Copy` for type `S<[const error]>` fn main() {} diff --git a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr index 35848db9b56b..6d7028c5e708 100644 --- a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr +++ b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr @@ -1,11 +1,14 @@ -error[E0119]: conflicting implementations of trait `Copy` for type `S<[const error]>` - --> $DIR/bad-const-wf-doesnt-specialize.rs:9:1 +error: the constant `N` is not of type `usize` + --> $DIR/bad-const-wf-doesnt-specialize.rs:8:29 | LL | impl Copy for S {} - | -------------------------------- first implementation here -LL | impl Copy for S {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `S<[const error]>` + | ^^^^ + | +note: required by a bound in `S` + --> $DIR/bad-const-wf-doesnt-specialize.rs:6:10 + | +LL | struct S; + | ^^^^^^^^^^^^^^ required by this bound in `S` error: aborting due to previous error -For more information about this error, try `rustc --explain E0119`. From 0e866af1f720ed487fb08bd40b69d7a4e168519c Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 13 Mar 2023 17:43:14 +0000 Subject: [PATCH 36/70] Only clear locals that are known to be written to. --- .../rustc_mir_transform/src/const_prop.rs | 41 +++++++++++++++---- .../src/const_prop_lint.rs | 28 +++++++++---- 2 files changed, 53 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index de7b8c63fc87..b73ba198afe7 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -4,6 +4,7 @@ use either::Right; use rustc_const_eval::const_eval::CheckAlignment; +use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::DefKind; use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; @@ -151,12 +152,17 @@ impl<'tcx> MirPass<'tcx> for ConstProp { pub struct ConstPropMachine<'mir, 'tcx> { /// The virtual call stack. stack: Vec>, + pub written_only_inside_own_block_locals: FxHashSet, pub can_const_prop: IndexVec, } impl ConstPropMachine<'_, '_> { pub fn new(can_const_prop: IndexVec) -> Self { - Self { stack: Vec::new(), can_const_prop } + Self { + stack: Vec::new(), + written_only_inside_own_block_locals: Default::default(), + can_const_prop, + } } } @@ -249,7 +255,10 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> "tried to write to a local that is marked as not propagatable" ) } - ConstPropMode::OnlyInsideOwnBlock | ConstPropMode::FullConstProp => {} + ConstPropMode::OnlyInsideOwnBlock => { + ecx.machine.written_only_inside_own_block_locals.insert(local); + } + ConstPropMode::FullConstProp => {} } ecx.machine.stack[frame].locals[local].access_mut() } @@ -416,6 +425,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { fn remove_const(ecx: &mut InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, local: Local) { ecx.frame_mut().locals[local].value = LocalValue::Live(interpret::Operand::Immediate(interpret::Immediate::Uninit)); + ecx.machine.written_only_inside_own_block_locals.remove(&local); } /// Returns the value, if any, of evaluating `c`. @@ -693,7 +703,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } } - fn ensure_not_propagated(&mut self, local: Local) { + fn ensure_not_propagated(&self, local: Local) { if cfg!(debug_assertions) { assert!( self.get_const(local.into()).is_none() @@ -963,17 +973,30 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> { // We remove all Locals which are restricted in propagation to their containing blocks and // which were modified in the current block. // Take it out of the ecx so we can get a mutable reference to the ecx for `remove_const`. - let can_const_prop = std::mem::take(&mut self.ecx.machine.can_const_prop); - for (local, &mode) in can_const_prop.iter_enumerated() { + let mut written_only_inside_own_block_locals = + std::mem::take(&mut self.ecx.machine.written_only_inside_own_block_locals); + + // This loop can get very hot for some bodies: it check each local in each bb. + // To avoid this quadratic behaviour, we only clear the locals that were modified inside + // the current block. + for local in written_only_inside_own_block_locals.drain() { + debug_assert_eq!( + self.ecx.machine.can_const_prop[local], + ConstPropMode::OnlyInsideOwnBlock + ); + Self::remove_const(&mut self.ecx, local); + } + self.ecx.machine.written_only_inside_own_block_locals = + written_only_inside_own_block_locals; + + #[cfg(debug_assertions)] + for (local, &mode) in self.ecx.machine.can_const_prop.iter_enumerated() { match mode { ConstPropMode::FullConstProp => {} - ConstPropMode::NoPropagation => self.ensure_not_propagated(local), - ConstPropMode::OnlyInsideOwnBlock => { - Self::remove_const(&mut self.ecx, local); + ConstPropMode::NoPropagation | ConstPropMode::OnlyInsideOwnBlock => { self.ensure_not_propagated(local); } } } - self.ecx.machine.can_const_prop = can_const_prop; } } diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index 68e50070e56e..aeefadf94085 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -247,6 +247,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { fn remove_const(ecx: &mut InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, local: Local) { ecx.frame_mut().locals[local].value = LocalValue::Live(interpret::Operand::Immediate(interpret::Immediate::Uninit)); + ecx.machine.written_only_inside_own_block_locals.remove(&local); } fn lint_root(&self, source_info: SourceInfo) -> Option { @@ -484,7 +485,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { Some(()) } - fn ensure_not_propagated(&mut self, local: Local) { + fn ensure_not_propagated(&self, local: Local) { if cfg!(debug_assertions) { assert!( self.get_const(local.into()).is_none() @@ -691,17 +692,30 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { // We remove all Locals which are restricted in propagation to their containing blocks and // which were modified in the current block. // Take it out of the ecx so we can get a mutable reference to the ecx for `remove_const`. - let can_const_prop = std::mem::take(&mut self.ecx.machine.can_const_prop); - for (local, &mode) in can_const_prop.iter_enumerated() { + let mut written_only_inside_own_block_locals = + std::mem::take(&mut self.ecx.machine.written_only_inside_own_block_locals); + + // This loop can get very hot for some bodies: it check each local in each bb. + // To avoid this quadratic behaviour, we only clear the locals that were modified inside + // the current block. + for local in written_only_inside_own_block_locals.drain() { + debug_assert_eq!( + self.ecx.machine.can_const_prop[local], + ConstPropMode::OnlyInsideOwnBlock + ); + Self::remove_const(&mut self.ecx, local); + } + self.ecx.machine.written_only_inside_own_block_locals = + written_only_inside_own_block_locals; + + #[cfg(debug_assertions)] + for (local, &mode) in self.ecx.machine.can_const_prop.iter_enumerated() { match mode { ConstPropMode::FullConstProp => {} - ConstPropMode::NoPropagation => self.ensure_not_propagated(local), - ConstPropMode::OnlyInsideOwnBlock => { - Self::remove_const(&mut self.ecx, local); + ConstPropMode::NoPropagation | ConstPropMode::OnlyInsideOwnBlock => { self.ensure_not_propagated(local); } } } - self.ecx.machine.can_const_prop = can_const_prop; } } From e5a55dc2c545643e6a7bee2eb34535544228c699 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 19 Mar 2023 08:59:11 +0000 Subject: [PATCH 37/70] Prefer if cfg!. --- compiler/rustc_mir_transform/src/const_prop.rs | 13 +++++++------ compiler/rustc_mir_transform/src/const_prop_lint.rs | 13 +++++++------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index b73ba198afe7..bebd9723740f 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -989,12 +989,13 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> { self.ecx.machine.written_only_inside_own_block_locals = written_only_inside_own_block_locals; - #[cfg(debug_assertions)] - for (local, &mode) in self.ecx.machine.can_const_prop.iter_enumerated() { - match mode { - ConstPropMode::FullConstProp => {} - ConstPropMode::NoPropagation | ConstPropMode::OnlyInsideOwnBlock => { - self.ensure_not_propagated(local); + if cfg!(debug_assertions) { + for (local, &mode) in self.ecx.machine.can_const_prop.iter_enumerated() { + match mode { + ConstPropMode::FullConstProp => {} + ConstPropMode::NoPropagation | ConstPropMode::OnlyInsideOwnBlock => { + self.ensure_not_propagated(local); + } } } } diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index aeefadf94085..45bd98f39d2b 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -708,12 +708,13 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { self.ecx.machine.written_only_inside_own_block_locals = written_only_inside_own_block_locals; - #[cfg(debug_assertions)] - for (local, &mode) in self.ecx.machine.can_const_prop.iter_enumerated() { - match mode { - ConstPropMode::FullConstProp => {} - ConstPropMode::NoPropagation | ConstPropMode::OnlyInsideOwnBlock => { - self.ensure_not_propagated(local); + if cfg!(debug_assertions) { + for (local, &mode) in self.ecx.machine.can_const_prop.iter_enumerated() { + match mode { + ConstPropMode::FullConstProp => {} + ConstPropMode::NoPropagation | ConstPropMode::OnlyInsideOwnBlock => { + self.ensure_not_propagated(local); + } } } } From 177572241076e4885c5c12e407d3ea10d3b2363f Mon Sep 17 00:00:00 2001 From: bohan Date: Sun, 19 Mar 2023 20:12:57 +0800 Subject: [PATCH 38/70] fix: modify the condition that `resolve_imports` stops --- compiler/rustc_resolve/src/imports.rs | 38 +++++++----- tests/ui/macros/nested-use-as.rs | 83 +++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 15 deletions(-) create mode 100644 tests/ui/macros/nested-use-as.rs diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 6e27bcc5bf3d..4d4bc1be3497 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -423,13 +423,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// Resolves all imports for the crate. This method performs the fixed- /// point iteration. pub(crate) fn resolve_imports(&mut self) { - let mut prev_num_indeterminates = self.indeterminate_imports.len() + 1; - while self.indeterminate_imports.len() < prev_num_indeterminates { - prev_num_indeterminates = self.indeterminate_imports.len(); + let mut prev_indeterminate_count = usize::MAX; + let mut indeterminate_count = self.indeterminate_imports.len() * 3; + while indeterminate_count < prev_indeterminate_count { + prev_indeterminate_count = indeterminate_count; + indeterminate_count = 0; for import in mem::take(&mut self.indeterminate_imports) { - match self.resolve_import(&import) { - true => self.determined_imports.push(import), - false => self.indeterminate_imports.push(import), + let import_indeterminate_count = self.resolve_import(&import); + indeterminate_count += import_indeterminate_count; + match import_indeterminate_count { + 0 => self.determined_imports.push(import), + _ => self.indeterminate_imports.push(import), } } } @@ -581,9 +585,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { diag.emit(); } - /// Attempts to resolve the given import, returning true if its resolution is determined. - /// If successful, the resolved bindings are written into the module. - fn resolve_import(&mut self, import: &'a Import<'a>) -> bool { + /// Attempts to resolve the given import, returning: + /// - `0` means its resolution is determined. + /// - Other values mean that indeterminate exists under certain namespaces. + /// + /// Meanwhile, if resolve successful, the resolved bindings are written + /// into the module. + fn resolve_import(&mut self, import: &'a Import<'a>) -> usize { debug!( "(resolving import for module) resolving import `{}::...` in `{}`", Segment::names_to_string(&import.module_path), @@ -601,8 +609,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { match path_res { PathResult::Module(module) => module, - PathResult::Indeterminate => return false, - PathResult::NonModule(..) | PathResult::Failed { .. } => return true, + PathResult::Indeterminate => return 3, + PathResult::NonModule(..) | PathResult::Failed { .. } => return 0, } }; @@ -618,12 +626,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } => (source, target, source_bindings, target_bindings, type_ns_only), ImportKind::Glob { .. } => { self.resolve_glob_import(import); - return true; + return 0; } _ => unreachable!(), }; - let mut indeterminate = false; + let mut indeterminate_count = 0; self.per_ns(|this, ns| { if !type_ns_only || ns == TypeNS { if let Err(Undetermined) = source_bindings[ns].get() { @@ -646,7 +654,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let parent = import.parent_scope.module; match source_bindings[ns].get() { - Err(Undetermined) => indeterminate = true, + Err(Undetermined) => indeterminate_count += 1, // Don't update the resolution, because it was never added. Err(Determined) if target.name == kw::Underscore => {} Ok(binding) if binding.is_importable() => { @@ -670,7 +678,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } }); - !indeterminate + indeterminate_count } /// Performs final import resolution, consistency checks and error reporting. diff --git a/tests/ui/macros/nested-use-as.rs b/tests/ui/macros/nested-use-as.rs new file mode 100644 index 000000000000..21aa81e80926 --- /dev/null +++ b/tests/ui/macros/nested-use-as.rs @@ -0,0 +1,83 @@ +// check-pass +// edition:2018 +// issue: https://github.com/rust-lang/rust/issues/97534 + +macro_rules! m { + () => { + macro_rules! foo { + () => {} + } + use foo as bar; + } +} + +m!{} + +use bar as baz; + +baz!{} + +macro_rules! foo2 { + () => {}; +} + +macro_rules! m2 { + () => { + use foo2 as bar2; + }; +} + +m2! {} + +use bar2 as baz2; + +baz2! {} + +macro_rules! n1 { + () => { + macro_rules! n2 { + () => { + macro_rules! n3 { + () => { + macro_rules! n4 { + () => {} + } + use n4 as c4; + } + } + use n3 as c3; + } + } + use n2 as c2; + } +} + +use n1 as c1; +c1!{} +use c2 as a2; +a2!{} +use c3 as a3; +a3!{} +use c4 as a4; +a4!{} + +// https://github.com/rust-lang/rust/pull/108729#issuecomment-1474750675 +// reversed +use d5 as d6; +use d4 as d5; +use d3 as d4; +use d2 as d3; +use d1 as d2; +use foo2 as d1; +d6! {} + +// mess +use f3 as f4; +f5! {} +use f1 as f2; +use f4 as f5; +use f2 as f3; +use foo2 as f1; + +fn main() { +} From 69a82f7f343f6fec675c1ed818103d10dd0ff1fc Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Sun, 19 Mar 2023 23:11:08 +0000 Subject: [PATCH 39/70] add myself to mailmap --- .mailmap | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.mailmap b/.mailmap index 715bc4d30855..9148b79e9801 100644 --- a/.mailmap +++ b/.mailmap @@ -29,6 +29,8 @@ Alexander Ronald Altman Alexandre Martin Alexis Beingessner Alfie John Alfie John +Alona Enraght-Moony +Alona Enraght-Moony Amos Onn Ana-Maria Mihalache Anatoly Ikorsky @@ -415,7 +417,6 @@ Nicolas Abram Nicole Mazzuca Nif Ward Nika Layzell -Nixon Enraght-Moony NODA Kai oliver <16816606+o752d@users.noreply.github.com> Oliver Middleton From 9f80c75703a7497241d9d1d072969f44f136597c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 16 Mar 2023 23:27:09 +0000 Subject: [PATCH 40/70] Walk un-shifted nested `impl Trait` in trait when setting up default trait method assumptions --- compiler/rustc_ty_utils/src/ty.rs | 42 ++++++++++++------- .../default-method-binder-shifting.rs | 6 +++ 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 9fed1e57c921..f53952d25fad 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -7,7 +7,10 @@ use rustc_middle::ty::{ TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, }; use rustc_session::config::TraitSolver; -use rustc_span::def_id::{DefId, CRATE_DEF_ID}; +use rustc_span::{ + def_id::{DefId, CRATE_DEF_ID}, + DUMMY_SP, +}; use rustc_trait_selection::traits; fn sized_constraint_for_ty<'tcx>( @@ -275,16 +278,22 @@ impl<'tcx> TypeVisitor> for ImplTraitInTraitFinder<'_, 'tcx> { } fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow { - if let ty::Alias(ty::Projection, alias_ty) = *ty.kind() - && self.tcx.is_impl_trait_in_trait(alias_ty.def_id) - && self.tcx.impl_trait_in_trait_parent_fn(alias_ty.def_id) == self.fn_def_id - && self.seen.insert(alias_ty.def_id) + if let ty::Alias(ty::Projection, unshifted_alias_ty) = *ty.kind() + && self.tcx.is_impl_trait_in_trait(unshifted_alias_ty.def_id) + && self.tcx.impl_trait_in_trait_parent_fn(unshifted_alias_ty.def_id) == self.fn_def_id + && self.seen.insert(unshifted_alias_ty.def_id) { // We have entered some binders as we've walked into the // bounds of the RPITIT. Shift these binders back out when // constructing the top-level projection predicate. - let alias_ty = self.tcx.fold_regions(alias_ty, |re, _| { + let shifted_alias_ty = self.tcx.fold_regions(unshifted_alias_ty, |re, depth| { if let ty::ReLateBound(index, bv) = re.kind() { + if depth != ty::INNERMOST { + return self.tcx.mk_re_error_with_message( + DUMMY_SP, + "we shouldn't walk non-predicate binders with `impl Trait`...", + ); + } self.tcx.mk_re_late_bound(index.shifted_out_to_binder(self.depth), bv) } else { re @@ -295,26 +304,27 @@ impl<'tcx> TypeVisitor> for ImplTraitInTraitFinder<'_, 'tcx> { // the `type_of` of the trait's associated item. If we're using the old lowering // strategy, then just reinterpret the associated type like an opaque :^) let default_ty = if self.tcx.lower_impl_trait_in_trait_to_assoc_ty() { - self - .tcx - .type_of(alias_ty.def_id) - .subst(self.tcx, alias_ty.substs) + self.tcx.type_of(shifted_alias_ty.def_id).subst(self.tcx, shifted_alias_ty.substs) } else { - self.tcx.mk_alias(ty::Opaque, alias_ty) + self.tcx.mk_alias(ty::Opaque, shifted_alias_ty) }; self.predicates.push( ty::Binder::bind_with_vars( - ty::ProjectionPredicate { - projection_ty: alias_ty, - term: default_ty.into(), - }, + ty::ProjectionPredicate { projection_ty: shifted_alias_ty, term: default_ty.into() }, self.bound_vars, ) .to_predicate(self.tcx), ); - for bound in self.tcx.item_bounds(alias_ty.def_id).subst_iter(self.tcx, alias_ty.substs) + // We walk the *un-shifted* alias ty, because we're tracking the de bruijn + // binder depth, and if we were to walk `shifted_alias_ty` instead, we'd + // have to reset `self.depth` back to `ty::INNERMOST` or something. It's + // easier to just do this. + for bound in self + .tcx + .item_bounds(unshifted_alias_ty.def_id) + .subst_iter(self.tcx, unshifted_alias_ty.substs) { bound.visit_with(self); } diff --git a/tests/ui/impl-trait/in-trait/default-method-binder-shifting.rs b/tests/ui/impl-trait/in-trait/default-method-binder-shifting.rs index 75b0ec939847..de82544f2933 100644 --- a/tests/ui/impl-trait/in-trait/default-method-binder-shifting.rs +++ b/tests/ui/impl-trait/in-trait/default-method-binder-shifting.rs @@ -13,4 +13,10 @@ trait Trait { fn method(&self) -> impl Trait; } +trait Trait2 { + type Type; + + fn method(&self) -> impl Trait2 + '_>; +} + fn main() {} From 239ec6cb11bf66d47fbc409ed8fca58370feb517 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 17 Mar 2023 00:50:47 +0000 Subject: [PATCH 41/70] drive-by: Fix a comment in TyCtxt::fold_regions and remove an unused method --- compiler/rustc_middle/src/ty/fold.rs | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index d66f436f947a..6205e2bf24dd 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -51,9 +51,7 @@ where // Region folder impl<'tcx> TyCtxt<'tcx> { - /// Folds the escaping and free regions in `value` using `f`, and - /// sets `skipped_regions` to true if any late-bound region was found - /// and skipped. + /// Folds the escaping and free regions in `value` using `f`. pub fn fold_regions( self, value: T, @@ -64,17 +62,6 @@ impl<'tcx> TyCtxt<'tcx> { { value.fold_with(&mut RegionFolder::new(self, &mut f)) } - - pub fn super_fold_regions( - self, - value: T, - mut f: impl FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>, - ) -> T - where - T: TypeSuperFoldable>, - { - value.super_fold_with(&mut RegionFolder::new(self, &mut f)) - } } /// Folds over the substructure of a type, visiting its component From 5b4fa5bf989e4d630512998789f4bb79f1d9f134 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 20 Mar 2023 10:46:43 +0100 Subject: [PATCH 42/70] fix typo --- compiler/rustc_hir_analysis/src/collect/type_of.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index fe44fabf57df..b5e8de3c9a7d 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -593,7 +593,7 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T found: Option>, /// In the presence of dead code, typeck may figure out a hidden type - /// while borrowck will now. We collect these cases here and check at + /// while borrowck will not. We collect these cases here and check at /// the end that we actually found a type that matches (modulo regions). typeck_types: Vec>, } From 40fc42371f04316e882cdfe8bf39b9dd194343ac Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 14 Mar 2023 11:19:20 +0100 Subject: [PATCH 43/70] Limited the number of parallel link jobs during LLVM build for mingw. This is an attempt to fix the spurious build error tracked by https://github.com/rust-lang/rust/issues/108227. --- src/ci/run.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/ci/run.sh b/src/ci/run.sh index 93dccb54c4e3..f5df5f7f6ecc 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -59,6 +59,14 @@ RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-locked-deps" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-cargo-native-static" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.codegen-units-std=1" +# When building for mingw, limit the number of parallel linker jobs during +# the LLVM build, as not to run out of memory. +# This is an attempt to fix the spurious build error tracked by +# https://github.com/rust-lang/rust/issues/108227. +if isWindows && [[ ${CUSTOM_MINGW-0} -eq 1 ]]; then + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set llvm.link-jobs=4" +fi + # Only produce xz tarballs on CI. gz tarballs will be generated by the release # process by recompressing the existing xz ones. This decreases the storage # space required for CI artifacts. From 8e4e55e5246492e7add98ccf24f2f483163cdbf2 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Mon, 20 Mar 2023 12:32:38 +0100 Subject: [PATCH 44/70] Support aggregate expressions --- .../src/build/custom/parse/instruction.rs | 25 +++++++ .../aggregate_exprs.adt.built.after.mir | 16 +++++ .../aggregate_exprs.array.built.after.mir | 15 ++++ .../building/custom/aggregate_exprs.rs | 71 +++++++++++++++++++ .../aggregate_exprs.tuple.built.after.mir | 10 +++ 5 files changed, 137 insertions(+) create mode 100644 tests/mir-opt/building/custom/aggregate_exprs.adt.built.after.mir create mode 100644 tests/mir-opt/building/custom/aggregate_exprs.array.built.after.mir create mode 100644 tests/mir-opt/building/custom/aggregate_exprs.rs create mode 100644 tests/mir-opt/building/custom/aggregate_exprs.tuple.built.after.mir diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index 5e77f2dc1268..e60e1a4c8150 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -166,6 +166,31 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { let cast_kind = mir_cast_kind(source_ty, expr.ty); Ok(Rvalue::Cast(cast_kind, source, expr.ty)) }, + ExprKind::Tuple { fields } => Ok( + Rvalue::Aggregate( + Box::new(AggregateKind::Tuple), + fields.iter().map(|e| self.parse_operand(*e)).collect::>()? + ) + ), + ExprKind::Array { fields } => { + let elem_ty = match expr.ty.kind() { + ty::Array(ty, ..) => ty, + _ => unreachable!("ty is array"), + }; + Ok(Rvalue::Aggregate( + Box::new(AggregateKind::Array(*elem_ty)), + fields.iter().map(|e| self.parse_operand(*e)).collect::>()? + )) + }, + ExprKind::Adt(box AdtExpr{ adt_def, variant_index, substs, fields, .. }) => { + let is_union = adt_def.is_union(); + let active_field_index = is_union.then(|| fields[0].name.index()); + + Ok(Rvalue::Aggregate( + Box::new(AggregateKind::Adt(adt_def.did(), *variant_index, substs, None, active_field_index)), + fields.iter().map(|f| self.parse_operand(f.expr)).collect::>()? + )) + }, _ => self.parse_operand(expr_id).map(Rvalue::Use), ) } diff --git a/tests/mir-opt/building/custom/aggregate_exprs.adt.built.after.mir b/tests/mir-opt/building/custom/aggregate_exprs.adt.built.after.mir new file mode 100644 index 000000000000..49e8c812c197 --- /dev/null +++ b/tests/mir-opt/building/custom/aggregate_exprs.adt.built.after.mir @@ -0,0 +1,16 @@ +// MIR for `adt` after built + +fn adt() -> Onion { + let mut _0: Onion; // return place in scope 0 at $DIR/aggregate_exprs.rs:+0:13: +0:18 + let mut _1: i32; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + let mut _2: Foo; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + let mut _3: Bar; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + + bb0: { + _1 = const 1_i32; // scope 0 at $DIR/aggregate_exprs.rs:+6:13: +6:20 + _2 = Foo { a: const 1_i32, b: const 2_i32 }; // scope 0 at $DIR/aggregate_exprs.rs:+7:13: +10:14 + _3 = Bar::Foo(move _2, _1); // scope 0 at $DIR/aggregate_exprs.rs:+11:13: +11:39 + _0 = Onion { neon: ((_3 as variant#0).1: i32) }; // scope 0 at $DIR/aggregate_exprs.rs:+12:13: +12:58 + return; // scope 0 at $DIR/aggregate_exprs.rs:+13:13: +13:21 + } +} diff --git a/tests/mir-opt/building/custom/aggregate_exprs.array.built.after.mir b/tests/mir-opt/building/custom/aggregate_exprs.array.built.after.mir new file mode 100644 index 000000000000..30d12897331c --- /dev/null +++ b/tests/mir-opt/building/custom/aggregate_exprs.array.built.after.mir @@ -0,0 +1,15 @@ +// MIR for `array` after built + +fn array() -> [i32; 2] { + let mut _0: [i32; 2]; // return place in scope 0 at $DIR/aggregate_exprs.rs:+0:15: +0:23 + let mut _1: [i32; 2]; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + let mut _2: i32; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + + bb0: { + _1 = [const 42_i32, const 43_i32]; // scope 0 at $DIR/aggregate_exprs.rs:+5:13: +5:25 + _2 = const 1_i32; // scope 0 at $DIR/aggregate_exprs.rs:+6:13: +6:20 + _1 = [_2, const 2_i32]; // scope 0 at $DIR/aggregate_exprs.rs:+7:13: +7:25 + _0 = move _1; // scope 0 at $DIR/aggregate_exprs.rs:+8:13: +8:26 + return; // scope 0 at $DIR/aggregate_exprs.rs:+9:13: +9:21 + } +} diff --git a/tests/mir-opt/building/custom/aggregate_exprs.rs b/tests/mir-opt/building/custom/aggregate_exprs.rs new file mode 100644 index 000000000000..554c9c03ba4a --- /dev/null +++ b/tests/mir-opt/building/custom/aggregate_exprs.rs @@ -0,0 +1,71 @@ +#![feature(custom_mir, core_intrinsics)] + +extern crate core; +use core::intrinsics::mir::*; + +// EMIT_MIR aggregate_exprs.tuple.built.after.mir +#[custom_mir(dialect = "built")] +fn tuple() -> (i32, bool) { + mir!( + { + RET = (1, true); + Return() + } + ) +} + +// EMIT_MIR aggregate_exprs.array.built.after.mir +#[custom_mir(dialect = "built")] +fn array() -> [i32; 2] { + mir!( + let x: [i32; 2]; + let one: i32; + { + x = [42, 43]; + one = 1; + x = [one, 2]; + RET = Move(x); + Return() + } + ) +} + +struct Foo { + a: i32, + b: i32, +} + +enum Bar { + Foo(Foo, i32), +} + +union Onion { + neon: i32, + noun: f32, +} + +// EMIT_MIR aggregate_exprs.adt.built.after.mir +#[custom_mir(dialect = "built")] +fn adt() -> Onion { + mir!( + let one: i32; + let x: Foo; + let y: Bar; + { + one = 1; + x = Foo { + a: 1, + b: 2, + }; + y = Bar::Foo(Move(x), one); + RET = Onion { neon: Field(Variant(y, 0), 1) }; + Return() + } + ) +} + +fn main() { + assert_eq!(tuple(), (1, true)); + assert_eq!(array(), [1, 2]); + assert_eq!(unsafe { adt().neon }, 1); +} diff --git a/tests/mir-opt/building/custom/aggregate_exprs.tuple.built.after.mir b/tests/mir-opt/building/custom/aggregate_exprs.tuple.built.after.mir new file mode 100644 index 000000000000..5fe45ccc90ca --- /dev/null +++ b/tests/mir-opt/building/custom/aggregate_exprs.tuple.built.after.mir @@ -0,0 +1,10 @@ +// MIR for `tuple` after built + +fn tuple() -> (i32, bool) { + let mut _0: (i32, bool); // return place in scope 0 at $DIR/aggregate_exprs.rs:+0:15: +0:26 + + bb0: { + _0 = (const 1_i32, const true); // scope 0 at $DIR/aggregate_exprs.rs:+3:13: +3:28 + return; // scope 0 at $DIR/aggregate_exprs.rs:+4:13: +4:21 + } +} From e24f5ac56b001d205618590b0519137abbc65580 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Mon, 20 Mar 2023 15:27:40 +0100 Subject: [PATCH 45/70] Fix off-by-one in mir syntax doc --- compiler/rustc_middle/src/mir/syntax.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index b16b6616415a..a702a6b9ee1b 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1165,7 +1165,7 @@ pub enum AggregateKind<'tcx> { Tuple, /// The second field is the variant index. It's equal to 0 for struct - /// and union expressions. The fourth field is + /// and union expressions. The last field is the /// active field number and is present only for union expressions /// -- e.g., for a union expression `SomeUnion { c: .. }`, the /// active field index would identity the field `c` From f404f33c2197c534cf2468ea7b929e73c9b5d4b7 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Mon, 20 Mar 2023 16:21:43 +0100 Subject: [PATCH 46/70] Use builtin_index instead of match Co-authored-by: Oli Scherer --- .../rustc_mir_build/src/build/custom/parse/instruction.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index e60e1a4c8150..adbd37a7cd95 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -173,12 +173,9 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { ) ), ExprKind::Array { fields } => { - let elem_ty = match expr.ty.kind() { - ty::Array(ty, ..) => ty, - _ => unreachable!("ty is array"), - }; + let elem_ty = expr.ty.builtin_index().expect("ty must be an array"); Ok(Rvalue::Aggregate( - Box::new(AggregateKind::Array(*elem_ty)), + Box::new(AggregateKind::Array(elem_ty)), fields.iter().map(|e| self.parse_operand(*e)).collect::>()? )) }, From f321144a56aef246d430f5eea9316d8cc257a5a0 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Wed, 4 Jan 2023 15:57:17 +0000 Subject: [PATCH 47/70] Add example for `Option::product` and `Result::product` --- library/core/src/iter/traits/accum.rs | 40 ++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/library/core/src/iter/traits/accum.rs b/library/core/src/iter/traits/accum.rs index e31669b39242..f9c7eb8f9383 100644 --- a/library/core/src/iter/traits/accum.rs +++ b/library/core/src/iter/traits/accum.rs @@ -164,12 +164,13 @@ where /// element is encountered: /// /// ``` + /// let f = |&x: &i32| if x < 0 { Err("Negative element found") } else { Ok(x) }; /// let v = vec![1, 2]; - /// let res: Result = v.iter().map(|&x: &i32| - /// if x < 0 { Err("Negative element found") } - /// else { Ok(x) } - /// ).sum(); + /// let res: Result = v.iter().map(f).sum(); /// assert_eq!(res, Ok(3)); + /// let v = vec![1, -2]; + /// let res: Result = v.iter().map(f).sum(); + /// assert_eq!(res, Err("Negative element found")); /// ``` fn sum(iter: I) -> Result where @@ -187,6 +188,20 @@ where /// Takes each element in the [`Iterator`]: if it is an [`Err`], no further /// elements are taken, and the [`Err`] is returned. Should no [`Err`] /// occur, the product of all elements is returned. + /// + /// # Examples + /// + /// This multiplies each number in a vector of strings, + /// if a string could not be parsed the operation returns `Err`: + /// + /// ``` + /// let nums = vec!["5", "10", "1", "2"]; + /// let total: Result = nums.iter().map(|w| w.parse::()).product(); + /// assert_eq!(total, Ok(100)); + /// let nums = vec!["5", "10", "one", "2"]; + /// let total: Result = nums.iter().map(|w| w.parse::()).product(); + /// assert!(total.is_err()); + /// ``` fn product(iter: I) -> Result where I: Iterator>, @@ -213,6 +228,9 @@ where /// let words = vec!["have", "a", "great", "day"]; /// let total: Option = words.iter().map(|w| w.find('a')).sum(); /// assert_eq!(total, Some(5)); + /// let words = vec!["have", "a", "good", "day"]; + /// let total: Option = words.iter().map(|w| w.find('a')).sum(); + /// assert_eq!(total, None); /// ``` fn sum(iter: I) -> Option where @@ -230,6 +248,20 @@ where /// Takes each element in the [`Iterator`]: if it is a [`None`], no further /// elements are taken, and the [`None`] is returned. Should no [`None`] /// occur, the product of all elements is returned. + /// + /// # Examples + /// + /// This multiplies each number in a vector of strings, + /// if a string could not be parsed the operation returns `None`: + /// + /// ``` + /// let nums = vec!["5", "10", "1", "2"]; + /// let total: Option = nums.iter().map(|w| w.parse::().ok()).product(); + /// assert_eq!(total, Some(100)); + /// let nums = vec!["5", "10", "one", "2"]; + /// let total: Option = nums.iter().map(|w| w.parse::().ok()).product(); + /// assert_eq!(total, None); + /// ``` fn product(iter: I) -> Option where I: Iterator>, From cbb8066321b65cc6762ee2645bea5fc050e62eee Mon Sep 17 00:00:00 2001 From: yukang Date: Tue, 21 Mar 2023 01:22:43 +0800 Subject: [PATCH 48/70] Avoid ICE of attempt to add with overflow in emitter --- compiler/rustc_errors/src/lib.rs | 2 +- tests/ui/suggestions/issue-109396.rs | 12 +++++++++ tests/ui/suggestions/issue-109396.stderr | 34 ++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 tests/ui/suggestions/issue-109396.rs create mode 100644 tests/ui/suggestions/issue-109396.stderr diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index bab4f31e7770..9866a9bffe0e 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -331,7 +331,7 @@ impl CodeSuggestion { }); buf.push_str(&part.snippet); let cur_hi = sm.lookup_char_pos(part.span.hi()); - if cur_hi.line == cur_lo.line { + if cur_hi.line == cur_lo.line && !part.snippet.is_empty() { // Account for the difference between the width of the current code and the // snippet being suggested, so that the *later* suggestions are correctly // aligned on the screen. diff --git a/tests/ui/suggestions/issue-109396.rs b/tests/ui/suggestions/issue-109396.rs new file mode 100644 index 000000000000..b6c464d45a2e --- /dev/null +++ b/tests/ui/suggestions/issue-109396.rs @@ -0,0 +1,12 @@ +fn main() { + { + let mut mutex = std::mem::zeroed( + //~^ ERROR this function takes 0 arguments but 4 arguments were supplied + file.as_raw_fd(), + //~^ ERROR expected value, found macro `file` + 0, + 0, + 0, + ); + } +} diff --git a/tests/ui/suggestions/issue-109396.stderr b/tests/ui/suggestions/issue-109396.stderr new file mode 100644 index 000000000000..eca160e2fab2 --- /dev/null +++ b/tests/ui/suggestions/issue-109396.stderr @@ -0,0 +1,34 @@ +error[E0423]: expected value, found macro `file` + --> $DIR/issue-109396.rs:5:13 + | +LL | file.as_raw_fd(), + | ^^^^ not a value + +error[E0061]: this function takes 0 arguments but 4 arguments were supplied + --> $DIR/issue-109396.rs:3:25 + | +LL | let mut mutex = std::mem::zeroed( + | ^^^^^^^^^^^^^^^^ +LL | +LL | file.as_raw_fd(), + | ---------------- unexpected argument +LL | +LL | 0, + | - unexpected argument of type `{integer}` +LL | 0, + | - unexpected argument of type `{integer}` +LL | 0, + | - unexpected argument of type `{integer}` + | +note: function defined here + --> $SRC_DIR/core/src/mem/mod.rs:LL:COL +help: remove the extra arguments + | +LL - file.as_raw_fd(), +LL + , + | + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0061, E0423. +For more information about an error, try `rustc --explain E0061`. From 5058cc8e62f1557f684d90ff0dde7cedc6c5d529 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 20 Mar 2023 19:36:01 +0100 Subject: [PATCH 49/70] not *all* retags might be explicit in Runtime MIR --- compiler/rustc_middle/src/mir/syntax.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index b16b6616415a..f25577de6a45 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -78,7 +78,8 @@ pub enum MirPhase { /// MIR, this is UB. /// - Retags: If `-Zmir-emit-retag` is enabled, analysis MIR has "implicit" retags in the same way /// that Rust itself has them. Where exactly these are is generally subject to change, and so we - /// don't document this here. Runtime MIR has all retags explicit. + /// don't document this here. Runtime MIR has most retags explicit (though implicit retags + /// can still occur at `Rvalue::{Ref,AddrOf}`). /// - Generator bodies: In analysis MIR, locals may actually be behind a pointer that user code has /// access to. This occurs in generator bodies. Such locals do not behave like other locals, /// because they eg may be aliased in surprising ways. Runtime MIR has no such special locals - From 93eeb127241928a2c64b0bd8c81d5ed859b864aa Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 1 Feb 2023 16:47:04 +1100 Subject: [PATCH 50/70] Refactor `handle_missing_lit`. --- compiler/rustc_parse/src/parser/expr.rs | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 296eb4d653cd..8b69b3cb0368 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1843,20 +1843,14 @@ impl<'a> Parser<'a> { &mut self, mk_lit_char: impl FnOnce(Symbol, Span) -> L, ) -> PResult<'a, L> { - if let token::Interpolated(inner) = &self.token.kind { - let expr = match inner.as_ref() { - token::NtExpr(expr) => Some(expr), - token::NtLiteral(expr) => Some(expr), - _ => None, - }; - if let Some(expr) = expr { - if matches!(expr.kind, ExprKind::Err) { - let mut err = errors::InvalidInterpolatedExpression { span: self.token.span } - .into_diagnostic(&self.sess.span_diagnostic); - err.downgrade_to_delayed_bug(); - return Err(err); - } - } + if let token::Interpolated(nt) = &self.token.kind + && let token::NtExpr(e) | token::NtLiteral(e) = &**nt + && matches!(e.kind, ExprKind::Err) + { + let mut err = errors::InvalidInterpolatedExpression { span: self.token.span } + .into_diagnostic(&self.sess.span_diagnostic); + err.downgrade_to_delayed_bug(); + return Err(err); } let token = self.token.clone(); let err = |self_: &Self| { From 720cc40fa7114e4ea429b4d6f22790d157971756 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 7 Mar 2023 05:51:43 +0000 Subject: [PATCH 51/70] Enforce non-lifetime-binders in supertrait preds are not object safe --- compiler/rustc_middle/src/traits/mod.rs | 13 ++++- .../src/traits/object_safety.rs | 21 ++++++- .../supertrait-object-safety.rs | 24 ++++++++ .../supertrait-object-safety.stderr | 56 +++++++++++++++++++ 4 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 tests/ui/traits/non_lifetime_binders/supertrait-object-safety.rs create mode 100644 tests/ui/traits/non_lifetime_binders/supertrait-object-safety.stderr diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index fb3e9cb12631..833402abfc47 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -897,6 +897,9 @@ pub enum ObjectSafetyViolation { /// (e.g., `trait Foo : Bar`). SupertraitSelf(SmallVec<[Span; 1]>), + // Supertrait has a non-lifetime `for` binder. + SupertraitNonLifetimeBinder(SmallVec<[Span; 1]>), + /// Method has something illegal. Method(Symbol, MethodViolationCode, Span), @@ -919,6 +922,9 @@ impl ObjectSafetyViolation { .into() } } + ObjectSafetyViolation::SupertraitNonLifetimeBinder(_) => { + format!("where clause cannot reference non-lifetime `for<...>` variables").into() + } ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => { format!("associated function `{}` has no `self` parameter", name).into() } @@ -969,7 +975,9 @@ impl ObjectSafetyViolation { pub fn solution(&self, err: &mut Diagnostic) { match self { - ObjectSafetyViolation::SizedSelf(_) | ObjectSafetyViolation::SupertraitSelf(_) => {} + ObjectSafetyViolation::SizedSelf(_) + | ObjectSafetyViolation::SupertraitSelf(_) + | ObjectSafetyViolation::SupertraitNonLifetimeBinder(..) => {} ObjectSafetyViolation::Method( name, MethodViolationCode::StaticMethod(Some((add_self_sugg, make_sized_sugg))), @@ -1023,7 +1031,8 @@ impl ObjectSafetyViolation { // diagnostics use a `note` instead of a `span_label`. match self { ObjectSafetyViolation::SupertraitSelf(spans) - | ObjectSafetyViolation::SizedSelf(spans) => spans.clone(), + | ObjectSafetyViolation::SizedSelf(spans) + | ObjectSafetyViolation::SupertraitNonLifetimeBinder(spans) => spans.clone(), ObjectSafetyViolation::AssocConst(_, span) | ObjectSafetyViolation::GAT(_, span) | ObjectSafetyViolation::Method(_, _, span) diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index a5def4151bfd..038f8964471f 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -17,10 +17,10 @@ use rustc_errors::{DelayDm, FatalError, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::{GenericArg, InternalSubsts}; -use rustc_middle::ty::ToPredicate; use rustc_middle::ty::{ self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, }; +use rustc_middle::ty::{ToPredicate, TypeVisitableExt}; use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY; use rustc_span::symbol::Symbol; use rustc_span::Span; @@ -139,6 +139,10 @@ fn object_safety_violations_for_trait( if !spans.is_empty() { violations.push(ObjectSafetyViolation::SupertraitSelf(spans)); } + let spans = super_predicates_have_non_lifetime_binders(tcx, trait_def_id); + if !spans.is_empty() { + violations.push(ObjectSafetyViolation::SupertraitNonLifetimeBinder(spans)); + } violations.extend( tcx.associated_items(trait_def_id) @@ -348,6 +352,21 @@ fn predicate_references_self<'tcx>( } } +fn super_predicates_have_non_lifetime_binders( + tcx: TyCtxt<'_>, + trait_def_id: DefId, +) -> SmallVec<[Span; 1]> { + // If non_lifetime_binders is disabled, then exit early + if !tcx.features().non_lifetime_binders { + return SmallVec::new(); + } + tcx.super_predicates_of(trait_def_id) + .predicates + .iter() + .filter_map(|(pred, span)| pred.has_non_region_late_bound().then_some(*span)) + .collect() +} + fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { generics_require_sized_self(tcx, trait_def_id) } diff --git a/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.rs b/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.rs new file mode 100644 index 000000000000..a635edb4485b --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.rs @@ -0,0 +1,24 @@ +#![feature(non_lifetime_binders)] +//~^ WARN the feature `non_lifetime_binders` is incomplete + +trait Foo: for Bar {} + +trait Bar { + fn method(&self) {} +} + +fn needs_bar(x: &(impl Bar + ?Sized)) { + x.method(); +} + +impl Foo for () {} + +impl Bar for () {} + +fn main() { + let x: &dyn Foo = &(); + //~^ ERROR the trait `Foo` cannot be made into an object + //~| ERROR the trait `Foo` cannot be made into an object + needs_bar(x); + //~^ ERROR the trait `Foo` cannot be made into an object +} diff --git a/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.stderr b/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.stderr new file mode 100644 index 000000000000..47fa29b66488 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.stderr @@ -0,0 +1,56 @@ +warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/supertrait-object-safety.rs:1:12 + | +LL | #![feature(non_lifetime_binders)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #108185 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/supertrait-object-safety.rs:19:23 + | +LL | let x: &dyn Foo = &(); + | ^^^ `Foo` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/supertrait-object-safety.rs:4:12 + | +LL | trait Foo: for Bar {} + | --- ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables + | | + | this trait cannot be made into an object... + = note: required for `&()` to implement `CoerceUnsized<&dyn Foo>` + = note: required by cast to type `&dyn Foo` + +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/supertrait-object-safety.rs:19:12 + | +LL | let x: &dyn Foo = &(); + | ^^^^^^^^ `Foo` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/supertrait-object-safety.rs:4:12 + | +LL | trait Foo: for Bar {} + | --- ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables + | | + | this trait cannot be made into an object... + +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/supertrait-object-safety.rs:22:5 + | +LL | needs_bar(x); + | ^^^^^^^^^ `Foo` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/supertrait-object-safety.rs:4:12 + | +LL | trait Foo: for Bar {} + | --- ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables + | | + | this trait cannot be made into an object... + +error: aborting due to 3 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0038`. From 01771762cd6369f941d4d4ed04993209f2a85e08 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Tue, 21 Mar 2023 09:44:42 +0100 Subject: [PATCH 52/70] change default to fast for everyone but the user profile --- config.example.toml | 2 +- src/bootstrap/config.rs | 2 +- src/bootstrap/defaults/config.user.toml | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/config.example.toml b/config.example.toml index 67916049e4ac..bf22895c324d 100644 --- a/config.example.toml +++ b/config.example.toml @@ -808,4 +808,4 @@ changelog-seen = 2 # compression profile, the longer compression will take. # # Available options: fast, balanced, best -#compression-profile = "balanced" +#compression-profile = "fast" diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 939853a76d83..66f7a0141497 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -821,7 +821,7 @@ impl Config { config.deny_warnings = true; config.bindir = "bin".into(); config.dist_include_mingw_linker = true; - config.dist_compression_profile = "balanced".into(); + config.dist_compression_profile = "fast".into(); // set by build.rs config.build = TargetSelection::from_user(&env!("BUILD_TRIPLE")); diff --git a/src/bootstrap/defaults/config.user.toml b/src/bootstrap/defaults/config.user.toml index 48ae2fe448de..ee271c3fb519 100644 --- a/src/bootstrap/defaults/config.user.toml +++ b/src/bootstrap/defaults/config.user.toml @@ -11,3 +11,7 @@ extended = true [llvm] # Most users installing from source want to build all parts of the project from source, not just rustc itself. download-ci-llvm = false + +[dist] +# Use better compression when preparing tarballs. +compression-profile = "balanced" From 791ce0b7b5d03649bc9014d5b0abb78f3c6f2cfd Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 14 Mar 2023 14:19:06 +0100 Subject: [PATCH 53/70] remove some trait solver helpers they add more complexity then they are worth. It's confusing which of these helpers should be used in which context. --- .../src/diagnostics/conflict_errors.rs | 21 ++---- .../rustc_borrowck/src/diagnostics/mod.rs | 1 - .../src/transform/check_consts/qualifs.rs | 7 +- .../rustc_hir_analysis/src/check/intrinsic.rs | 1 + .../src/coherence/builtin.rs | 33 +++++---- .../rustc_hir_analysis/src/hir_wf_check.rs | 42 +++++------ compiler/rustc_hir_analysis/src/lib.rs | 33 +++++---- compiler/rustc_hir_typeck/src/callee.rs | 2 +- compiler/rustc_hir_typeck/src/cast.rs | 4 +- compiler/rustc_hir_typeck/src/coercion.rs | 16 ++--- compiler/rustc_hir_typeck/src/demand.rs | 2 +- .../rustc_hir_typeck/src/expr_use_visitor.rs | 5 +- .../src/fn_ctxt/suggestions.rs | 9 ++- .../src/mem_categorization.rs | 4 +- compiler/rustc_hir_typeck/src/op.rs | 8 ++- compiler/rustc_hir_typeck/src/upvar.rs | 5 +- .../src/for_loops_over_fallibles.rs | 10 ++- compiler/rustc_middle/src/ty/mod.rs | 14 ++++ compiler/rustc_mir_build/src/build/misc.rs | 4 +- .../src/thir/pattern/const_to_pat.rs | 16 ++--- compiler/rustc_trait_selection/src/infer.rs | 35 +++------ .../src/traits/auto_trait.rs | 5 +- .../src/traits/coherence.rs | 5 +- .../rustc_trait_selection/src/traits/mod.rs | 72 ++++--------------- .../src/traits/outlives_bounds.rs | 29 ++++---- .../src/traits/query/type_op/custom.rs | 8 +-- .../src/traits/select/confirmation.rs | 44 +++++------- .../src/traits/select/mod.rs | 13 ++-- .../rustc_trait_selection/src/traits/util.rs | 31 +------- compiler/rustc_ty_utils/src/common_traits.rs | 3 +- .../clippy_lints/src/future_not_send.rs | 6 +- 31 files changed, 199 insertions(+), 289 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 7c88205da3b9..75a3dd0c0f3d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -24,6 +24,7 @@ use rustc_span::hygiene::DesugaringKind; use rustc_span::symbol::{kw, sym}; use rustc_span::{BytePos, Span, Symbol}; use rustc_trait_selection::infer::InferCtxtExt; +use rustc_trait_selection::traits::ObligationCtxt; use crate::borrow_set::TwoPhaseActivation; use crate::borrowck_errors; @@ -760,20 +761,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { else { return; }; // Try to find predicates on *generic params* that would allow copying `ty` let infcx = tcx.infer_ctxt().build(); - let copy_did = infcx.tcx.require_lang_item(LangItem::Copy, Some(span)); - let cause = ObligationCause::new( - span, - self.mir_def_id(), - rustc_infer::traits::ObligationCauseCode::MiscObligation, - ); - let errors = rustc_trait_selection::traits::fully_solve_bound( - &infcx, - cause, - self.param_env, - // Erase any region vids from the type, which may not be resolved - infcx.tcx.erase_regions(ty), - copy_did, - ); + let ocx = ObligationCtxt::new(&infcx); + let copy_did = tcx.require_lang_item(LangItem::Copy, Some(span)); + let cause = ObligationCause::misc(span, self.mir_def_id()); + + ocx.register_bound(cause, self.param_env, infcx.tcx.erase_regions(ty), copy_did); + let errors = ocx.select_all_or_error(); // Only emit suggestion if all required predicates are on generic let predicates: Result, _> = errors diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 611abb01238b..9f543b71c5fa 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -1078,7 +1078,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.param_env, tcx.mk_imm_ref(tcx.lifetimes.re_erased, tcx.erase_regions(ty)), def_id, - DUMMY_SP, ) } _ => false, diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index bb4b7ad50b8f..6758cba2eed3 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -9,7 +9,7 @@ use rustc_middle::mir; use rustc_middle::mir::*; use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty}; use rustc_trait_selection::traits::{ - self, ImplSource, Obligation, ObligationCause, SelectionContext, + self, ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext, }; use super::ConstCx; @@ -184,7 +184,10 @@ impl Qualif for NeedsNonConstDrop { } // If we had any errors, then it's bad - !traits::fully_solve_obligations(&infcx, impl_src.nested_obligations()).is_empty() + let ocx = ObligationCtxt::new(&infcx); + ocx.register_obligations(impl_src.nested_obligations()); + let errors = ocx.select_all_or_error(); + !errors.is_empty() } fn in_adt_inherently<'tcx>( diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 8c364a4f3b2b..f7aaa7a159ff 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -59,6 +59,7 @@ fn equate_intrinsic_type<'tcx>( require_same_types( tcx, &cause, + ty::ParamEnv::empty(), // FIXME: do all intrinsics have an empty param env? tcx.mk_fn_ptr(tcx.fn_sig(it.owner_id).subst_identity()), fty, ); diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 0e1cf3e6c6a7..e57996a46764 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -11,13 +11,14 @@ use rustc_hir::ItemKind; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{self, RegionResolutionError}; use rustc_infer::infer::{DefineOpaqueTypes, TyCtxtInferExt}; +use rustc_infer::traits::Obligation; use rustc_middle::ty::adjustment::CoerceUnsizedInfo; use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitableExt}; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::misc::{ type_allowed_to_implement_copy, CopyImplementationError, InfringingFieldsReason, }; -use rustc_trait_selection::traits::predicate_for_trait_def; +use rustc_trait_selection::traits::ObligationCtxt; use rustc_trait_selection::traits::{self, ObligationCause}; use std::collections::BTreeMap; @@ -334,19 +335,19 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef )) .emit(); } else { - let errors = traits::fully_solve_obligations( - &infcx, - coerced_fields.into_iter().map(|field| { - predicate_for_trait_def( - tcx, - param_env, - cause.clone(), + let ocx = ObligationCtxt::new(&infcx); + for field in coerced_fields { + ocx.register_obligation(Obligation::new( + tcx, + cause.clone(), + param_env, + ty::Binder::dummy(tcx.mk_trait_ref( dispatch_from_dyn_trait, - 0, [field.ty(tcx, substs_a), field.ty(tcx, substs_b)], - ) - }), - ); + )), + )); + } + let errors = ocx.select_all_or_error(); if !errors.is_empty() { infcx.err_ctxt().report_fulfillment_errors(&errors); } @@ -583,10 +584,12 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn }; // Register an obligation for `A: Trait`. + let ocx = ObligationCtxt::new(&infcx); let cause = traits::ObligationCause::misc(span, impl_did); - let predicate = - predicate_for_trait_def(tcx, param_env, cause, trait_def_id, 0, [source, target]); - let errors = traits::fully_solve_obligation(&infcx, predicate); + let obligation = + Obligation::new(tcx, cause, param_env, tcx.mk_trait_ref(trait_def_id, [source, target])); + ocx.register_obligation(obligation); + let errors = ocx.select_all_or_error(); if !errors.is_empty() { infcx.err_ctxt().report_fulfillment_errors(&errors); } diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index e330fcc78577..bdd033c5f5f1 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -7,7 +7,7 @@ use rustc_infer::traits::{ObligationCause, WellFormedLoc}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Region, TyCtxt, TypeFoldable, TypeFolder}; use rustc_span::def_id::LocalDefId; -use rustc_trait_selection::traits; +use rustc_trait_selection::traits::{self, ObligationCtxt}; pub fn provide(providers: &mut Providers) { *providers = Providers { diagnostic_hir_wf_check, ..*providers }; @@ -66,35 +66,35 @@ fn diagnostic_hir_wf_check<'tcx>( impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> { fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { let infcx = self.tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new(&infcx); + let tcx_ty = self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx }); let cause = traits::ObligationCause::new( ty.span, self.def_id, traits::ObligationCauseCode::WellFormed(None), ); - let errors = traits::fully_solve_obligation( - &infcx, - traits::Obligation::new( - self.tcx, - cause, - self.param_env, - ty::Binder::dummy(ty::PredicateKind::WellFormed(tcx_ty.into())), - ), - ); - if !errors.is_empty() { - debug!("Wf-check got errors for {:?}: {:?}", ty, errors); - for error in errors { - if error.obligation.predicate == self.predicate { - // Save the cause from the greatest depth - this corresponds - // to picking more-specific types (e.g. `MyStruct`) - // over less-specific types (e.g. `Option>`) - if self.depth >= self.cause_depth { - self.cause = Some(error.obligation.cause); - self.cause_depth = self.depth - } + + ocx.register_obligation(traits::Obligation::new( + self.tcx, + cause, + self.param_env, + ty::PredicateKind::WellFormed(tcx_ty.into()), + )); + + for error in ocx.select_all_or_error() { + debug!("Wf-check got error for {:?}: {:?}", ty, error); + if error.obligation.predicate == self.predicate { + // Save the cause from the greatest depth - this corresponds + // to picking more-specific types (e.g. `MyStruct`) + // over less-specific types (e.g. `Option>`) + if self.depth >= self.cause_depth { + self.cause = Some(error.obligation.cause); + self.cause_depth = self.depth } } } + self.depth += 1; intravisit::walk_ty(self, ty); self.depth -= 1; diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 08786fe9b1ef..a3d045c80d16 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -102,7 +102,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_hir as hir; use rustc_hir::Node; -use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TyCtxtInferExt}; +use rustc_infer::infer::TyCtxtInferExt; use rustc_macros::fluent_messages; use rustc_middle::middle; use rustc_middle::ty::query::Providers; @@ -113,7 +113,7 @@ use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_span::{symbol::sym, Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; -use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; +use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, ObligationCtxt}; use std::ops::Not; @@ -160,24 +160,21 @@ fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi fn require_same_types<'tcx>( tcx: TyCtxt<'tcx>, cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>, -) -> bool { +) { let infcx = &tcx.infer_ctxt().build(); - let param_env = ty::ParamEnv::empty(); - let errors = match infcx.at(cause, param_env).eq(DefineOpaqueTypes::No, expected, actual) { - Ok(InferOk { obligations, .. }) => traits::fully_solve_obligations(infcx, obligations), + let ocx = ObligationCtxt::new(infcx); + match ocx.eq(cause, param_env, expected, actual) { + Ok(()) => { + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + infcx.err_ctxt().report_fulfillment_errors(&errors); + } + } Err(err) => { infcx.err_ctxt().report_mismatched_types(cause, expected, actual, err).emit(); - return false; - } - }; - - match &errors[..] { - [] => true, - errors => { - infcx.err_ctxt().report_fulfillment_errors(errors); - false } } } @@ -296,6 +293,8 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { return; } + // Main should have no WC, so empty param env is OK here. + let param_env = ty::ParamEnv::empty(); let expected_return_type; if let Some(term_did) = tcx.lang_items().termination() { let return_ty = main_fnsig.output(); @@ -306,8 +305,6 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { } let return_ty = return_ty.skip_binder(); let infcx = tcx.infer_ctxt().build(); - // Main should have no WC, so empty param env is OK here. - let param_env = ty::ParamEnv::empty(); let cause = traits::ObligationCause::new( return_ty_span, main_diagnostics_def_id, @@ -343,6 +340,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { main_diagnostics_def_id, ObligationCauseCode::MainFunctionType, ), + param_env, se_ty, tcx.mk_fn_ptr(main_fnsig), ); @@ -417,6 +415,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { start_def_id, ObligationCauseCode::StartFunctionType, ), + ty::ParamEnv::empty(), // start should not have any where bounds. se_ty, tcx.mk_fn_ptr(tcx.fn_sig(start_def_id).subst_identity()), ); diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index ecbe4a97dd96..5235710a2666 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -668,7 +668,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) { if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_ty) - && !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span) + && !self.type_is_sized_modulo_regions(self.param_env, output_ty) { let descr = match maybe_def { DefIdOrName::DefId(def_id) => self.tcx.def_descr(def_id), diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 316c2a7eeeb4..d28b3b3ce7bb 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -96,7 +96,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let t = self.resolve_vars_if_possible(t); t.error_reported()?; - if self.type_is_sized_modulo_regions(self.param_env, t, span) { + if self.type_is_sized_modulo_regions(self.param_env, t) { return Ok(Some(PointerKind::Thin)); } @@ -722,7 +722,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty); - if !fcx.type_is_sized_modulo_regions(fcx.param_env, self.cast_ty, self.span) + if !fcx.type_is_sized_modulo_regions(fcx.param_env, self.cast_ty) && !self.cast_ty.has_infer_types() { self.report_cast_to_unsized_type(fcx); diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index a27905ea46c9..8fa3bcd68c3d 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -46,7 +46,7 @@ use rustc_hir::Expr; use rustc_hir_analysis::astconv::AstConv; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult}; -use rustc_infer::traits::Obligation; +use rustc_infer::traits::{Obligation, PredicateObligation}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast, @@ -597,13 +597,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // and almost never more than 3. By using a SmallVec we avoid an // allocation, at the (very small) cost of (occasionally) having to // shift subsequent elements down when removing the front element. - let mut queue: SmallVec<[_; 4]> = smallvec![traits::predicate_for_trait_def( + let mut queue: SmallVec<[PredicateObligation<'tcx>; 4]> = smallvec![Obligation::new( self.tcx, - self.fcx.param_env, cause, - coerce_unsized_did, - 0, - [coerce_source, coerce_target] + self.fcx.param_env, + self.tcx.mk_trait_ref(coerce_unsized_did, [coerce_source, coerce_target]) )]; let mut has_unsized_tuple_coercion = false; @@ -651,9 +649,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let self_ty = trait_pred.skip_binder().self_ty(); let unsize_ty = trait_pred.skip_binder().trait_ref.substs[1].expect_ty(); debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_pred); - match (&self_ty.kind(), &unsize_ty.kind()) { - (ty::Infer(ty::TyVar(v)), ty::Dynamic(..)) - if self.type_var_is_sized(*v) => + match (self_ty.kind(), unsize_ty.kind()) { + (&ty::Infer(ty::TyVar(v)), ty::Dynamic(..)) + if self.type_var_is_sized(v) => { debug!("coerce_unsized: have sized infer {:?}", v); coercion.obligations.push(obligation); diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index f65f16e317d4..06e857ec3ca1 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -1480,7 +1480,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // For this suggestion to make sense, the type would need to be `Copy`, // or we have to be moving out of a `Box` - if self.type_is_copy_modulo_regions(self.param_env, expected, sp) + if self.type_is_copy_modulo_regions(self.param_env, expected) // FIXME(compiler-errors): We can actually do this if the checked_ty is // `steps` layers of boxes, not just one, but this is easier and most likely. || (checked_ty.is_box() && steps == 1) diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 9aa6c7f103f8..c62c1553d6f7 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -867,10 +867,7 @@ fn copy_or_move<'a, 'tcx>( mc: &mc::MemCategorizationContext<'a, 'tcx>, place_with_id: &PlaceWithHirId<'tcx>, ) -> ConsumeMode { - if !mc.type_is_copy_modulo_regions( - place_with_id.place.ty(), - mc.tcx().hir().span(place_with_id.hir_id), - ) { + if !mc.type_is_copy_modulo_regions(place_with_id.place.ty()) { ConsumeMode::Move } else { ConsumeMode::Copy diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 7a09ea40d797..7273b93b6769 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1011,11 +1011,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut suggest_copied_or_cloned = || { let expr_inner_ty = substs.type_at(0); let expected_inner_ty = expected_substs.type_at(0); - if let ty::Ref(_, ty, hir::Mutability::Not) = expr_inner_ty.kind() - && self.can_eq(self.param_env, *ty, expected_inner_ty) + if let &ty::Ref(_, ty, hir::Mutability::Not) = expr_inner_ty.kind() + && self.can_eq(self.param_env, ty, expected_inner_ty) { let def_path = self.tcx.def_path_str(adt_def.did()); - if self.type_is_copy_modulo_regions(self.param_env, *ty, expr.span) { + if self.type_is_copy_modulo_regions(self.param_env, ty) { diag.span_suggestion_verbose( expr.span.shrink_to_hi(), format!( @@ -1029,9 +1029,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions( self, self.param_env, - *ty, + ty, clone_did, - expr.span ) { diag.span_suggestion_verbose( diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs index 9a8d7ca9e338..95e5483abf3b 100644 --- a/compiler/rustc_hir_typeck/src/mem_categorization.rs +++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs @@ -120,8 +120,8 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { self.infcx.tcx } - pub(crate) fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>, span: Span) -> bool { - self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) + pub(crate) fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool { + self.infcx.type_is_copy_modulo_regions(self.param_env, ty) } fn resolve_vars_if_possible(&self, value: T) -> T diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 37783bc91bb8..8a83bb58573d 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -21,7 +21,7 @@ use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _; -use rustc_trait_selection::traits::{self, FulfillmentError}; +use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt}; use rustc_type_ir::sty::TyKind::*; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -434,7 +434,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if self.type_is_copy_modulo_regions( self.param_env, *lhs_deref_ty, - lhs_expr.span, ) { suggest_deref_binop(*lhs_deref_ty); } @@ -776,7 +775,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (None, Some(trait_did)) => { let (obligation, _) = self.obligation_for_method(cause, trait_did, lhs_ty, Some(input_types)); - Err(rustc_trait_selection::traits::fully_solve_obligation(self, obligation)) + // FIXME: This should potentially just add the obligation to the `FnCtxt` + let ocx = ObligationCtxt::new(&self.infcx); + ocx.register_obligation(obligation); + Err(ocx.select_all_or_error()) } } } diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 4a432328c4d1..84fe21825d78 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -424,7 +424,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // closures. We want to make sure any adjustment that might make us move the place into // the closure gets handled. let (place, capture_kind) = - restrict_precision_for_drop_types(self, place, capture_kind, usage_span); + restrict_precision_for_drop_types(self, place, capture_kind); capture_info.capture_kind = capture_kind; (place, capture_info) @@ -1822,9 +1822,8 @@ fn restrict_precision_for_drop_types<'a, 'tcx>( fcx: &'a FnCtxt<'a, 'tcx>, mut place: Place<'tcx>, mut curr_mode: ty::UpvarCapture, - span: Span, ) -> (Place<'tcx>, ty::UpvarCapture) { - let is_copy_type = fcx.infcx.type_is_copy_modulo_regions(fcx.param_env, place.ty(), span); + let is_copy_type = fcx.infcx.type_is_copy_modulo_regions(fcx.param_env, place.ty()); if let (false, UpvarCapture::ByValue) = (is_copy_type, curr_mode) { for i in 0..place.projections.len() { diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs index a3367ae4a9f1..cb7711034ed6 100644 --- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs +++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs @@ -11,6 +11,7 @@ use rustc_hir as hir; use rustc_infer::{infer::TyCtxtInferExt, traits::ObligationCause}; use rustc_middle::ty::{self, List}; use rustc_span::{sym, Span}; +use rustc_trait_selection::traits::ObligationCtxt; declare_lint! { /// The `for_loops_over_fallibles` lint checks for `for` loops over `Option` or `Result` values. @@ -136,20 +137,23 @@ fn suggest_question_mark<'tcx>( let ty = substs.type_at(0); let infcx = cx.tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new(&infcx); + let body_def_id = cx.tcx.hir().body_owner_def_id(body_id); let cause = ObligationCause::new( span, body_def_id, rustc_infer::traits::ObligationCauseCode::MiscObligation, ); - let errors = rustc_trait_selection::traits::fully_solve_bound( - &infcx, + + ocx.register_bound( cause, + // FIXME: using the empty param env is wrong, should use the one from `body_id`. ty::ParamEnv::empty(), // Erase any region vids from the type, which may not be resolved infcx.tcx.erase_regions(ty), into_iterator_did, ); - errors.is_empty() + ocx.select_all_or_error().is_empty() } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 298b2c3073cd..6ba3ab097de5 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1128,6 +1128,13 @@ impl<'tcx, T> ToPredicate<'tcx, T> for T { } } +impl<'tcx> ToPredicate<'tcx> for PredicateKind<'tcx> { + #[inline(always)] + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + ty::Binder::dummy(self).to_predicate(tcx) + } +} + impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> { #[inline(always)] fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { @@ -1142,6 +1149,13 @@ impl<'tcx> ToPredicate<'tcx> for Clause<'tcx> { } } +impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> { + #[inline(always)] + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + ty::Binder::dummy(self).to_predicate(tcx) + } +} + impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, TraitRef<'tcx>> { #[inline(always)] fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { diff --git a/compiler/rustc_mir_build/src/build/misc.rs b/compiler/rustc_mir_build/src/build/misc.rs index baeb2718cae4..90d78658f968 100644 --- a/compiler/rustc_mir_build/src/build/misc.rs +++ b/compiler/rustc_mir_build/src/build/misc.rs @@ -5,7 +5,7 @@ use crate::build::Builder; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::Span; use rustc_trait_selection::infer::InferCtxtExt; impl<'a, 'tcx> Builder<'a, 'tcx> { @@ -66,7 +66,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn consume_by_copy_or_move(&self, place: Place<'tcx>) -> Operand<'tcx> { let tcx = self.tcx; let ty = place.ty(&self.local_decls, tcx).ty; - if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, DUMMY_SP) { + if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty) { Operand::Move(place) } else { Operand::Copy(place) diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index ff88d0013517..274c2f06137a 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -1,14 +1,14 @@ use rustc_hir as hir; use rustc_index::vec::Idx; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; +use rustc_infer::traits::Obligation; use rustc_middle::mir::{self, Field}; use rustc_middle::thir::{FieldPat, Pat, PatKind}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::lint; use rustc_span::Span; -use rustc_trait_selection::traits::predicate_for_trait_def; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; -use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation}; +use rustc_trait_selection::traits::{self, ObligationCause}; use std::cell::Cell; @@ -189,17 +189,15 @@ impl<'tcx> ConstToPat<'tcx> { // using `PartialEq::eq` in this scenario in the past.) let partial_eq_trait_id = self.tcx().require_lang_item(hir::LangItem::PartialEq, Some(self.span)); - let obligation: PredicateObligation<'_> = predicate_for_trait_def( + let partial_eq_obligation = Obligation::new( self.tcx(), + ObligationCause::dummy(), self.param_env, - ObligationCause::misc(self.span, self.id.owner.def_id), - partial_eq_trait_id, - 0, - [ty, ty], + self.tcx().mk_trait_ref(partial_eq_trait_id, [ty, ty]), ); - // FIXME: should this call a `predicate_must_hold` variant instead? - let has_impl = self.infcx.predicate_may_hold(&obligation); + // FIXME: should this call a `predicate_must_hold` variant instead? + let has_impl = self.infcx.predicate_may_hold(&partial_eq_obligation); // Note: To fix rust-lang/rust#65466, we could just remove this type // walk hack for function pointers, and unconditionally error diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 9b47c7299bb7..911cc0b88c40 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -8,26 +8,16 @@ use rustc_middle::infer::canonical::{Canonical, CanonicalQueryResponse, QueryRes use rustc_middle::traits::query::Fallible; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_middle::ty::{GenericArg, ToPredicate}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::DUMMY_SP; use std::fmt::Debug; pub use rustc_infer::infer::*; pub trait InferCtxtExt<'tcx> { - fn type_is_copy_modulo_regions( - &self, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - span: Span, - ) -> bool; + fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool; - fn type_is_sized_modulo_regions( - &self, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - span: Span, - ) -> bool; + fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool; /// Check whether a `ty` implements given trait(trait_def_id). /// The inputs are: @@ -46,13 +36,9 @@ pub trait InferCtxtExt<'tcx> { param_env: ty::ParamEnv<'tcx>, ) -> traits::EvaluationResult; } + impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { - fn type_is_copy_modulo_regions( - &self, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - span: Span, - ) -> bool { + fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { let ty = self.resolve_vars_if_possible(ty); if !(param_env, ty).needs_infer() { @@ -65,17 +51,12 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { // rightly refuses to work with inference variables, but // moves_by_default has a cache, which we want to use in other // cases. - traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id, span) + traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id) } - fn type_is_sized_modulo_regions( - &self, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - span: Span, - ) -> bool { + fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); - traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item, span) + traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item) } #[instrument(level = "debug", skip(self, params), ret)] diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 1870d3a2daf3..dbf6775afc2f 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -180,8 +180,9 @@ impl<'tcx> AutoTraitFinder<'tcx> { // At this point, we already have all of the bounds we need. FulfillmentContext is used // to store all of the necessary region/lifetime bounds in the InferContext, as well as // an additional sanity check. - let errors = - super::fully_solve_bound(&infcx, ObligationCause::dummy(), full_env, ty, trait_did); + let ocx = ObligationCtxt::new(&infcx); + ocx.register_bound(ObligationCause::dummy(), full_env, ty, trait_did); + let errors = ocx.select_all_or_error(); if !errors.is_empty() { panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors); } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index f4cfe4ec0b0c..572d20b5368b 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -383,7 +383,10 @@ fn resolve_negative_obligation<'tcx>( }; let param_env = o.param_env; - if !super::fully_solve_obligation(&infcx, o).is_empty() { + let ocx = ObligationCtxt::new(&infcx); + ocx.register_obligation(o); + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { return false; } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index bfeda88a6d40..b27a39290781 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -30,7 +30,7 @@ use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeSuperVisitable}; use rustc_middle::ty::{InternalSubsts, SubstsRef}; -use rustc_span::def_id::{DefId, CRATE_DEF_ID}; +use rustc_span::def_id::DefId; use rustc_span::Span; use std::fmt::Debug; @@ -63,9 +63,7 @@ pub use self::util::{ elaborate_trait_ref, elaborate_trait_refs, }; pub use self::util::{expand_trait_aliases, TraitAliasExpander}; -pub use self::util::{ - get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices, -}; +pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices}; pub use self::util::{ supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_type, SupertraitDefIds, Supertraits, @@ -131,29 +129,23 @@ pub fn type_known_to_meet_bound_modulo_regions<'tcx>( param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, def_id: DefId, - span: Span, ) -> bool { let trait_ref = ty::Binder::dummy(infcx.tcx.mk_trait_ref(def_id, [ty])); - pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref.without_const(), span) + pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref.without_const()) } -#[instrument(level = "debug", skip(infcx, param_env, span, pred), ret)] +/// FIXME(@lcnr): this function doesn't seem right and shouldn't exist? +/// +/// Ping me on zulip if you want to use this method and need help with finding +/// an appropriate replacement. +#[instrument(level = "debug", skip(infcx, param_env, pred), ret)] fn pred_known_to_hold_modulo_regions<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, pred: impl ToPredicate<'tcx> + TypeVisitable>, - span: Span, ) -> bool { let has_non_region_infer = pred.has_non_region_infer(); - let obligation = Obligation { - param_env, - // We can use a dummy node-id here because we won't pay any mind - // to region obligations that arise (there shouldn't really be any - // anyhow). - cause: ObligationCause::misc(span, CRATE_DEF_ID), - recursion_depth: 0, - predicate: pred.to_predicate(infcx.tcx), - }; + let obligation = Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, pred); let result = infcx.evaluate_obligation_no_overflow(&obligation); debug!(?result); @@ -166,14 +158,13 @@ fn pred_known_to_hold_modulo_regions<'tcx>( // this function's result remains infallible, we must confirm // that guess. While imperfect, I believe this is sound. - // FIXME(@lcnr): this function doesn't seem right. - // // The handling of regions in this area of the code is terrible, // see issue #29149. We should be able to improve on this with // NLL. - let errors = fully_solve_obligation(infcx, obligation); - - match &errors[..] { + let ocx = ObligationCtxt::new(infcx); + ocx.register_obligation(obligation); + let errors = ocx.select_all_or_error(); + match errors.as_slice() { [] => true, errors => { debug!(?errors); @@ -389,43 +380,6 @@ where Ok(resolved_value) } -/// Process an obligation (and any nested obligations that come from it) to -/// completion, returning any errors -pub fn fully_solve_obligation<'tcx>( - infcx: &InferCtxt<'tcx>, - obligation: PredicateObligation<'tcx>, -) -> Vec> { - fully_solve_obligations(infcx, [obligation]) -} - -/// Process a set of obligations (and any nested obligations that come from them) -/// to completion -pub fn fully_solve_obligations<'tcx>( - infcx: &InferCtxt<'tcx>, - obligations: impl IntoIterator>, -) -> Vec> { - let ocx = ObligationCtxt::new(infcx); - ocx.register_obligations(obligations); - ocx.select_all_or_error() -} - -/// Process a bound (and any nested obligations that come from it) to completion. -/// This is a convenience function for traits that have no generic arguments, such -/// as auto traits, and builtin traits like Copy or Sized. -pub fn fully_solve_bound<'tcx>( - infcx: &InferCtxt<'tcx>, - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - bound: DefId, -) -> Vec> { - let tcx = infcx.tcx; - let trait_ref = tcx.mk_trait_ref(bound, [ty]); - let obligation = Obligation::new(tcx, cause, param_env, ty::Binder::dummy(trait_ref)); - - fully_solve_obligation(infcx, obligation) -} - /// Normalizes the predicates and checks whether they hold in an empty environment. If this /// returns true, then either normalize encountered an error or one of the predicates did not /// hold. Used when creating vtables to check for unsatisfiable methods. diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 6cb64ad574f5..bac02f2d3832 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -1,7 +1,7 @@ use crate::infer::InferCtxt; use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput}; use crate::traits::query::NoSolution; -use crate::traits::ObligationCause; +use crate::traits::{ObligationCause, ObligationCtxt}; use rustc_data_structures::fx::FxIndexSet; use rustc_middle::ty::{self, ParamEnv, Ty}; use rustc_span::def_id::LocalDefId; @@ -71,22 +71,23 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { if let Some(constraints) = constraints { debug!(?constraints); - // Instantiation may have produced new inference variables and constraints on those - // variables. Process these constraints. - let cause = ObligationCause::misc(span, body_id); - let errors = super::fully_solve_obligations( - self, - constraints.outlives.iter().map(|constraint| { - self.query_outlives_constraint_to_obligation( - *constraint, - cause.clone(), - param_env, - ) - }), - ); if !constraints.member_constraints.is_empty() { span_bug!(span, "{:#?}", constraints.member_constraints); } + + // Instantiation may have produced new inference variables and constraints on those + // variables. Process these constraints. + let ocx = ObligationCtxt::new(self); + let cause = ObligationCause::misc(span, body_id); + for &constraint in &constraints.outlives { + ocx.register_obligation(self.query_outlives_constraint_to_obligation( + constraint, + cause.clone(), + param_env, + )); + } + + let errors = ocx.select_all_or_error(); if !errors.is_empty() { self.tcx.sess.delay_span_bug( span, diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index 6bf3ed0d0e29..8f1b05c1190d 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -1,8 +1,8 @@ use crate::infer::canonical::query_response; use crate::infer::{InferCtxt, InferOk}; -use crate::traits; use crate::traits::query::type_op::TypeOpOutput; use crate::traits::query::Fallible; +use crate::traits::ObligationCtxt; use rustc_infer::infer::region_constraints::RegionConstraintData; use rustc_span::source_map::DUMMY_SP; @@ -73,7 +73,9 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( ); let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?; - let errors = traits::fully_solve_obligations(infcx, obligations); + let ocx = ObligationCtxt::new(infcx); + ocx.register_obligations(obligations); + let errors = ocx.select_all_or_error(); if !errors.is_empty() { infcx.tcx.sess.diagnostic().delay_span_bug( DUMMY_SP, @@ -82,9 +84,7 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( } let region_obligations = infcx.take_registered_region_obligations(); - let region_constraint_data = infcx.take_and_reset_region_constraints(); - let region_constraints = query_response::make_query_region_constraints( infcx.tcx, region_obligations diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 3d5dd18f4c1d..eb354bc3f50c 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -18,7 +18,7 @@ use rustc_session::config::TraitSolver; use rustc_span::def_id::DefId; use crate::traits::project::{normalize_with_depth, normalize_with_depth_to}; -use crate::traits::util::{self, closure_trait_ref_and_return_type, predicate_for_trait_def}; +use crate::traits::util::{self, closure_trait_ref_and_return_type}; use crate::traits::vtable::{ count_own_vtable_entries, prepare_vtable_segments, vtable_trait_first_method_offset, VtblSegment, @@ -253,15 +253,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; let cause = obligation.derived_cause(BuiltinDerivedObligation); - ensure_sufficient_stack(|| { - self.collect_predicates_for_types( - obligation.param_env, - cause, - obligation.recursion_depth + 1, - trait_def, - nested, - ) - }) + self.collect_predicates_for_types( + obligation.param_env, + cause, + obligation.recursion_depth + 1, + trait_def, + nested, + ) } else { vec![] }; @@ -1118,14 +1116,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { nested.extend(obligations); // Construct the nested `TailField: Unsize>` predicate. - nested.push(predicate_for_trait_def( + let tail_unsize_obligation = obligation.with( tcx, - obligation.param_env, - obligation.cause.clone(), - obligation.predicate.def_id(), - obligation.recursion_depth + 1, - [source_tail, target_tail], - )); + tcx.mk_trait_ref(obligation.predicate.def_id(), [source_tail, target_tail]), + ); + nested.push(tail_unsize_obligation); } // `(.., T)` -> `(.., U)` @@ -1147,17 +1142,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .map_err(|_| Unimplemented)?; nested.extend(obligations); - // Construct the nested `T: Unsize` predicate. - nested.push(ensure_sufficient_stack(|| { - predicate_for_trait_def( - tcx, - obligation.param_env, - obligation.cause.clone(), - obligation.predicate.def_id(), - obligation.recursion_depth + 1, - [a_last, b_last], - ) - })); + // Add a nested `T: Unsize` predicate. + let last_unsize_obligation = obligation + .with(tcx, tcx.mk_trait_ref(obligation.predicate.def_id(), [a_last, b_last])); + nested.push(last_unsize_obligation); } _ => bug!("source: {source}, target: {target}"), diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index bc1c72da1e17..d9b2b7dbe164 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -17,7 +17,7 @@ use super::project; use super::project::normalize_with_depth_to; use super::project::ProjectionTyObligation; use super::util; -use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def}; +use super::util::closure_trait_ref_and_return_type; use super::wf; use super::{ ErrorReporting, ImplDerivedObligation, ImplDerivedObligationCause, Normalized, Obligation, @@ -2440,15 +2440,14 @@ impl<'tcx> SelectionContext<'_, 'tcx> { placeholder_ty, ) }); - let placeholder_obligation = predicate_for_trait_def( + + let obligation = Obligation::new( self.tcx(), - param_env, cause.clone(), - trait_def_id, - recursion_depth, - [normalized_ty], + param_env, + self.tcx().mk_trait_ref(trait_def_id, [normalized_ty]), ); - obligations.push(placeholder_obligation); + obligations.push(obligation); obligations }) .collect() diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index ab4c36975a0e..00c9a3522588 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -1,11 +1,11 @@ use super::NormalizeExt; -use super::{Obligation, ObligationCause, PredicateObligation, SelectionContext}; +use super::{ObligationCause, PredicateObligation, SelectionContext}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Diagnostic; use rustc_hir::def_id::DefId; use rustc_infer::infer::InferOk; +use rustc_middle::ty::SubstsRef; use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitableExt}; -use rustc_middle::ty::{GenericArg, SubstsRef}; use rustc_span::Span; use smallvec::SmallVec; @@ -218,33 +218,6 @@ pub fn impl_subject_and_oblig<'a, 'tcx>( (subject, impl_obligations) } -pub fn predicate_for_trait_ref<'tcx>( - tcx: TyCtxt<'tcx>, - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - trait_ref: ty::TraitRef<'tcx>, - recursion_depth: usize, -) -> PredicateObligation<'tcx> { - Obligation { - cause, - param_env, - recursion_depth, - predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx), - } -} - -pub fn predicate_for_trait_def<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - trait_def_id: DefId, - recursion_depth: usize, - params: impl IntoIterator>>, -) -> PredicateObligation<'tcx> { - let trait_ref = tcx.mk_trait_ref(trait_def_id, params); - predicate_for_trait_ref(tcx, cause, param_env, trait_ref, recursion_depth) -} - /// Casts a trait reference into a reference to one of its super /// traits; returns `None` if `target_trait_def_id` is not a /// supertrait. diff --git a/compiler/rustc_ty_utils/src/common_traits.rs b/compiler/rustc_ty_utils/src/common_traits.rs index d3169b6d962e..3b1abdcb24f8 100644 --- a/compiler/rustc_ty_utils/src/common_traits.rs +++ b/compiler/rustc_ty_utils/src/common_traits.rs @@ -3,7 +3,6 @@ use rustc_hir::lang_items::LangItem; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::DUMMY_SP; use rustc_trait_selection::traits; fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { @@ -30,7 +29,7 @@ fn is_item_raw<'tcx>( let (param_env, ty) = query.into_parts(); let trait_def_id = tcx.require_lang_item(item, None); let infcx = tcx.infer_ctxt().build(); - traits::type_known_to_meet_bound_modulo_regions(&infcx, param_env, ty, trait_def_id, DUMMY_SP) + traits::type_known_to_meet_bound_modulo_regions(&infcx, param_env, ty, trait_def_id) } pub(crate) fn provide(providers: &mut ty::query::Providers) { diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index 9fb73a371b8f..ed0bd58c770c 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -9,7 +9,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt; -use rustc_trait_selection::traits::{self, FulfillmentError}; +use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt}; declare_clippy_lint! { /// ### What it does @@ -79,8 +79,10 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap(); let span = decl.output.span(); let infcx = cx.tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new(&infcx); let cause = traits::ObligationCause::misc(span, fn_def_id); - let send_errors = traits::fully_solve_bound(&infcx, cause, cx.param_env, ret_ty, send_trait); + ocx.register_bound(cause, cx.param_env, ret_ty, send_trait); + let send_errors = ocx.select_all_or_error(); if !send_errors.is_empty() { span_lint_and_then( cx, From c63861b9d5a91b827c5c8164e24ee556dd790bbe Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 14 Mar 2023 14:56:16 +0100 Subject: [PATCH 54/70] evaluate: improve and fix recursion depth handling --- compiler/rustc_infer/src/traits/mod.rs | 10 +++ .../src/traits/select/mod.rs | 71 +++++-------------- tests/ui/associated-consts/issue-93775.rs | 2 +- tests/ui/did_you_mean/recursion_limit.stderr | 7 +- tests/ui/error-codes/E0275.stderr | 2 +- tests/ui/issues/issue-20413.stderr | 34 ++++----- tests/ui/traits/cycle-cache-err-60010.stderr | 15 +--- .../traits/issue-91949-hangs-on-recursion.rs | 2 +- .../issue-91949-hangs-on-recursion.stderr | 12 +++- 9 files changed, 60 insertions(+), 95 deletions(-) diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index 77c67c14ecc5..dd9b2e548c73 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -8,6 +8,8 @@ mod project; mod structural_impls; pub mod util; +use std::cmp; + use hir::def_id::LocalDefId; use rustc_hir as hir; use rustc_middle::ty::error::{ExpectedFound, TypeError}; @@ -139,6 +141,14 @@ impl<'tcx, O> Obligation<'tcx, O> { Self::with_depth(tcx, cause, 0, param_env, predicate) } + /// We often create nested obligations without setting the correct depth. + /// + /// To deal with this evaluate and fulfill explicitly update the depth + /// of nested obligations using this function. + pub fn set_depth_from_parent(&mut self, parent_depth: usize) { + self.recursion_depth = cmp::max(parent_depth + 1, self.recursion_depth); + } + pub fn with_depth( tcx: TyCtxt<'tcx>, cause: ObligationCause<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index d9b2b7dbe164..b8758ad93231 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -595,7 +595,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.evaluate_predicates_recursively_in_new_solver(predicates) } else { let mut result = EvaluatedToOk; - for obligation in predicates { + for mut obligation in predicates { + obligation.set_depth_from_parent(stack.depth()); let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?; if let EvaluatedToErr = eval { // fast-path - EvaluatedToErr is the top of the lattice, @@ -661,12 +662,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let p = bound_predicate.rebind(p); // Does this code ever run? match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) { - Ok(Ok(InferOk { mut obligations, .. })) => { - self.add_depth(obligations.iter_mut(), obligation.recursion_depth); - self.evaluate_predicates_recursively( - previous_stack, - obligations.into_iter(), - ) + Ok(Ok(InferOk { obligations, .. })) => { + self.evaluate_predicates_recursively(previous_stack, obligations) } Ok(Err(_)) => Ok(EvaluatedToErr), Err(..) => Ok(EvaluatedToAmbig), @@ -677,12 +674,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let p = bound_predicate.rebind(p); // Does this code ever run? match self.infcx.coerce_predicate(&obligation.cause, obligation.param_env, p) { - Ok(Ok(InferOk { mut obligations, .. })) => { - self.add_depth(obligations.iter_mut(), obligation.recursion_depth); - self.evaluate_predicates_recursively( - previous_stack, - obligations.into_iter(), - ) + Ok(Ok(InferOk { obligations, .. })) => { + self.evaluate_predicates_recursively(previous_stack, obligations) } Ok(Err(_)) => Ok(EvaluatedToErr), Err(..) => Ok(EvaluatedToAmbig), @@ -755,9 +748,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { arg, obligation.cause.span, ) { - Some(mut obligations) => { - self.add_depth(obligations.iter_mut(), obligation.recursion_depth); - + Some(obligations) => { cache.wf_args.borrow_mut().push((arg, previous_stack.depth())); let result = self.evaluate_predicates_recursively(previous_stack, obligations); @@ -826,10 +817,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - self.add_depth( - subobligations.iter_mut(), - obligation.recursion_depth, - ); + // Need to explicitly set the depth of nested goals here as + // projection obligations can cycle by themselves and in + // `evaluate_predicates_recursively` we only add the depth + // for parent trait goals because only these get added to the + // `TraitObligationStackList`. + for subobligation in subobligations.iter_mut() { + subobligation.set_depth_from_parent(obligation.recursion_depth); + } let res = self.evaluate_predicates_recursively( previous_stack, subobligations, @@ -909,38 +904,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if a.def.did == b.def.did && tcx.def_kind(a.def.did) == DefKind::AssocConst => { - if let Ok(new_obligations) = self + if let Ok(InferOk { obligations, value: () }) = self .infcx .at(&obligation.cause, obligation.param_env) .trace(c1, c2) .eq(DefineOpaqueTypes::No, a.substs, b.substs) { - let mut obligations = new_obligations.obligations; - self.add_depth( - obligations.iter_mut(), - obligation.recursion_depth, - ); return self.evaluate_predicates_recursively( previous_stack, - obligations.into_iter(), + obligations, ); } } (_, Unevaluated(_)) | (Unevaluated(_), _) => (), (_, _) => { - if let Ok(new_obligations) = self + if let Ok(InferOk { obligations, value: () }) = self .infcx .at(&obligation.cause, obligation.param_env) .eq(DefineOpaqueTypes::No, c1, c2) { - let mut obligations = new_obligations.obligations; - self.add_depth( - obligations.iter_mut(), - obligation.recursion_depth, - ); return self.evaluate_predicates_recursively( previous_stack, - obligations.into_iter(), + obligations, ); } } @@ -1366,24 +1351,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.evaluation_cache.insert((param_env, trait_pred), dep_node, result); } - /// For various reasons, it's possible for a subobligation - /// to have a *lower* recursion_depth than the obligation used to create it. - /// Projection sub-obligations may be returned from the projection cache, - /// which results in obligations with an 'old' `recursion_depth`. - /// Additionally, methods like `InferCtxt.subtype_predicate` produce - /// subobligations without taking in a 'parent' depth, causing the - /// generated subobligations to have a `recursion_depth` of `0`. - /// - /// To ensure that obligation_depth never decreases, we force all subobligations - /// to have at least the depth of the original obligation. - fn add_depth>>( - &self, - it: I, - min_depth: usize, - ) { - it.for_each(|o| o.recursion_depth = cmp::max(min_depth, o.recursion_depth) + 1); - } - fn check_recursion_depth( &self, depth: usize, diff --git a/tests/ui/associated-consts/issue-93775.rs b/tests/ui/associated-consts/issue-93775.rs index 7a007b732de8..db788fe6e6af 100644 --- a/tests/ui/associated-consts/issue-93775.rs +++ b/tests/ui/associated-consts/issue-93775.rs @@ -3,7 +3,7 @@ // Regression for #93775, needs build-pass to test it. -#![recursion_limit = "1000"] +#![recursion_limit = "1001"] use std::marker::PhantomData; diff --git a/tests/ui/did_you_mean/recursion_limit.stderr b/tests/ui/did_you_mean/recursion_limit.stderr index 247fe4b5b07b..70e49566ac0d 100644 --- a/tests/ui/did_you_mean/recursion_limit.stderr +++ b/tests/ui/did_you_mean/recursion_limit.stderr @@ -1,15 +1,10 @@ -error[E0275]: overflow evaluating the requirement `K: Send` +error[E0275]: overflow evaluating the requirement `J: Send` --> $DIR/recursion_limit.rs:34:5 | LL | is_send::(); | ^^^^^^^^^^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`recursion_limit`) -note: required because it appears within the type `J` - --> $DIR/recursion_limit.rs:24:9 - | -LL | link! { J, K } - | ^ note: required because it appears within the type `I` --> $DIR/recursion_limit.rs:23:9 | diff --git a/tests/ui/error-codes/E0275.stderr b/tests/ui/error-codes/E0275.stderr index cf9a7f69bfbd..03c37d6f0e1d 100644 --- a/tests/ui/error-codes/E0275.stderr +++ b/tests/ui/error-codes/E0275.stderr @@ -11,7 +11,7 @@ note: required for `Bar Foo for T where Bar: Foo {} | ^^^ ^ --- unsatisfied trait bound introduced here = note: the full type name has been written to '$TEST_BUILD_DIR/error-codes/E0275/E0275.long-type-hash.txt' - = note: 127 redundant requirements hidden + = note: 126 redundant requirements hidden = note: required for `Bar` to implement `Foo` error: aborting due to previous error diff --git a/tests/ui/issues/issue-20413.stderr b/tests/ui/issues/issue-20413.stderr index 202e8463145c..8891a26784e4 100644 --- a/tests/ui/issues/issue-20413.stderr +++ b/tests/ui/issues/issue-20413.stderr @@ -20,51 +20,51 @@ note: required for `NoData Foo for T where NoData: Foo { | ^^^ ^ --- unsatisfied trait bound introduced here = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt' - = note: 127 redundant requirements hidden + = note: 126 redundant requirements hidden = note: required for `NoData` to implement `Foo` -error[E0275]: overflow evaluating the requirement `EvenLessData>>>>>>: Baz` +error[E0275]: overflow evaluating the requirement `AlmostNoData>>>>>>: Bar` --> $DIR/issue-20413.rs:28:42 | LL | impl Bar for T where EvenLessData: Baz { | ^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_20413`) -note: required for `AlmostNoData>>>>>>` to implement `Bar` - --> $DIR/issue-20413.rs:28:9 - | -LL | impl Bar for T where EvenLessData: Baz { - | ^^^ ^ --- unsatisfied trait bound introduced here - = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt' note: required for `EvenLessData>>>>>>` to implement `Baz` --> $DIR/issue-20413.rs:35:9 | LL | impl Baz for T where AlmostNoData: Bar { | ^^^ ^ --- unsatisfied trait bound introduced here = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt' - = note: 126 redundant requirements hidden +note: required for `AlmostNoData>>>>>>` to implement `Bar` + --> $DIR/issue-20413.rs:28:9 + | +LL | impl Bar for T where EvenLessData: Baz { + | ^^^ ^ --- unsatisfied trait bound introduced here + = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt' + = note: 125 redundant requirements hidden = note: required for `EvenLessData` to implement `Baz` -error[E0275]: overflow evaluating the requirement `AlmostNoData>>>>>>: Bar` +error[E0275]: overflow evaluating the requirement `EvenLessData>>>>>>: Baz` --> $DIR/issue-20413.rs:35:42 | LL | impl Baz for T where AlmostNoData: Bar { | ^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_20413`) -note: required for `EvenLessData>>>>>>` to implement `Baz` - --> $DIR/issue-20413.rs:35:9 - | -LL | impl Baz for T where AlmostNoData: Bar { - | ^^^ ^ --- unsatisfied trait bound introduced here - = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt' note: required for `AlmostNoData>>>>>>` to implement `Bar` --> $DIR/issue-20413.rs:28:9 | LL | impl Bar for T where EvenLessData: Baz { | ^^^ ^ --- unsatisfied trait bound introduced here = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt' - = note: 126 redundant requirements hidden +note: required for `EvenLessData>>>>>>` to implement `Baz` + --> $DIR/issue-20413.rs:35:9 + | +LL | impl Baz for T where AlmostNoData: Bar { + | ^^^ ^ --- unsatisfied trait bound introduced here + = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt' + = note: 125 redundant requirements hidden = note: required for `AlmostNoData` to implement `Bar` error: aborting due to 4 previous errors diff --git a/tests/ui/traits/cycle-cache-err-60010.stderr b/tests/ui/traits/cycle-cache-err-60010.stderr index eeee997608e6..2ff16b4af38d 100644 --- a/tests/ui/traits/cycle-cache-err-60010.stderr +++ b/tests/ui/traits/cycle-cache-err-60010.stderr @@ -1,22 +1,9 @@ -error[E0275]: overflow evaluating the requirement `SalsaStorage: RefUnwindSafe` +error[E0275]: overflow evaluating the requirement `RootDatabase: RefUnwindSafe` --> $DIR/cycle-cache-err-60010.rs:27:13 | LL | _parse: >::Data, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: required because it appears within the type `PhantomData` - = note: required because it appears within the type `Unique` - = note: required because it appears within the type `Box` -note: required because it appears within the type `Runtime` - --> $DIR/cycle-cache-err-60010.rs:23:8 - | -LL | struct Runtime { - | ^^^^^^^ -note: required because it appears within the type `RootDatabase` - --> $DIR/cycle-cache-err-60010.rs:20:8 - | -LL | struct RootDatabase { - | ^^^^^^^^^^^^ note: required for `RootDatabase` to implement `SourceDatabase` --> $DIR/cycle-cache-err-60010.rs:44:9 | diff --git a/tests/ui/traits/issue-91949-hangs-on-recursion.rs b/tests/ui/traits/issue-91949-hangs-on-recursion.rs index 6474b2b38e1c..4eca643a92d4 100644 --- a/tests/ui/traits/issue-91949-hangs-on-recursion.rs +++ b/tests/ui/traits/issue-91949-hangs-on-recursion.rs @@ -1,6 +1,6 @@ // build-fail // compile-flags: -Zinline-mir=no -// error-pattern: overflow evaluating the requirement `(): Sized` +// error-pattern: overflow evaluating the requirement ` as Iterator>::Item == ()` // error-pattern: function cannot return without recursing // normalize-stderr-test: "long-type-\d+" -> "long-type-hash" diff --git a/tests/ui/traits/issue-91949-hangs-on-recursion.stderr b/tests/ui/traits/issue-91949-hangs-on-recursion.stderr index 1f18c5daf66e..144990d50f00 100644 --- a/tests/ui/traits/issue-91949-hangs-on-recursion.stderr +++ b/tests/ui/traits/issue-91949-hangs-on-recursion.stderr @@ -12,11 +12,17 @@ LL | recurse(IteratorOfWrapped(elements).map(|t| t.0)) = help: a `loop` may express intention better if this is on purpose = note: `#[warn(unconditional_recursion)]` on by default -error[E0275]: overflow evaluating the requirement `(): Sized` +error[E0275]: overflow evaluating the requirement ` as Iterator>::Item == ()` | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "512"]` attribute to your crate (`issue_91949_hangs_on_recursion`) - = note: required for `std::iter::Empty<()>` to implement `Iterator` - = note: 171 redundant requirements hidden +note: required for `IteratorOfWrapped<(), std::iter::Empty<()>>` to implement `Iterator` + --> $DIR/issue-91949-hangs-on-recursion.rs:16:32 + | +LL | impl> Iterator for IteratorOfWrapped { + | -------- ^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ + | | + | unsatisfied trait bound introduced here + = note: 256 redundant requirements hidden = note: required for `IteratorOfWrapped<(), Map>, ...>>, ...>>` to implement `Iterator` = note: the full type name has been written to '$TEST_BUILD_DIR/traits/issue-91949-hangs-on-recursion/issue-91949-hangs-on-recursion.long-type-hash.txt' From b8541eb76769798cc34908dc815cc17b6a7a91bc Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 15 Mar 2023 14:36:10 +0100 Subject: [PATCH 55/70] use the correct param env --- compiler/rustc_lint/src/for_loops_over_fallibles.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs index cb7711034ed6..7b58bf03bbea 100644 --- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs +++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs @@ -148,8 +148,7 @@ fn suggest_question_mark<'tcx>( ocx.register_bound( cause, - // FIXME: using the empty param env is wrong, should use the one from `body_id`. - ty::ParamEnv::empty(), + cx.param_env, // Erase any region vids from the type, which may not be resolved infcx.tcx.erase_regions(ty), into_iterator_did, From fb9e171ab7b0303fc983b6955e684ebb2a0f5944 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 21 Mar 2023 11:11:32 +0000 Subject: [PATCH 56/70] Only implement Fn* traits for extern "Rust" safe function pointers. --- .../solve/trait_goals/structural_traits.rs | 16 ++++- .../src/traits/select/candidate_assembly.rs | 3 + tests/ui/traits/new-solver/fn-trait.rs | 17 ++++- tests/ui/traits/new-solver/fn-trait.stderr | 64 +++++++++++++++++++ 4 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 tests/ui/traits/new-solver/fn-trait.stderr diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs index d7d93377cf16..51a1a88f8e77 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs @@ -2,6 +2,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::{def_id::DefId, Movability, Mutability}; use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable}; +use rustc_target::spec::abi::Abi; use crate::solve::EvalCtxt; @@ -194,7 +195,20 @@ pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>( .subst(tcx, substs) .map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())), )), - ty::FnPtr(sig) => Ok(Some(sig.map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())))), + // keep this in sync with assemble_fn_pointer_candidates until the old solver is removed. + ty::FnPtr(sig) => { + if let ty::FnSig { + unsafety: rustc_hir::Unsafety::Normal, + abi: Abi::Rust, + c_variadic: false, + .. + } = sig.skip_binder() + { + Ok(Some(sig.map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())))) + } else { + Err(NoSolution) + } + } ty::Closure(_, substs) => { let closure_substs = substs.as_closure(); match closure_substs.kind_ty().to_opt_closure_kind() { diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 3182af989f05..2b3f003353c6 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -291,6 +291,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return; } + // Keep this funtion in sync with extract_tupled_inputs_and_output_from_callable + // until the old solver (and thus this function) is removed. + // Okay to skip binder because what we are inspecting doesn't involve bound regions. let self_ty = obligation.self_ty().skip_binder(); match *self_ty.kind() { diff --git a/tests/ui/traits/new-solver/fn-trait.rs b/tests/ui/traits/new-solver/fn-trait.rs index d566ead105c8..8967858a8ba5 100644 --- a/tests/ui/traits/new-solver/fn-trait.rs +++ b/tests/ui/traits/new-solver/fn-trait.rs @@ -1,5 +1,4 @@ // compile-flags: -Ztrait-solver=next -// check-pass fn require_fn(_: impl Fn() -> i32) {} @@ -7,7 +6,23 @@ fn f() -> i32 { 1i32 } +extern "C" fn g() -> i32 { + 2i32 +} + +unsafe fn h() -> i32 { + 2i32 +} + fn main() { require_fn(f); require_fn(f as fn() -> i32); + require_fn(f as unsafe fn() -> i32); + //~^ ERROR: expected a `Fn<()>` closure, found `unsafe fn() -> i32` + //~| ERROR: type mismatch resolving ` i32 as FnOnce<()>>::Output == i32` + require_fn(g); + require_fn(g as extern "C" fn() -> i32); + //~^ ERROR: expected a `Fn<()>` closure, found `extern "C" fn() -> i32` + //~| ERROR: type mismatch resolving ` i32 as FnOnce<()>>::Output == i32` + require_fn(h); } diff --git a/tests/ui/traits/new-solver/fn-trait.stderr b/tests/ui/traits/new-solver/fn-trait.stderr new file mode 100644 index 000000000000..01f1b64be20c --- /dev/null +++ b/tests/ui/traits/new-solver/fn-trait.stderr @@ -0,0 +1,64 @@ +error[E0277]: expected a `Fn<()>` closure, found `unsafe fn() -> i32` + --> $DIR/fn-trait.rs:20:16 + | +LL | require_fn(f as unsafe fn() -> i32); + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` + | | + | required by a bound introduced by this call + | + = help: the trait `Fn<()>` is not implemented for `unsafe fn() -> i32` + = note: wrap the `unsafe fn() -> i32` in a closure with no arguments: `|| { /* code */ }` +note: required by a bound in `require_fn` + --> $DIR/fn-trait.rs:3:23 + | +LL | fn require_fn(_: impl Fn() -> i32) {} + | ^^^^^^^^^^^ required by this bound in `require_fn` + +error[E0271]: type mismatch resolving ` i32 as FnOnce<()>>::Output == i32` + --> $DIR/fn-trait.rs:20:16 + | +LL | require_fn(f as unsafe fn() -> i32); + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^ types differ + | | + | required by a bound introduced by this call + | +note: required by a bound in `require_fn` + --> $DIR/fn-trait.rs:3:31 + | +LL | fn require_fn(_: impl Fn() -> i32) {} + | ^^^ required by this bound in `require_fn` + +error[E0277]: expected a `Fn<()>` closure, found `extern "C" fn() -> i32` + --> $DIR/fn-trait.rs:24:16 + | +LL | require_fn(g as extern "C" fn() -> i32); + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `extern "C" fn() -> i32` + | | + | required by a bound introduced by this call + | + = help: the trait `Fn<()>` is not implemented for `extern "C" fn() -> i32` + = note: wrap the `extern "C" fn() -> i32` in a closure with no arguments: `|| { /* code */ }` +note: required by a bound in `require_fn` + --> $DIR/fn-trait.rs:3:23 + | +LL | fn require_fn(_: impl Fn() -> i32) {} + | ^^^^^^^^^^^ required by this bound in `require_fn` + +error[E0271]: type mismatch resolving ` i32 as FnOnce<()>>::Output == i32` + --> $DIR/fn-trait.rs:24:16 + | +LL | require_fn(g as extern "C" fn() -> i32); + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ + | | + | required by a bound introduced by this call + | +note: required by a bound in `require_fn` + --> $DIR/fn-trait.rs:3:31 + | +LL | fn require_fn(_: impl Fn() -> i32) {} + | ^^^ required by this bound in `require_fn` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0271, E0277. +For more information about an error, try `rustc --explain E0271`. From 91d913168cf357d4c7ba9b91d4656065477e3c2c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 21 Mar 2023 11:38:13 +0000 Subject: [PATCH 57/70] Deduplicate fn trait compatibility checks --- compiler/rustc_middle/src/ty/sty.rs | 14 +++++++++- .../solve/trait_goals/structural_traits.rs | 9 +------ .../src/traits/select/candidate_assembly.rs | 27 +++++-------------- 3 files changed, 21 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 4c606b939b25..2a0536a1af72 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -23,7 +23,7 @@ use rustc_macros::HashStable; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; use rustc_target::abi::VariantIdx; -use rustc_target::spec::abi; +use rustc_target::spec::abi::{self, Abi}; use std::borrow::Cow; use std::cmp::Ordering; use std::fmt; @@ -1403,6 +1403,18 @@ impl<'tcx> PolyFnSig<'tcx> { pub fn abi(&self) -> abi::Abi { self.skip_binder().abi } + + pub fn is_fn_trait_compatible(&self) -> bool { + matches!( + self.skip_binder(), + ty::FnSig { + unsafety: rustc_hir::Unsafety::Normal, + abi: Abi::Rust, + c_variadic: false, + .. + } + ) + } } pub type CanonicalPolyFnSig<'tcx> = Canonical<'tcx, Binder<'tcx, FnSig<'tcx>>>; diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs index 51a1a88f8e77..ecebe3fbcfb5 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs @@ -2,7 +2,6 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::{def_id::DefId, Movability, Mutability}; use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable}; -use rustc_target::spec::abi::Abi; use crate::solve::EvalCtxt; @@ -197,13 +196,7 @@ pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>( )), // keep this in sync with assemble_fn_pointer_candidates until the old solver is removed. ty::FnPtr(sig) => { - if let ty::FnSig { - unsafety: rustc_hir::Unsafety::Normal, - abi: Abi::Rust, - c_variadic: false, - .. - } = sig.skip_binder() - { + if sig.is_fn_trait_compatible() { Ok(Some(sig.map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())))) } else { Err(NoSolution) diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 2b3f003353c6..e06eff34df21 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -11,7 +11,6 @@ use rustc_infer::traits::ObligationCause; use rustc_infer::traits::{Obligation, SelectionError, TraitObligation}; use rustc_middle::ty::fast_reject::TreatProjections; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; -use rustc_target::spec::abi::Abi; use crate::traits; use crate::traits::query::evaluate_obligation::InferCtxtExt; @@ -302,31 +301,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates.ambiguous = true; // Could wind up being a fn() type. } // Provide an impl, but only for suitable `fn` pointers. - ty::FnPtr(_) => { - if let ty::FnSig { - unsafety: hir::Unsafety::Normal, - abi: Abi::Rust, - c_variadic: false, - .. - } = self_ty.fn_sig(self.tcx()).skip_binder() - { + ty::FnPtr(sig) => { + if sig.is_fn_trait_compatible() { candidates.vec.push(FnPointerCandidate { is_const: false }); } } // Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396). ty::FnDef(def_id, _) => { - if let ty::FnSig { - unsafety: hir::Unsafety::Normal, - abi: Abi::Rust, - c_variadic: false, - .. - } = self_ty.fn_sig(self.tcx()).skip_binder() + if self.tcx().fn_sig(def_id).skip_binder().is_fn_trait_compatible() + && self.tcx().codegen_fn_attrs(def_id).target_features.is_empty() { - if self.tcx().codegen_fn_attrs(def_id).target_features.is_empty() { - candidates - .vec - .push(FnPointerCandidate { is_const: self.tcx().is_const_fn(def_id) }); - } + candidates + .vec + .push(FnPointerCandidate { is_const: self.tcx().is_const_fn(def_id) }); } } _ => {} From a00413f680d52b6e4ba1c1075e1310513a1d061c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 21 Mar 2023 11:44:36 +0000 Subject: [PATCH 58/70] Also check function items' signatures for Fn* trait compatibility --- .../solve/trait_goals/structural_traits.rs | 19 ++++-- tests/ui/traits/new-solver/fn-trait.rs | 4 ++ tests/ui/traits/new-solver/fn-trait.stderr | 66 ++++++++++++++++++- 3 files changed, 81 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs index ecebe3fbcfb5..ded14a87f2ce 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs @@ -189,11 +189,20 @@ pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>( goal_kind: ty::ClosureKind, ) -> Result, Ty<'tcx>)>>, NoSolution> { match *self_ty.kind() { - ty::FnDef(def_id, substs) => Ok(Some( - tcx.fn_sig(def_id) - .subst(tcx, substs) - .map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())), - )), + // keep this in sync with assemble_fn_pointer_candidates until the old solver is removed. + ty::FnDef(def_id, substs) => { + let sig = tcx.fn_sig(def_id); + if sig.skip_binder().is_fn_trait_compatible() + && tcx.codegen_fn_attrs(def_id).target_features.is_empty() + { + Ok(Some( + sig.subst(tcx, substs) + .map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())), + )) + } else { + Err(NoSolution) + } + } // keep this in sync with assemble_fn_pointer_candidates until the old solver is removed. ty::FnPtr(sig) => { if sig.is_fn_trait_compatible() { diff --git a/tests/ui/traits/new-solver/fn-trait.rs b/tests/ui/traits/new-solver/fn-trait.rs index 8967858a8ba5..0599e51d7ad8 100644 --- a/tests/ui/traits/new-solver/fn-trait.rs +++ b/tests/ui/traits/new-solver/fn-trait.rs @@ -21,8 +21,12 @@ fn main() { //~^ ERROR: expected a `Fn<()>` closure, found `unsafe fn() -> i32` //~| ERROR: type mismatch resolving ` i32 as FnOnce<()>>::Output == i32` require_fn(g); + //~^ ERROR: expected a `Fn<()>` closure, found `extern "C" fn() -> i32 {g}` + //~| ERROR: type mismatch resolving ` i32 {g} as FnOnce<()>>::Output == i32` require_fn(g as extern "C" fn() -> i32); //~^ ERROR: expected a `Fn<()>` closure, found `extern "C" fn() -> i32` //~| ERROR: type mismatch resolving ` i32 as FnOnce<()>>::Output == i32` require_fn(h); + //~^ ERROR: expected a `Fn<()>` closure, found `unsafe fn() -> i32 {h}` + //~| ERROR: type mismatch resolving ` i32 {h} as FnOnce<()>>::Output == i32` } diff --git a/tests/ui/traits/new-solver/fn-trait.stderr b/tests/ui/traits/new-solver/fn-trait.stderr index 01f1b64be20c..d52bcaf25b87 100644 --- a/tests/ui/traits/new-solver/fn-trait.stderr +++ b/tests/ui/traits/new-solver/fn-trait.stderr @@ -28,8 +28,38 @@ note: required by a bound in `require_fn` LL | fn require_fn(_: impl Fn() -> i32) {} | ^^^ required by this bound in `require_fn` +error[E0277]: expected a `Fn<()>` closure, found `extern "C" fn() -> i32 {g}` + --> $DIR/fn-trait.rs:23:16 + | +LL | require_fn(g); + | ---------- ^ expected an `Fn<()>` closure, found `extern "C" fn() -> i32 {g}` + | | + | required by a bound introduced by this call + | + = help: the trait `Fn<()>` is not implemented for fn item `extern "C" fn() -> i32 {g}` + = note: wrap the `extern "C" fn() -> i32 {g}` in a closure with no arguments: `|| { /* code */ }` +note: required by a bound in `require_fn` + --> $DIR/fn-trait.rs:3:23 + | +LL | fn require_fn(_: impl Fn() -> i32) {} + | ^^^^^^^^^^^ required by this bound in `require_fn` + +error[E0271]: type mismatch resolving ` i32 {g} as FnOnce<()>>::Output == i32` + --> $DIR/fn-trait.rs:23:16 + | +LL | require_fn(g); + | ---------- ^ types differ + | | + | required by a bound introduced by this call + | +note: required by a bound in `require_fn` + --> $DIR/fn-trait.rs:3:31 + | +LL | fn require_fn(_: impl Fn() -> i32) {} + | ^^^ required by this bound in `require_fn` + error[E0277]: expected a `Fn<()>` closure, found `extern "C" fn() -> i32` - --> $DIR/fn-trait.rs:24:16 + --> $DIR/fn-trait.rs:26:16 | LL | require_fn(g as extern "C" fn() -> i32); | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `extern "C" fn() -> i32` @@ -45,7 +75,7 @@ LL | fn require_fn(_: impl Fn() -> i32) {} | ^^^^^^^^^^^ required by this bound in `require_fn` error[E0271]: type mismatch resolving ` i32 as FnOnce<()>>::Output == i32` - --> $DIR/fn-trait.rs:24:16 + --> $DIR/fn-trait.rs:26:16 | LL | require_fn(g as extern "C" fn() -> i32); | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ @@ -58,7 +88,37 @@ note: required by a bound in `require_fn` LL | fn require_fn(_: impl Fn() -> i32) {} | ^^^ required by this bound in `require_fn` -error: aborting due to 4 previous errors +error[E0277]: expected a `Fn<()>` closure, found `unsafe fn() -> i32 {h}` + --> $DIR/fn-trait.rs:29:16 + | +LL | require_fn(h); + | ---------- ^ call the function in a closure: `|| unsafe { /* code */ }` + | | + | required by a bound introduced by this call + | + = help: the trait `Fn<()>` is not implemented for fn item `unsafe fn() -> i32 {h}` + = note: wrap the `unsafe fn() -> i32 {h}` in a closure with no arguments: `|| { /* code */ }` +note: required by a bound in `require_fn` + --> $DIR/fn-trait.rs:3:23 + | +LL | fn require_fn(_: impl Fn() -> i32) {} + | ^^^^^^^^^^^ required by this bound in `require_fn` + +error[E0271]: type mismatch resolving ` i32 {h} as FnOnce<()>>::Output == i32` + --> $DIR/fn-trait.rs:29:16 + | +LL | require_fn(h); + | ---------- ^ types differ + | | + | required by a bound introduced by this call + | +note: required by a bound in `require_fn` + --> $DIR/fn-trait.rs:3:31 + | +LL | fn require_fn(_: impl Fn() -> i32) {} + | ^^^ required by this bound in `require_fn` + +error: aborting due to 8 previous errors Some errors have detailed explanations: E0271, E0277. For more information about an error, try `rustc --explain E0271`. From aacbd8671b316a0fb79af71121d723ce25e703d2 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Tue, 21 Mar 2023 15:07:05 +0100 Subject: [PATCH 59/70] handle tests timing out --- src/bootstrap/render_tests.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bootstrap/render_tests.rs b/src/bootstrap/render_tests.rs index fd78e449a49b..af2370d439e6 100644 --- a/src/bootstrap/render_tests.rs +++ b/src/bootstrap/render_tests.rs @@ -260,6 +260,9 @@ impl<'a> Renderer<'a> { self.render_test_outcome(Outcome::Failed, &outcome); self.failures.push(outcome); } + Message::Test(TestMessage::Timeout { name }) => { + println!("test {name} has been running for a long time"); + } Message::Test(TestMessage::Started) => {} // Not useful } } @@ -353,6 +356,7 @@ enum TestMessage { Ok(TestOutcome), Failed(TestOutcome), Ignored(TestOutcome), + Timeout { name: String }, Started, } From 2eb1c08e433aadf2362a65f2ef1387670a6d34cf Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 13 Mar 2023 18:54:05 +0000 Subject: [PATCH 60/70] Use local key in providers --- .../src/back/symbol_export.rs | 12 +- .../rustc_codegen_ssa/src/codegen_attrs.rs | 3 +- .../src/const_eval/fn_queries.rs | 3 +- .../src/transform/check_consts/check.rs | 2 +- .../check_consts/post_drop_elaboration.rs | 2 +- compiler/rustc_hir/src/hir_id.rs | 6 + .../rustc_hir_analysis/src/check/check.rs | 2 +- .../src/check/compare_impl_item.rs | 7 +- compiler/rustc_hir_analysis/src/check/mod.rs | 4 +- .../src/coherence/builtin.rs | 5 +- .../src/coherence/inherent_impls.rs | 8 +- compiler/rustc_hir_analysis/src/collect.rs | 61 ++-- .../src/collect/generics_of.rs | 16 +- .../src/collect/item_bounds.rs | 23 +- .../src/collect/predicates_of.rs | 28 +- .../src/collect/resolve_bound_vars.rs | 3 +- .../rustc_hir_analysis/src/collect/type_of.rs | 7 +- .../rustc_hir_analysis/src/outlives/mod.rs | 9 +- .../rustc_hir_analysis/src/outlives/test.rs | 2 +- .../rustc_hir_analysis/src/variance/mod.rs | 6 +- .../rustc_hir_analysis/src/variance/test.rs | 2 +- compiler/rustc_hir_typeck/src/lib.rs | 2 +- compiler/rustc_hir_typeck/src/upvar.rs | 2 +- compiler/rustc_hir_typeck/src/writeback.rs | 3 +- .../src/persist/dirty_clean.rs | 2 +- .../src/infer/error_reporting/suggest.rs | 6 +- compiler/rustc_lint/src/builtin.rs | 7 +- compiler/rustc_lint/src/internal.rs | 2 +- compiler/rustc_lint/src/nonstandard_style.rs | 6 +- .../src/rmeta/decoder/cstore_impl.rs | 23 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 12 +- compiler/rustc_middle/src/hir/map/mod.rs | 5 +- compiler/rustc_middle/src/hir/mod.rs | 14 +- compiler/rustc_middle/src/query/keys.rs | 311 ++++++++++++------ compiler/rustc_middle/src/ty/consts.rs | 6 +- compiler/rustc_middle/src/ty/context.rs | 15 +- compiler/rustc_middle/src/ty/instance.rs | 6 +- compiler/rustc_middle/src/ty/mod.rs | 14 +- compiler/rustc_middle/src/ty/query.rs | 31 +- compiler/rustc_middle/src/ty/util.rs | 7 +- .../src/deduce_param_attrs.rs | 11 +- .../src/ffi_unwind_calls.rs | 6 +- compiler/rustc_mir_transform/src/generator.rs | 5 +- compiler/rustc_mir_transform/src/lib.rs | 15 +- compiler/rustc_passes/src/check_const.rs | 4 +- compiler/rustc_passes/src/dead.rs | 4 +- .../rustc_passes/src/debugger_visualizer.rs | 6 +- compiler/rustc_passes/src/diagnostic_items.rs | 6 +- compiler/rustc_passes/src/layout_test.rs | 2 +- compiler/rustc_passes/src/liveness.rs | 2 +- compiler/rustc_passes/src/naked_functions.rs | 4 +- compiler/rustc_passes/src/stability.rs | 12 +- compiler/rustc_privacy/src/lib.rs | 6 +- compiler/rustc_query_impl/src/plumbing.rs | 18 +- compiler/rustc_symbol_mangling/src/test.rs | 4 +- compiler/rustc_ty_utils/src/assoc.rs | 25 +- compiler/rustc_ty_utils/src/consts.rs | 1 - .../rustc_ty_utils/src/representability.rs | 4 +- compiler/rustc_ty_utils/src/ty.rs | 14 +- .../clippy_lints/src/cognitive_complexity.rs | 2 +- .../clippy_lints/src/derivable_impls.rs | 2 +- src/tools/clippy/clippy_lints/src/derive.rs | 2 +- .../clippy_lints/src/functions/must_use.rs | 6 +- .../clippy_lints/src/partialeq_ne_impl.rs | 2 +- src/tools/miri/src/bin/miri.rs | 5 +- 65 files changed, 458 insertions(+), 395 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 18d17b1a0137..3380864fbb2a 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -41,9 +41,7 @@ pub fn crates_export_threshold(crate_types: &[CrateType]) -> SymbolExportLevel { } } -fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap { - assert_eq!(cnum, LOCAL_CRATE); - +fn reachable_non_generics_provider(tcx: TyCtxt<'_>, (): ()) -> DefIdMap { if !tcx.sess.opts.output_types.should_codegen() { return Default::default(); } @@ -154,10 +152,10 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap< reachable_non_generics } -fn is_reachable_non_generic_provider_local(tcx: TyCtxt<'_>, def_id: DefId) -> bool { +fn is_reachable_non_generic_provider_local(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { let export_threshold = threshold(tcx); - if let Some(&info) = tcx.reachable_non_generics(def_id.krate).get(&def_id) { + if let Some(&info) = tcx.reachable_non_generics(LOCAL_CRATE).get(&def_id.to_def_id()) { info.level.is_below_threshold(export_threshold) } else { false @@ -170,10 +168,8 @@ fn is_reachable_non_generic_provider_extern(tcx: TyCtxt<'_>, def_id: DefId) -> b fn exported_symbols_provider_local( tcx: TyCtxt<'_>, - cnum: CrateNum, + (): (), ) -> &[(ExportedSymbol<'_>, SymbolExportInfo)] { - assert_eq!(cnum, LOCAL_CRATE); - if !tcx.sess.opts.output_types.should_codegen() { return &[]; } diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index f9bb8359208e..037b07dec629 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -43,7 +43,7 @@ fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage { } } -fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { +fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { if cfg!(debug_assertions) { let def_kind = tcx.def_kind(did); assert!( @@ -52,7 +52,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { ); } - let did = did.expect_local(); let attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(did)); let mut codegen_fn_attrs = CodegenFnAttrs::new(); if tcx.should_inherit_track_caller(did) { diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs index 6dcfdc147908..088a824fd8f1 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -32,8 +32,7 @@ pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { /// it is a trait impl/function, return if it has a `const` modifier. If it is an intrinsic, /// report whether said intrinsic has a `rustc_const_{un,}stable` attribute. Otherwise, return /// `Constness::NotConst`. -fn constness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Constness { - let def_id = def_id.expect_local(); +fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness { let node = tcx.hir().get_by_def_id(def_id); match node { diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index f775b4796678..0d9cd78fe12a 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -246,7 +246,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { self.check_local_or_return_ty(return_ty.skip_binder(), RETURN_PLACE); } - if !tcx.has_attr(def_id.to_def_id(), sym::rustc_do_not_const_check) { + if !tcx.has_attr(def_id, sym::rustc_do_not_const_check) { self.visit_body(&body); } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs index 43806035a44a..f01ab4c5d611 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs @@ -30,7 +30,7 @@ pub fn check_live_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>) { return; } - if tcx.has_attr(def_id.to_def_id(), sym::rustc_do_not_const_check) { + if tcx.has_attr(def_id, sym::rustc_do_not_const_check) { return; } diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs index 404abe2b068c..37ac37231619 100644 --- a/compiler/rustc_hir/src/hir_id.rs +++ b/compiler/rustc_hir/src/hir_id.rs @@ -22,6 +22,12 @@ impl From for HirId { } } +impl From for DefId { + fn from(value: OwnerId) -> Self { + value.to_def_id() + } +} + impl OwnerId { #[inline] pub fn to_def_id(self) -> DefId { diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 872fec3954b2..43703e1e4693 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1161,7 +1161,7 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) { def.destructor(tcx); // force the destructor to be evaluated if def.variants().is_empty() { - if let Some(attr) = tcx.get_attrs(def_id.to_def_id(), sym::repr).next() { + if let Some(attr) = tcx.get_attrs(def_id, sym::repr).next() { struct_span_err!( tcx.sess, attr.span, diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 32b6aeed5f8c..49665525967f 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -583,13 +583,13 @@ fn compare_asyncness<'tcx>( #[instrument(skip(tcx), level = "debug", ret)] pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( tcx: TyCtxt<'tcx>, - def_id: DefId, + impl_m_def_id: LocalDefId, ) -> Result<&'tcx FxHashMap>, ErrorGuaranteed> { - let impl_m = tcx.opt_associated_item(def_id).unwrap(); + let impl_m = tcx.opt_associated_item(impl_m_def_id.to_def_id()).unwrap(); let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap(); let impl_trait_ref = tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap().subst_identity(); - let param_env = tcx.param_env(def_id); + let param_env = tcx.param_env(impl_m_def_id); // First, check a few of the same things as `compare_impl_method`, // just so we don't ICE during substitution later. @@ -599,7 +599,6 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( let trait_to_impl_substs = impl_trait_ref.substs; - let impl_m_def_id = impl_m.def_id.expect_local(); let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m_def_id); let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span(); let cause = ObligationCause::new( diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 9acfc1b3d292..1e2b37bd50c5 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -109,8 +109,8 @@ pub fn provide(providers: &mut Providers) { }; } -fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option { - tcx.calculate_dtor(def_id, dropck::check_drop_impl) +fn adt_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { + tcx.calculate_dtor(def_id.to_def_id(), dropck::check_drop_impl) } /// Given a `DefId` for an opaque type in return position, find its parent item's return diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 0e1cf3e6c6a7..d5e19d913e75 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -368,11 +368,8 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef } } -pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedInfo { +pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> CoerceUnsizedInfo { debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did); - - // this provider should only get invoked for local def-ids - let impl_did = impl_did.expect_local(); let span = tcx.def_span(impl_did); let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)); diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index 07a33bcbb509..d4dfe455b29a 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -10,7 +10,7 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::DefKind; -use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams, TreatProjections}; use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt}; use rustc_span::symbol::sym; @@ -24,7 +24,7 @@ pub fn crate_inherent_impls(tcx: TyCtxt<'_>, (): ()) -> CrateInherentImpls { collect.impls_map } -pub fn crate_incoherent_impls(tcx: TyCtxt<'_>, (_, simp): (CrateNum, SimplifiedType)) -> &[DefId] { +pub fn crate_incoherent_impls(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId] { let crate_map = tcx.crate_inherent_impls(()); tcx.arena.alloc_from_iter( crate_map.incoherent_impls.get(&simp).unwrap_or(&Vec::new()).iter().map(|d| d.to_def_id()), @@ -32,9 +32,7 @@ pub fn crate_incoherent_impls(tcx: TyCtxt<'_>, (_, simp): (CrateNum, SimplifiedT } /// On-demand query: yields a vector of the inherent impls for a specific type. -pub fn inherent_impls(tcx: TyCtxt<'_>, ty_def_id: DefId) -> &[DefId] { - let ty_def_id = ty_def_id.expect_local(); - +pub fn inherent_impls(tcx: TyCtxt<'_>, ty_def_id: LocalDefId) -> &[DefId] { let crate_map = tcx.crate_inherent_impls(()); match crate_map.inherent_impls.get(&ty_def_id) { Some(v) => &v[..], diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 604d54cafb53..8a1306aae083 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -839,17 +839,15 @@ fn convert_variant( adt_kind, parent_did.to_def_id(), recovered, - adt_kind == AdtKind::Struct && tcx.has_attr(parent_did.to_def_id(), sym::non_exhaustive) - || variant_did.map_or(false, |variant_did| { - tcx.has_attr(variant_did.to_def_id(), sym::non_exhaustive) - }), + adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, sym::non_exhaustive) + || variant_did + .map_or(false, |variant_did| tcx.has_attr(variant_did, sym::non_exhaustive)), ) } -fn adt_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtDef<'_> { +fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> { use rustc_hir::*; - let def_id = def_id.expect_local(); let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let Node::Item(item) = tcx.hir().get(hir_id) else { bug!(); @@ -908,8 +906,8 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtDef<'_> { tcx.mk_adt_def(def_id.to_def_id(), kind, variants, repr) } -fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef { - let item = tcx.hir().expect_item(def_id.expect_local()); +fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { + let item = tcx.hir().expect_item(def_id); let (is_auto, unsafety, items) = match item.kind { hir::ItemKind::Trait(is_auto, unsafety, .., items) => { @@ -1036,7 +1034,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef { }); ty::TraitDef { - def_id, + def_id: def_id.to_def_id(), unsafety, paren_sugar, has_auto_impl: is_auto, @@ -1091,11 +1089,10 @@ pub fn get_infer_ret_ty<'hir>(output: &'hir hir::FnRetTy<'hir>) -> Option<&'hir } #[instrument(level = "debug", skip(tcx))] -fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder> { +fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder> { use rustc_hir::Node::*; use rustc_hir::*; - let def_id = def_id.expect_local(); let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let icx = ItemCtxt::new(tcx, def_id.to_def_id()); @@ -1338,9 +1335,12 @@ fn suggest_impl_trait<'tcx>( None } -fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option>> { - let icx = ItemCtxt::new(tcx, def_id); - let impl_ = tcx.hir().expect_item(def_id.expect_local()).expect_impl(); +fn impl_trait_ref( + tcx: TyCtxt<'_>, + def_id: LocalDefId, +) -> Option>> { + let icx = ItemCtxt::new(tcx, def_id.to_def_id()); + let impl_ = tcx.hir().expect_item(def_id).expect_impl(); impl_ .of_trait .as_ref() @@ -1380,9 +1380,9 @@ fn check_impl_constness( } } -fn impl_polarity(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ImplPolarity { +fn impl_polarity(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::ImplPolarity { let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl); - let item = tcx.hir().expect_item(def_id.expect_local()); + let item = tcx.hir().expect_item(def_id); match &item.kind { hir::ItemKind::Impl(hir::Impl { polarity: hir::ImplPolarity::Negative(span), @@ -1515,31 +1515,28 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( fty } -fn is_foreign_item(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - match tcx.hir().get_if_local(def_id) { - Some(Node::ForeignItem(..)) => true, - Some(_) => false, - _ => bug!("is_foreign_item applied to non-local def-id {:?}", def_id), +fn is_foreign_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { + match tcx.hir().get_by_def_id(def_id) { + Node::ForeignItem(..) => true, + _ => false, } } -fn generator_kind(tcx: TyCtxt<'_>, def_id: DefId) -> Option { - match tcx.hir().get_if_local(def_id) { - Some(Node::Expr(&rustc_hir::Expr { +fn generator_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { + match tcx.hir().get_by_def_id(def_id) { + Node::Expr(&rustc_hir::Expr { kind: rustc_hir::ExprKind::Closure(&rustc_hir::Closure { body, .. }), .. - })) => tcx.hir().body(body).generator_kind(), - Some(_) => None, - _ => bug!("generator_kind applied to non-local def-id {:?}", def_id), + }) => tcx.hir().body(body).generator_kind(), + _ => None, } } -fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { - match tcx.hir().get_if_local(def_id) { - Some(Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(opaque), .. })) => { +fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool { + match tcx.hir().get_by_def_id(def_id) { + Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(opaque), .. }) => { matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias) } - Some(_) => bug!("tried getting opaque_ty_origin for non-opaque: {:?}", def_id), - _ => bug!("tried getting opaque_ty_origin for non-local def-id {:?}", def_id), + _ => bug!("tried getting opaque_ty_origin for non-opaque: {:?}", def_id), } } diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 127d4fa908bb..119933697a16 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -5,16 +5,16 @@ use hir::{ }; use rustc_hir as hir; use rustc_hir::def::DefKind; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint; use rustc_span::symbol::{kw, Symbol}; use rustc_span::Span; -pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { +pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { use rustc_hir::*; - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let node = tcx.hir().get(hir_id); let parent_def_id = match node { @@ -121,7 +121,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { Some(parent_def_id.to_def_id()) } Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => { - Some(tcx.typeck_root_def_id(def_id)) + Some(tcx.typeck_root_def_id(def_id.to_def_id())) } // Exclude `GlobalAsm` here which cannot have generics. Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) @@ -140,7 +140,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { } } Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => { - Some(tcx.typeck_root_def_id(def_id)) + Some(tcx.typeck_root_def_id(def_id.to_def_id())) } Node::Item(item) => match item.kind { ItemKind::OpaqueTy(hir::OpaqueTy { @@ -189,7 +189,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { let opt_self = Some(ty::GenericParamDef { index: 0, name: kw::SelfUpper, - def_id, + def_id: def_id.to_def_id(), pure_wrt_drop: false, kind: ty::GenericParamDefKind::Type { has_default: false, @@ -326,7 +326,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { params.extend(dummy_args.iter().map(|&arg| ty::GenericParamDef { index: next_index(), name: Symbol::intern(arg), - def_id, + def_id: def_id.to_def_id(), pure_wrt_drop: false, kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false }, })); @@ -339,7 +339,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { params.push(ty::GenericParamDef { index: next_index(), name: Symbol::intern(""), - def_id, + def_id: def_id.to_def_id(), pure_wrt_drop: false, kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false }, }); diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index df0258ff7a36..3f4125954acb 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -4,7 +4,7 @@ use rustc_hir as hir; use rustc_infer::traits::util; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::def_id::DefId; +use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::Span; /// For associated types we include both bounds written on the type @@ -74,9 +74,9 @@ fn opaque_type_bounds<'tcx>( pub(super) fn explicit_item_bounds( tcx: TyCtxt<'_>, - def_id: DefId, + def_id: LocalDefId, ) -> &'_ [(ty::Predicate<'_>, Span)] { - match tcx.opt_rpitit_info(def_id) { + match tcx.opt_rpitit_info(def_id.to_def_id()) { // RPITIT's bounds are the same as opaque type bounds, but with // a projection self type. Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => { @@ -86,7 +86,10 @@ pub(super) fn explicit_item_bounds( tcx, opaque_def_id, opaque_ty.bounds, - tcx.mk_projection(def_id, ty::InternalSubsts::identity_for_item(tcx, def_id)), + tcx.mk_projection( + def_id.to_def_id(), + ty::InternalSubsts::identity_for_item(tcx, def_id.to_def_id()), + ), item.span, ); } @@ -95,25 +98,25 @@ pub(super) fn explicit_item_bounds( None => {} } - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); match tcx.hir().get(hir_id) { hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(bounds, _), span, .. - }) => associated_type_bounds(tcx, def_id, bounds, *span), + }) => associated_type_bounds(tcx, def_id.to_def_id(), bounds, *span), hir::Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, in_trait, .. }), span, .. }) => { - let substs = InternalSubsts::identity_for_item(tcx, def_id); + let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); let item_ty = if *in_trait && !tcx.lower_impl_trait_in_trait_to_assoc_ty() { - tcx.mk_projection(def_id, substs) + tcx.mk_projection(def_id.to_def_id(), substs) } else { - tcx.mk_opaque(def_id, substs) + tcx.mk_opaque(def_id.to_def_id(), substs) }; - opaque_type_bounds(tcx, def_id, bounds, item_ty, *span) + opaque_type_bounds(tcx, def_id.to_def_id(), bounds, item_ty, *span) } _ => bug!("item_bounds called on {:?}", def_id), } diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 2badd66e346f..c1d61b1efc23 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -62,16 +62,17 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic /// Returns a list of user-specified type predicates for the definition with ID `def_id`. /// N.B., this does not include any implied/inferred constraints. #[instrument(level = "trace", skip(tcx), ret)] -fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> { +fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::GenericPredicates<'_> { use rustc_hir::*; - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let node = tcx.hir().get(hir_id); let mut is_trait = None; let mut is_default_impl_trait = None; - let icx = ItemCtxt::new(tcx, def_id); + // FIXME: Should ItemCtxt take a LocalDefId? + let icx = ItemCtxt::new(tcx, def_id.to_def_id()); const NO_GENERICS: &hir::Generics<'_> = hir::Generics::empty(); @@ -99,7 +100,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP | ItemKind::Union(_, generics) => generics, ItemKind::Trait(_, _, generics, ..) | ItemKind::TraitAlias(generics, _) => { - is_trait = Some(ty::TraitRef::identity(tcx, def_id)); + is_trait = Some(ty::TraitRef::identity(tcx, def_id.to_def_id())); generics } ItemKind::OpaqueTy(OpaqueTy { generics, .. }) => generics, @@ -253,7 +254,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP } if tcx.features().generic_const_exprs { - predicates.extend(const_evaluatable_predicates_of(tcx, def_id.expect_local())); + predicates.extend(const_evaluatable_predicates_of(tcx, def_id)); } let mut predicates: Vec<_> = predicates.into_iter().collect(); @@ -392,19 +393,19 @@ pub(super) fn trait_explicit_predicates_and_bounds( def_id: LocalDefId, ) -> ty::GenericPredicates<'_> { assert_eq!(tcx.def_kind(def_id), DefKind::Trait); - gather_explicit_predicates_of(tcx, def_id.to_def_id()) + gather_explicit_predicates_of(tcx, def_id) } pub(super) fn explicit_predicates_of<'tcx>( tcx: TyCtxt<'tcx>, - def_id: DefId, + def_id: LocalDefId, ) -> ty::GenericPredicates<'tcx> { let def_kind = tcx.def_kind(def_id); if let DefKind::Trait = def_kind { // Remove bounds on associated types from the predicates, they will be // returned by `explicit_item_bounds`. - let predicates_and_bounds = tcx.trait_explicit_predicates_and_bounds(def_id.expect_local()); - let trait_identity_substs = InternalSubsts::identity_for_item(tcx, def_id); + let predicates_and_bounds = tcx.trait_explicit_predicates_and_bounds(def_id); + let trait_identity_substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); let is_assoc_item_ty = |ty: Ty<'tcx>| { // For a predicate from a where clause to become a bound on an @@ -418,7 +419,8 @@ pub(super) fn explicit_predicates_of<'tcx>( // supertrait). if let ty::Alias(ty::Projection, projection) = ty.kind() { projection.substs == trait_identity_substs - && tcx.associated_item(projection.def_id).container_id(tcx) == def_id + && tcx.associated_item(projection.def_id).container_id(tcx) + == def_id.to_def_id() } else { false } @@ -449,7 +451,7 @@ pub(super) fn explicit_predicates_of<'tcx>( } } else { if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let parent_def_id = tcx.hir().get_parent_item(hir_id); if let Some(defaulted_param_def_id) = @@ -537,9 +539,9 @@ pub(super) fn explicit_predicates_of<'tcx>( /// the transitive super-predicates are converted. pub(super) fn super_predicates_of( tcx: TyCtxt<'_>, - trait_def_id: DefId, + trait_def_id: LocalDefId, ) -> ty::GenericPredicates<'_> { - tcx.super_predicates_that_define_assoc_type((trait_def_id, None)) + tcx.super_predicates_that_define_assoc_type((trait_def_id.to_def_id(), None)) } /// Ensures that the super-predicates of the trait with a `DefId` diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 465ae047de37..f1769415797c 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1051,9 +1051,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { } } -fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: DefId) -> ObjectLifetimeDefault { +fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: LocalDefId) -> ObjectLifetimeDefault { debug_assert_eq!(tcx.def_kind(param_def_id), DefKind::TyParam); - let param_def_id = param_def_id.expect_local(); let hir::Node::GenericParam(param) = tcx.hir().get_by_def_id(param_def_id) else { bug!("expected GenericParam for object_lifetime_default"); }; diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 7ab7a8c4c1b4..91eb63bc9f2d 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -244,11 +244,13 @@ fn get_path_containing_arg_in_pat<'hir>( arg_path } -pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder> { +pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder> { // If we are computing `type_of` the synthesized associated type for an RPITIT in the impl // side, use `collect_return_position_impl_trait_in_trait_tys` to infer the value of the // associated type in the impl. - if let Some(ImplTraitInTraitData::Impl { fn_def_id, .. }) = tcx.opt_rpitit_info(def_id) { + if let Some(ImplTraitInTraitData::Impl { fn_def_id, .. }) = + tcx.opt_rpitit_info(def_id.to_def_id()) + { match tcx.collect_return_position_impl_trait_in_trait_tys(fn_def_id) { Ok(map) => { let assoc_item = tcx.associated_item(def_id); @@ -263,7 +265,6 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder> } } - let def_id = def_id.expect_local(); use rustc_hir::*; let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); diff --git a/compiler/rustc_hir_analysis/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs index 81fe32000d30..da72d2584e33 100644 --- a/compiler/rustc_hir_analysis/src/outlives/mod.rs +++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs @@ -1,6 +1,6 @@ use hir::Node; use rustc_hir as hir; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, CratePredicatesMap, TyCtxt}; @@ -17,8 +17,8 @@ pub fn provide(providers: &mut Providers) { *providers = Providers { inferred_outlives_of, inferred_outlives_crate, ..*providers }; } -fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[(ty::Clause<'_>, Span)] { - let id = tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()); +fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clause<'_>, Span)] { + let id = tcx.hir().local_def_id_to_hir_id(item_def_id); if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst) && tcx.lazy_normalization() { @@ -45,7 +45,8 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[(ty::Clause<'_ hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) | hir::ItemKind::Union(..) => { let crate_map = tcx.inferred_outlives_crate(()); - let predicates = crate_map.predicates.get(&item_def_id).copied().unwrap_or(&[]); + let predicates = + crate_map.predicates.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]); if tcx.has_attr(item_def_id, sym::rustc_outlives) { let mut pred: Vec = predicates diff --git a/compiler/rustc_hir_analysis/src/outlives/test.rs b/compiler/rustc_hir_analysis/src/outlives/test.rs index fa2ac56593bc..60f8e246ad66 100644 --- a/compiler/rustc_hir_analysis/src/outlives/test.rs +++ b/compiler/rustc_hir_analysis/src/outlives/test.rs @@ -6,7 +6,7 @@ pub fn test_inferred_outlives(tcx: TyCtxt<'_>) { for id in tcx.hir().items() { // For unit testing: check for a special "rustc_outlives" // attribute and report an error with various results if found. - if tcx.has_attr(id.owner_id.to_def_id(), sym::rustc_outlives) { + if tcx.has_attr(id.owner_id, sym::rustc_outlives) { let inferred_outlives_of = tcx.inferred_outlives_of(id.owner_id); struct_span_err!( tcx.sess, diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 361e8948e851..72be951839d0 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -38,7 +38,7 @@ fn crate_variances(tcx: TyCtxt<'_>, (): ()) -> CrateVariancesMap<'_> { solve::solve_constraints(constraints_cx) } -fn variances_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[ty::Variance] { +fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] { // Skip items with no generics - there's nothing to infer in them. if tcx.generics_of(item_def_id).count() == 0 { return &[]; @@ -53,7 +53,7 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[ty::Variance] { | DefKind::Variant | DefKind::Ctor(..) => {} DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder => { - return variance_of_opaque(tcx, item_def_id.expect_local()); + return variance_of_opaque(tcx, item_def_id); } _ => { // Variance not relevant. @@ -64,7 +64,7 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[ty::Variance] { // Everything else must be inferred. let crate_map = tcx.crate_variances(()); - crate_map.variances.get(&item_def_id).copied().unwrap_or(&[]) + crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]) } #[instrument(level = "trace", skip(tcx), ret)] diff --git a/compiler/rustc_hir_analysis/src/variance/test.rs b/compiler/rustc_hir_analysis/src/variance/test.rs index 64614831f560..d57d05d7605d 100644 --- a/compiler/rustc_hir_analysis/src/variance/test.rs +++ b/compiler/rustc_hir_analysis/src/variance/test.rs @@ -7,7 +7,7 @@ pub fn test_variance(tcx: TyCtxt<'_>) { // For unit testing: check for a special "rustc_variance" // attribute and report an error with various results if found. for id in tcx.hir().items() { - if tcx.has_attr(id.owner_id.to_def_id(), sym::rustc_variance) { + if tcx.has_attr(id.owner_id, sym::rustc_variance) { let variances_of = tcx.variances_of(id.owner_id); tcx.sess.emit_err(errors::VariancesOf { diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index d9c56134b662..6af095cb4d43 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -207,7 +207,7 @@ fn typeck_with_fallback<'tcx>( let body = tcx.hir().body(body_id); let param_env = tcx.param_env(def_id); - let param_env = if tcx.has_attr(def_id.to_def_id(), sym::rustc_do_not_const_check) { + let param_env = if tcx.has_attr(def_id, sym::rustc_do_not_const_check) { param_env.without_const() } else { param_env diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 4a432328c4d1..6e873577c1f0 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -1498,7 +1498,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } fn should_log_capture_analysis(&self, closure_def_id: LocalDefId) -> bool { - self.tcx.has_attr(closure_def_id.to_def_id(), sym::rustc_capture_analysis) + self.tcx.has_attr(closure_def_id, sym::rustc_capture_analysis) } fn log_capture_analysis_first_pass( diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index af588b16d593..e876fa27593d 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -44,8 +44,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This attribute causes us to dump some writeback information // in the form of errors, which is used for unit tests. - let rustc_dump_user_substs = - self.tcx.has_attr(item_def_id.to_def_id(), sym::rustc_dump_user_substs); + let rustc_dump_user_substs = self.tcx.has_attr(item_def_id, sym::rustc_dump_user_substs); let mut wbcx = WritebackCx::new(self, body, rustc_dump_user_substs); for param in body.params { diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index b839416c9195..1d88dfd20c8c 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -371,7 +371,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { fn check_item(&mut self, item_id: LocalDefId) { let item_span = self.tcx.def_span(item_id.to_def_id()); let def_path_hash = self.tcx.def_path_hash(item_id.to_def_id()); - for attr in self.tcx.get_attrs(item_id.to_def_id(), sym::rustc_clean) { + for attr in self.tcx.get_attrs(item_id, sym::rustc_clean) { let Some(assertion) = self.assertion_maybe(item_id, attr) else { continue; }; diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index 55dcfd05e0ad..ec122dc039f7 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -356,7 +356,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { if !self.same_type_modulo_infer(*found_sig, *expected_sig) || !sig.is_suggestable(self.tcx, true) - || ty::util::is_intrinsic(self.tcx, *did) + || self.tcx.is_intrinsic(*did) { return; } @@ -400,8 +400,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { if !self.same_type_modulo_infer(*found_sig, *expected_sig) || !found_sig.is_suggestable(self.tcx, true) || !expected_sig.is_suggestable(self.tcx, true) - || ty::util::is_intrinsic(self.tcx, *did1) - || ty::util::is_intrinsic(self.tcx, *did2) + || self.tcx.is_intrinsic(*did1) + || self.tcx.is_intrinsic(*did2) { return; } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index b1ff76865abd..8af1a663ef5e 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1306,7 +1306,7 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller { if fn_kind.asyncness() == IsAsync::Async && !cx.tcx.features().closure_track_caller // Now, check if the function has the `#[track_caller]` attribute - && let Some(attr) = cx.tcx.get_attr(def_id.to_def_id(), sym::track_caller) + && let Some(attr) = cx.tcx.get_attr(def_id, sym::track_caller) { cx.emit_spanned_lint(UNGATED_ASYNC_FN_TRACK_CALLER, attr.span, BuiltinUngatedAsyncFnTrackCaller { label: span, @@ -2748,10 +2748,7 @@ impl ClashingExternDeclarations { // information, we could have codegen_fn_attrs also give span information back for // where the attribute was defined. However, until this is found to be a // bottleneck, this does just fine. - ( - overridden_link_name, - tcx.get_attr(fi.owner_id.to_def_id(), sym::link_name).unwrap().span, - ) + (overridden_link_name, tcx.get_attr(fi.owner_id, sym::link_name).unwrap().span) }) { SymbolName::Link(overridden_link_name, overridden_link_name_span) diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index a14dc20fca36..9c7feadaf874 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -386,7 +386,7 @@ impl LateLintPass<'_> for Diagnostics { for (hir_id, parent) in cx.tcx.hir().parent_iter(expr.hir_id) { if let Some(owner_did) = hir_id.as_owner() { found_parent_with_attr = found_parent_with_attr - || cx.tcx.has_attr(owner_did.to_def_id(), sym::rustc_lint_diagnostics); + || cx.tcx.has_attr(owner_did, sym::rustc_lint_diagnostics); } debug!(?parent); diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 71e2e66bdebc..0f44dde59485 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -384,9 +384,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { match &fk { FnKind::Method(ident, sig, ..) => match method_context(cx, id) { MethodLateContext::PlainImpl => { - if sig.header.abi != Abi::Rust - && cx.tcx.has_attr(id.to_def_id(), sym::no_mangle) - { + if sig.header.abi != Abi::Rust && cx.tcx.has_attr(id, sym::no_mangle) { return; } self.check_snake_case(cx, "method", ident); @@ -398,7 +396,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { }, FnKind::ItemFn(ident, _, header) => { // Skip foreign-ABI #[no_mangle] functions (Issue #31924) - if header.abi != Abi::Rust && cx.tcx.has_attr(id.to_def_id(), sym::no_mangle) { + if header.abi != Abi::Rust && cx.tcx.has_attr(id, sym::no_mangle) { return; } self.check_snake_case(cx, "function", ident); diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 561e770d90ce..2da075221db6 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -367,10 +367,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { *providers = Providers { allocator_kind: |tcx, ()| CStore::from_tcx(tcx).allocator_kind(), alloc_error_handler_kind: |tcx, ()| CStore::from_tcx(tcx).alloc_error_handler_kind(), - is_private_dep: |_tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - false - }, + is_private_dep: |_tcx, ()| false, native_library: |tcx, id| { tcx.native_libraries(id.krate) .iter() @@ -386,12 +383,8 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { .contains(&id) }) }, - native_libraries: |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - native_libs::collect(tcx) - }, - foreign_modules: |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); + native_libraries: |tcx, ()| native_libs::collect(tcx), + foreign_modules: |tcx, ()| { foreign_modules::collect(tcx).into_iter().map(|m| (m.def_id, m)).collect() }, @@ -489,14 +482,8 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { }, dependency_formats: |tcx, ()| Lrc::new(crate::dependency_format::calculate(tcx)), - has_global_allocator: |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - CStore::from_tcx(tcx).has_global_allocator() - }, - has_alloc_error_handler: |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - CStore::from_tcx(tcx).has_alloc_error_handler() - }, + has_global_allocator: |tcx, ()| CStore::from_tcx(tcx).has_global_allocator(), + has_alloc_error_handler: |tcx, ()| CStore::from_tcx(tcx).has_alloc_error_handler(), postorder_cnums: |tcx, ()| { tcx.arena .alloc_slice(&CStore::from_tcx(tcx).crate_dependencies_in_postorder(LOCAL_CRATE)) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 46fd0cace09a..97ac3eccae7b 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -2231,18 +2231,16 @@ pub fn provide(providers: &mut Providers) { doc_link_resolutions: |tcx, def_id| { tcx.resolutions(()) .doc_link_resolutions - .get(&def_id.expect_local()) + .get(&def_id) .expect("no resolutions for a doc link") }, doc_link_traits_in_scope: |tcx, def_id| { tcx.resolutions(()) .doc_link_traits_in_scope - .get(&def_id.expect_local()) + .get(&def_id) .expect("no traits in scope for a doc link") }, - traits_in_crate: |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - + traits_in_crate: |tcx, ()| { let mut traits = Vec::new(); for id in tcx.hir().items() { if matches!(tcx.def_kind(id.owner_id), DefKind::Trait | DefKind::TraitAlias) { @@ -2254,9 +2252,7 @@ pub fn provide(providers: &mut Providers) { traits.sort_by_cached_key(|&def_id| tcx.def_path_hash(def_id)); tcx.arena.alloc_slice(&traits) }, - trait_impls_in_crate: |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - + trait_impls_in_crate: |tcx, ()| { let mut trait_impls = Vec::new(); for id in tcx.hir().items() { if matches!(tcx.def_kind(id.owner_id), DefKind::Impl { .. }) diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 8a4c10cd71c0..d877a2c54942 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -6,7 +6,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::*; @@ -1131,8 +1131,7 @@ impl<'hir> intravisit::Map<'hir> for Map<'hir> { } } -pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh { - debug_assert_eq!(crate_num, LOCAL_CRATE); +pub(super) fn crate_hash(tcx: TyCtxt<'_>, (): ()) -> Svh { let krate = tcx.hir_crate(()); let hir_body_hash = krate.opt_hir_hash.expect("HIR hash missing while computing crate hash"); diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 403b2b650886..0d8a8c9cdfd4 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -147,18 +147,18 @@ pub fn provide(providers: &mut Providers) { tcx.hir_crate(()).owners[id.def_id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs) }; providers.def_span = |tcx, def_id| { - let def_id = def_id.expect_local(); + let def_id = def_id; let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); tcx.hir().opt_span(hir_id).unwrap_or(DUMMY_SP) }; providers.def_ident_span = |tcx, def_id| { - let def_id = def_id.expect_local(); + let def_id = def_id; let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); tcx.hir().opt_ident_span(hir_id) }; providers.fn_arg_names = |tcx, id| { let hir = tcx.hir(); - let def_id = id.expect_local(); + let def_id = id; let hir_id = hir.local_def_id_to_hir_id(def_id); if let Some(body_id) = hir.maybe_body_owned_by(def_id) { tcx.arena.alloc_from_iter(hir.body_param_names(body_id)) @@ -176,12 +176,10 @@ pub fn provide(providers: &mut Providers) { span_bug!(hir.span(hir_id), "fn_arg_names: unexpected item {:?}", id); } }; - providers.opt_def_kind = |tcx, def_id| tcx.hir().opt_def_kind(def_id.expect_local()); + providers.opt_def_kind = |tcx, def_id| tcx.hir().opt_def_kind(def_id); providers.all_local_trait_impls = |tcx, ()| &tcx.resolutions(()).trait_impls; - providers.expn_that_defined = |tcx, id| { - let id = id.expect_local(); - tcx.resolutions(()).expn_that_defined.get(&id).copied().unwrap_or(ExpnId::root()) - }; + providers.expn_that_defined = + |tcx, id| tcx.resolutions(()).expn_that_defined.get(&id).copied().unwrap_or(ExpnId::root()); providers.in_scope_traits_map = |tcx, id| { tcx.hir_crate(()).owners[id.def_id].as_owner().map(|owner_info| &owner_info.trait_map) }; diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 6e961a775c1f..584e94bf847c 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -26,9 +26,11 @@ pub trait Key: Sized { // r-a issue: type CacheSelector; + type LocalKey; + /// Given an instance of this key, what crate is it referring to? /// This is used to find the provider. - fn query_crate_is_local(&self) -> bool; + fn as_local_key(&self) -> Option; /// In the event that a cycle occurs, if no explicit span has been /// given for a query with key `self`, what span should we use? @@ -47,10 +49,11 @@ pub trait Key: Sized { impl Key for () { type CacheSelector = SingleCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } fn default_span(&self, _: TyCtxt<'_>) -> Span { @@ -60,10 +63,11 @@ impl Key for () { impl<'tcx> Key for ty::InstanceDef<'tcx> { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.def_id().is_local() + fn as_local_key(&self) -> Option { + self.def_id().is_local().then(|| *self) } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { @@ -73,10 +77,11 @@ impl<'tcx> Key for ty::InstanceDef<'tcx> { impl<'tcx> Key for ty::Instance<'tcx> { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.def_id().is_local() + fn as_local_key(&self) -> Option { + self.def_id().is_local().then(|| *self) } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { @@ -86,10 +91,11 @@ impl<'tcx> Key for ty::Instance<'tcx> { impl<'tcx> Key for mir::interpret::GlobalId<'tcx> { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { @@ -99,10 +105,11 @@ impl<'tcx> Key for mir::interpret::GlobalId<'tcx> { impl<'tcx> Key for (Ty<'tcx>, Option>) { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } fn default_span(&self, _: TyCtxt<'_>) -> Span { @@ -112,10 +119,11 @@ impl<'tcx> Key for (Ty<'tcx>, Option>) { impl<'tcx> Key for mir::interpret::LitToConstInput<'tcx> { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { @@ -125,11 +133,13 @@ impl<'tcx> Key for mir::interpret::LitToConstInput<'tcx> { impl Key for CrateNum { type CacheSelector = VecCacheSelector; + type LocalKey = (); #[inline(always)] - fn query_crate_is_local(&self) -> bool { - *self == LOCAL_CRATE + fn as_local_key(&self) -> Option { + (*self == LOCAL_CRATE).then_some(()) } + fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -137,14 +147,17 @@ impl Key for CrateNum { impl Key for OwnerId { type CacheSelector = VecCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.to_def_id().default_span(tcx) } + fn key_as_def_id(&self) -> Option { Some(self.to_def_id()) } @@ -152,14 +165,17 @@ impl Key for OwnerId { impl Key for LocalDefId { type CacheSelector = VecCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.to_def_id().default_span(tcx) } + fn key_as_def_id(&self) -> Option { Some(self.to_def_id()) } @@ -167,14 +183,17 @@ impl Key for LocalDefId { impl Key for DefId { type CacheSelector = DefaultCacheSelector; + type LocalKey = LocalDefId; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.krate == LOCAL_CRATE + fn as_local_key(&self) -> Option { + self.as_local() } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(*self) } + #[inline(always)] fn key_as_def_id(&self) -> Option { Some(*self) @@ -183,11 +202,13 @@ impl Key for DefId { impl Key for ty::WithOptConstParam { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.did.default_span(tcx) } @@ -195,11 +216,13 @@ impl Key for ty::WithOptConstParam { impl Key for SimplifiedType { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } + fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -207,11 +230,13 @@ impl Key for SimplifiedType { impl Key for (DefId, DefId) { type CacheSelector = DefaultCacheSelector; + type LocalKey = (LocalDefId, DefId); #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.0.krate == LOCAL_CRATE + fn as_local_key(&self) -> Option { + Some((self.0.as_local()?, self.1)) } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.1.default_span(tcx) } @@ -219,11 +244,13 @@ impl Key for (DefId, DefId) { impl<'tcx> Key for (ty::Instance<'tcx>, LocalDefId) { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) } @@ -231,11 +258,13 @@ impl<'tcx> Key for (ty::Instance<'tcx>, LocalDefId) { impl Key for (DefId, LocalDefId) { type CacheSelector = DefaultCacheSelector; + type LocalKey = (LocalDefId, LocalDefId); #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.0.krate == LOCAL_CRATE + fn as_local_key(&self) -> Option { + Some((self.0.as_local()?, self.1)) } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.1.default_span(tcx) } @@ -243,11 +272,13 @@ impl Key for (DefId, LocalDefId) { impl Key for (LocalDefId, DefId) { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) } @@ -255,11 +286,13 @@ impl Key for (LocalDefId, DefId) { impl Key for (LocalDefId, LocalDefId) { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) } @@ -267,14 +300,16 @@ impl Key for (LocalDefId, LocalDefId) { impl Key for (DefId, Option) { type CacheSelector = DefaultCacheSelector; + type LocalKey = (LocalDefId, Option); - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.0.krate == LOCAL_CRATE + fn as_local_key(&self) -> Option { + Some((self.0.as_local()?, self.1)) } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.0) } + #[inline(always)] fn key_as_def_id(&self) -> Option { Some(self.0) @@ -283,11 +318,12 @@ impl Key for (DefId, Option) { impl Key for (DefId, LocalDefId, Ident) { type CacheSelector = DefaultCacheSelector; + type LocalKey = (LocalDefId, LocalDefId, Ident); - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.0.krate == LOCAL_CRATE + fn as_local_key(&self) -> Option { + Some((self.0.as_local()?, self.1, self.2)) } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.1.default_span(tcx) } @@ -295,11 +331,13 @@ impl Key for (DefId, LocalDefId, Ident) { impl Key for (CrateNum, DefId) { type CacheSelector = DefaultCacheSelector; + type LocalKey = DefId; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.0 == LOCAL_CRATE + fn as_local_key(&self) -> Option { + (self.0 == LOCAL_CRATE).then_some(self.1) } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.1.default_span(tcx) } @@ -307,11 +345,13 @@ impl Key for (CrateNum, DefId) { impl Key for (CrateNum, SimplifiedType) { type CacheSelector = DefaultCacheSelector; + type LocalKey = SimplifiedType; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.0 == LOCAL_CRATE + fn as_local_key(&self) -> Option { + (self.0 == LOCAL_CRATE).then_some(self.1) } + fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -319,11 +359,13 @@ impl Key for (CrateNum, SimplifiedType) { impl Key for (DefId, SimplifiedType) { type CacheSelector = DefaultCacheSelector; + type LocalKey = (LocalDefId, SimplifiedType); #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.0.krate == LOCAL_CRATE + fn as_local_key(&self) -> Option { + Some((self.0.as_local()?, self.1)) } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) } @@ -331,11 +373,13 @@ impl Key for (DefId, SimplifiedType) { impl<'tcx> Key for SubstsRef<'tcx> { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } + fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -343,11 +387,13 @@ impl<'tcx> Key for SubstsRef<'tcx> { impl<'tcx> Key for (DefId, SubstsRef<'tcx>) { type CacheSelector = DefaultCacheSelector; + type LocalKey = (LocalDefId, SubstsRef<'tcx>); #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.0.krate == LOCAL_CRATE + fn as_local_key(&self) -> Option { + Some((self.0.as_local()?, self.1)) } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) } @@ -355,11 +401,13 @@ impl<'tcx> Key for (DefId, SubstsRef<'tcx>) { impl<'tcx> Key for (ty::UnevaluatedConst<'tcx>, ty::UnevaluatedConst<'tcx>) { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - (self.0).def.did.krate == LOCAL_CRATE + fn as_local_key(&self) -> Option { + self.0.def.is_local().then_some(*self) } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { (self.0).def.did.default_span(tcx) } @@ -367,11 +415,13 @@ impl<'tcx> Key for (ty::UnevaluatedConst<'tcx>, ty::UnevaluatedConst<'tcx>) { impl<'tcx> Key for (LocalDefId, DefId, SubstsRef<'tcx>) { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) } @@ -379,11 +429,13 @@ impl<'tcx> Key for (LocalDefId, DefId, SubstsRef<'tcx>) { impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.1.def_id().krate == LOCAL_CRATE + fn as_local_key(&self) -> Option { + self.1.def_id().is_local().then_some(*self) } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.1.def_id()) } @@ -391,11 +443,13 @@ impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) { impl<'tcx> Key for (ty::Const<'tcx>, mir::Field) { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } + fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -403,11 +457,13 @@ impl<'tcx> Key for (ty::Const<'tcx>, mir::Field) { impl<'tcx> Key for mir::interpret::ConstAlloc<'tcx> { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } + fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -415,11 +471,13 @@ impl<'tcx> Key for mir::interpret::ConstAlloc<'tcx> { impl<'tcx> Key for ty::PolyTraitRef<'tcx> { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.def_id().krate == LOCAL_CRATE + fn as_local_key(&self) -> Option { + self.def_id().is_local().then_some(*self) } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.def_id()) } @@ -427,11 +485,13 @@ impl<'tcx> Key for ty::PolyTraitRef<'tcx> { impl<'tcx> Key for ty::PolyExistentialTraitRef<'tcx> { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.def_id().krate == LOCAL_CRATE + fn as_local_key(&self) -> Option { + self.def_id().is_local().then_some(*self) } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.def_id()) } @@ -439,11 +499,13 @@ impl<'tcx> Key for ty::PolyExistentialTraitRef<'tcx> { impl<'tcx> Key for (ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>) { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.0.def_id().krate == LOCAL_CRATE + fn as_local_key(&self) -> Option { + self.0.def_id().is_local().then_some(*self) } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.0.def_id()) } @@ -451,11 +513,13 @@ impl<'tcx> Key for (ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>) { impl<'tcx> Key for GenericArg<'tcx> { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } + fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -463,11 +527,13 @@ impl<'tcx> Key for GenericArg<'tcx> { impl<'tcx> Key for mir::ConstantKind<'tcx> { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } + fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -475,11 +541,13 @@ impl<'tcx> Key for mir::ConstantKind<'tcx> { impl<'tcx> Key for ty::Const<'tcx> { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } + fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -487,14 +555,17 @@ impl<'tcx> Key for ty::Const<'tcx> { impl<'tcx> Key for Ty<'tcx> { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } + fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } + fn ty_adt_id(&self) -> Option { match self.kind() { ty::Adt(adt, _) => Some(adt.did()), @@ -505,11 +576,13 @@ impl<'tcx> Key for Ty<'tcx> { impl<'tcx> Key for TyAndLayout<'tcx> { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } + fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -517,11 +590,13 @@ impl<'tcx> Key for TyAndLayout<'tcx> { impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } + fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -529,11 +604,13 @@ impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) { impl<'tcx> Key for &'tcx ty::List> { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } + fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -541,11 +618,13 @@ impl<'tcx> Key for &'tcx ty::List> { impl<'tcx> Key for ty::ParamEnv<'tcx> { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } + fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -553,11 +632,12 @@ impl<'tcx> Key for ty::ParamEnv<'tcx> { impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> { type CacheSelector = DefaultCacheSelector; + type LocalKey = ty::ParamEnvAnd<'tcx, T::LocalKey>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.value.query_crate_is_local() + fn as_local_key(&self) -> Option { + self.value.as_local_key().map(|value| ty::ParamEnvAnd { param_env: self.param_env, value }) } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.value.default_span(tcx) } @@ -565,11 +645,13 @@ impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> { impl Key for Symbol { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } + fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -577,11 +659,13 @@ impl Key for Symbol { impl Key for Option { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } + fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -589,12 +673,13 @@ impl Key for Option { /// Canonical query goals correspond to abstract trait operations that /// are not tied to any crate in particular. -impl<'tcx, T> Key for Canonical<'tcx, T> { +impl<'tcx, T: Clone> Key for Canonical<'tcx, T> { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(self.clone()) } fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { @@ -604,10 +689,11 @@ impl<'tcx, T> Key for Canonical<'tcx, T> { impl Key for (Symbol, u32, u32) { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { @@ -617,10 +703,11 @@ impl Key for (Symbol, u32, u32) { impl<'tcx> Key for (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>) { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { @@ -630,10 +717,11 @@ impl<'tcx> Key for (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>) { impl<'tcx> Key for (ty::Predicate<'tcx>, traits::WellFormedLoc) { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { @@ -643,10 +731,11 @@ impl<'tcx> Key for (ty::Predicate<'tcx>, traits::WellFormedLoc) { impl<'tcx> Key for (ty::PolyFnSig<'tcx>, &'tcx ty::List>) { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } fn default_span(&self, _: TyCtxt<'_>) -> Span { @@ -656,10 +745,11 @@ impl<'tcx> Key for (ty::PolyFnSig<'tcx>, &'tcx ty::List>) { impl<'tcx> Key for (ty::Instance<'tcx>, &'tcx ty::List>) { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { @@ -669,10 +759,11 @@ impl<'tcx> Key for (ty::Instance<'tcx>, &'tcx ty::List>) { impl<'tcx> Key for (Ty<'tcx>, ty::ValTree<'tcx>) { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } fn default_span(&self, _: TyCtxt<'_>) -> Span { @@ -682,10 +773,11 @@ impl<'tcx> Key for (Ty<'tcx>, ty::ValTree<'tcx>) { impl Key for HirId { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { @@ -700,11 +792,12 @@ impl Key for HirId { impl<'tcx> Key for (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>) { type CacheSelector = DefaultCacheSelector; + type LocalKey = Self; // Just forward to `Ty<'tcx>` #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option { + Some(*self) } fn default_span(&self, _: TyCtxt<'_>) -> Span { diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 42101f6b9315..712c1a31a52f 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -4,7 +4,7 @@ use crate::ty::{self, InternalSubsts, ParamEnv, ParamEnvAnd, Ty, TyCtxt}; use rustc_data_structures::intern::Interned; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::LocalDefId; use rustc_macros::HashStable; use std::fmt; @@ -265,8 +265,8 @@ impl<'tcx> Const<'tcx> { } } -pub fn const_param_default(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder> { - let default_def_id = match tcx.hir().get_by_def_id(def_id.expect_local()) { +pub fn const_param_default(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder> { + let default_def_id = match tcx.hir().get_by_def_id(def_id) { hir::Node::GenericParam(hir::GenericParam { kind: hir::GenericParamKind::Const { default: Some(ac), .. }, .. diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index e4694809cd1a..23ac99d3397e 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2518,16 +2518,11 @@ pub fn provide(providers: &mut ty::query::Providers) { providers.extern_mod_stmt_cnum = |tcx, id| tcx.resolutions(()).extern_crate_map.get(&id).cloned(); - providers.is_panic_runtime = |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::panic_runtime) - }; - providers.is_compiler_builtins = |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins) - }; - providers.has_panic_handler = |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); + providers.is_panic_runtime = + |tcx, ()| tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::panic_runtime); + providers.is_compiler_builtins = + |tcx, ()| tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins); + providers.has_panic_handler = |tcx, ()| { // We want to check if the panic handler was defined in this crate tcx.lang_items().panic_impl().map_or(false, |did| did.is_local()) }; diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 5fc98f01a547..aa10a651c071 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -187,7 +187,11 @@ impl<'tcx> InstanceDef<'tcx> { } #[inline] - pub fn get_attrs(&self, tcx: TyCtxt<'tcx>, attr: Symbol) -> ty::Attributes<'tcx> { + pub fn get_attrs( + &self, + tcx: TyCtxt<'tcx>, + attr: Symbol, + ) -> impl Iterator { tcx.get_attrs(self.def_id(), attr) } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 298b2c3073cd..d8da8e0f34a9 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2027,7 +2027,6 @@ impl<'tcx> FieldDef { } } -pub type Attributes<'tcx> = impl Iterator; #[derive(Debug, PartialEq, Eq)] pub enum ImplOverlapKind { /// These impls are always allowed to overlap. @@ -2375,7 +2374,12 @@ impl<'tcx> TyCtxt<'tcx> { } /// Gets all attributes with the given name. - pub fn get_attrs(self, did: DefId, attr: Symbol) -> ty::Attributes<'tcx> { + pub fn get_attrs( + self, + did: impl Into, + attr: Symbol, + ) -> impl Iterator { + let did: DefId = did.into(); let filter_fn = move |a: &&ast::Attribute| a.has_name(attr); if let Some(did) = did.as_local() { self.hir().attrs(self.hir().local_def_id_to_hir_id(did)).iter().filter(filter_fn) @@ -2386,8 +2390,9 @@ impl<'tcx> TyCtxt<'tcx> { } } - pub fn get_attr(self, did: DefId, attr: Symbol) -> Option<&'tcx ast::Attribute> { + pub fn get_attr(self, did: impl Into, attr: Symbol) -> Option<&'tcx ast::Attribute> { if cfg!(debug_assertions) && !rustc_feature::is_valid_for_get_attr(attr) { + let did: DefId = did.into(); bug!("get_attr: unexpected called with DefId `{:?}`, attr `{:?}`", did, attr); } else { self.get_attrs(did, attr).next() @@ -2395,7 +2400,8 @@ impl<'tcx> TyCtxt<'tcx> { } /// Determines whether an item is annotated with an attribute. - pub fn has_attr(self, did: DefId, attr: Symbol) -> bool { + pub fn has_attr(self, did: impl Into, attr: Symbol) -> bool { + let did: DefId = did.into(); if cfg!(debug_assertions) && !did.is_local() && rustc_feature::is_builtin_only_local(attr) { bug!("tried to access the `only_local` attribute `{}` from an extern crate", attr); } else { diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 05219efe5f54..3cf28408f690 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -151,6 +151,24 @@ macro_rules! query_if_arena { }; } +macro_rules! separate_provide_local_decl { + ([][$name:ident]) => { + for<'tcx> fn( + TyCtxt<'tcx>, + query_keys::$name<'tcx>, + ) -> query_provided::$name<'tcx> + }; + ([(separate_provide_extern) $($rest:tt)*][$name:ident]) => { + for<'tcx> fn( + TyCtxt<'tcx>, + query_keys_local::$name<'tcx>, + ) -> query_provided::$name<'tcx> + }; + ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => { + separate_provide_local_decl!([$($modifiers)*][$($args)*]) + }; +} + macro_rules! separate_provide_extern_decl { ([][$name:ident]) => { () @@ -212,6 +230,12 @@ macro_rules! define_callbacks { $(pub type $name<'tcx> = $($K)*;)* } #[allow(nonstandard_style, unused_lifetimes)] + pub mod query_keys_local { + use super::*; + + $(pub type $name<'tcx> = <$($K)* as Key>::LocalKey;)* + } + #[allow(nonstandard_style, unused_lifetimes)] pub mod query_values { use super::*; @@ -383,10 +407,7 @@ macro_rules! define_callbacks { } pub struct Providers { - $(pub $name: for<'tcx> fn( - TyCtxt<'tcx>, - query_keys::$name<'tcx>, - ) -> query_provided::$name<'tcx>,)* + $(pub $name: separate_provide_local_decl!([$($modifiers)*][$name]),)* } pub struct ExternProviders { @@ -405,7 +426,7 @@ macro_rules! define_callbacks { If that's not the case, {} was likely never assigned to a provider function.\n", stringify!($name), key, - if key.query_crate_is_local() { "local" } else { "external" }, + if key.as_local_key().is_some() { "local" } else { "external" }, stringify!($name), ),)* } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index dc585f438f4c..dcd9743196e1 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -15,7 +15,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_index::bit_set::GrowableBitSet; use rustc_index::vec::{Idx, IndexVec}; use rustc_macros::HashStable; @@ -1439,8 +1439,7 @@ pub fn reveal_opaque_types_in_bounds<'tcx>( } /// Determines whether an item is annotated with `doc(hidden)`. -fn is_doc_hidden(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - assert!(def_id.is_local()); +fn is_doc_hidden(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { tcx.get_attrs(def_id, sym::doc) .filter_map(|attr| attr.meta_item_list()) .any(|items| items.iter().any(|item| item.has_name(sym::hidden))) @@ -1454,7 +1453,7 @@ pub fn is_doc_notable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool { } /// Determines whether an item is an intrinsic by Abi. -pub fn is_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool { +pub fn is_intrinsic(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { matches!(tcx.fn_sig(def_id).skip_binder().abi(), Abi::RustIntrinsic | Abi::PlatformIntrinsic) } diff --git a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs index 89ca04a15827..e5c3fa5646a7 100644 --- a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs +++ b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs @@ -5,7 +5,7 @@ //! purposes on a best-effort basis. We compute them here and store them into the crate metadata so //! dependent crates can use them. -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::{Body, Local, Location, Operand, Terminator, TerminatorKind, RETURN_PLACE}; @@ -149,7 +149,10 @@ fn type_will_always_be_passed_directly(ty: Ty<'_>) -> bool { /// body of the function instead of just the signature. These can be useful for optimization /// purposes on a best-effort basis. We compute them here and store them into the crate metadata so /// dependent crates can use them. -pub fn deduced_param_attrs<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx [DeducedParamAttrs] { +pub fn deduced_param_attrs<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> &'tcx [DeducedParamAttrs] { // This computation is unfortunately rather expensive, so don't do it unless we're optimizing. // Also skip it in incremental mode. if tcx.sess.opts.optimize == OptLevel::No || tcx.sess.opts.incremental.is_some() { @@ -182,10 +185,6 @@ pub fn deduced_param_attrs<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx [Ded return &[]; } - // Deduced attributes for other crates should be read from the metadata instead of via this - // function. - debug_assert!(def_id.is_local()); - // Grab the optimized MIR. Analyze it to determine which arguments have been mutated. let body: &Body<'tcx> = tcx.optimized_mir(def_id); let mut deduce_read_only = DeduceReadOnly::new(body.arg_count); diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs index e6546911a2d0..1a9b1b8090b8 100644 --- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs +++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs @@ -1,4 +1,4 @@ -use rustc_hir::def_id::{CrateNum, LocalDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE}; use rustc_middle::mir::*; use rustc_middle::ty::layout; use rustc_middle::ty::query::Providers; @@ -121,9 +121,7 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool { tainted } -fn required_panic_strategy(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option { - assert_eq!(cnum, LOCAL_CRATE); - +fn required_panic_strategy(tcx: TyCtxt<'_>, (): ()) -> Option { if tcx.is_panic_runtime(LOCAL_CRATE) { return Some(tcx.sess.panic_strategy()); } diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index e6875fad3068..8a6360114dc5 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -70,7 +70,7 @@ use rustc_mir_dataflow::impls::{ }; use rustc_mir_dataflow::storage::always_storage_live_locals; use rustc_mir_dataflow::{self, Analysis}; -use rustc_span::def_id::DefId; +use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::symbol::sym; use rustc_span::Span; use rustc_target::abi::VariantIdx; @@ -1386,10 +1386,9 @@ fn create_cases<'tcx>( #[instrument(level = "debug", skip(tcx), ret)] pub(crate) fn mir_generator_witnesses<'tcx>( tcx: TyCtxt<'tcx>, - def_id: DefId, + def_id: LocalDefId, ) -> GeneratorLayout<'tcx> { assert!(tcx.sess.opts.unstable_opts.drop_tracking_mir); - let def_id = def_id.expect_local(); let (body, _) = tcx.mir_promoted(ty::WithOptConstParam::unknown(def_id)); let body = body.borrow(); diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 50c3023b02bd..3a515fe8323e 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -112,7 +112,6 @@ pub fn provide(providers: &mut Providers) { mir_keys, mir_const, mir_const_qualif: |tcx, def_id| { - let def_id = def_id.expect_local(); if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { tcx.mir_const_qualif_const_arg(def) } else { @@ -133,7 +132,6 @@ pub fn provide(providers: &mut Providers) { mir_callgraph_reachable: inline::cycle::mir_callgraph_reachable, mir_inliner_callees: inline::cycle::mir_inliner_callees, promoted_mir: |tcx, def_id| { - let def_id = def_id.expect_local(); if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { tcx.promoted_mir_of_const_arg(def) } else { @@ -206,8 +204,7 @@ fn remap_mir_for_const_eval_select<'tcx>( body } -fn is_mir_available(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - let def_id = def_id.expect_local(); +fn is_mir_available(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { tcx.mir_keys(()).contains(&def_id) } @@ -350,12 +347,11 @@ fn mir_promoted( } /// Compute the MIR that is used during CTFE (and thus has no optimizations run on it) -fn mir_for_ctfe(tcx: TyCtxt<'_>, def_id: DefId) -> &Body<'_> { - let did = def_id.expect_local(); - if let Some(def) = ty::WithOptConstParam::try_lookup(did, tcx) { +fn mir_for_ctfe(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &Body<'_> { + if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { tcx.mir_for_ctfe_of_const_arg(def) } else { - tcx.arena.alloc(inner_mir_for_ctfe(tcx, ty::WithOptConstParam::unknown(did))) + tcx.arena.alloc(inner_mir_for_ctfe(tcx, ty::WithOptConstParam::unknown(def_id))) } } @@ -599,8 +595,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { } /// Optimize the MIR and prepare it for codegen. -fn optimized_mir(tcx: TyCtxt<'_>, did: DefId) -> &Body<'_> { - let did = did.expect_local(); +fn optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> &Body<'_> { assert_eq!(ty::WithOptConstParam::try_lookup(did, tcx), None); tcx.arena.alloc(inner_optimized_mir(tcx, did)) } diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index 526b829bf676..30dd3e4d0169 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -104,9 +104,7 @@ impl<'tcx> CheckConstVisitor<'tcx> { // If this crate is not using stability attributes, or this function is not claiming to be a // stable `const fn`, that is all that is required. - if !tcx.features().staged_api - || tcx.has_attr(def_id.to_def_id(), sym::rustc_const_unstable) - { + if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) { return true; } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index ec1e1d0054b3..75ce446e6b44 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -469,9 +469,9 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { fn has_lang_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { - tcx.has_attr(def_id.to_def_id(), sym::lang) + tcx.has_attr(def_id, sym::lang) // Stable attribute for #[lang = "panic_impl"] - || tcx.has_attr(def_id.to_def_id(), sym::panic_handler) + || tcx.has_attr(def_id, sym::panic_handler) } fn has_allow_dead_code(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs index aeacbaa67cb5..9c7a3605d080 100644 --- a/compiler/rustc_passes/src/debugger_visualizer.rs +++ b/compiler/rustc_passes/src/debugger_visualizer.rs @@ -4,11 +4,9 @@ use hir::CRATE_HIR_ID; use rustc_data_structures::fx::FxHashSet; use rustc_expand::base::resolve_path; use rustc_hir as hir; -use rustc_hir::def_id::CrateNum; use rustc_hir::HirId; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; -use rustc_span::def_id::LOCAL_CRATE; use rustc_span::{sym, DebuggerVisualizerFile, DebuggerVisualizerType}; use std::sync::Arc; @@ -69,9 +67,7 @@ fn check_for_debugger_visualizer( } /// Traverses and collects the debugger visualizers for a specific crate. -fn debugger_visualizers(tcx: TyCtxt<'_>, cnum: CrateNum) -> Vec { - assert_eq!(cnum, LOCAL_CRATE); - +fn debugger_visualizers(tcx: TyCtxt<'_>, (): ()) -> Vec { // Initialize the collector. let mut debugger_visualizers = FxHashSet::default(); diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs index 110eb210df9a..b74fad66c0f0 100644 --- a/compiler/rustc_passes/src/diagnostic_items.rs +++ b/compiler/rustc_passes/src/diagnostic_items.rs @@ -14,7 +14,7 @@ use rustc_hir::diagnostic_items::DiagnosticItems; use rustc_hir::OwnerId; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; -use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use rustc_span::def_id::{DefId, LOCAL_CRATE}; use rustc_span::symbol::{sym, Symbol}; use crate::errors::DuplicateDiagnosticItemInCrate; @@ -62,9 +62,7 @@ fn extract(attrs: &[ast::Attribute]) -> Option { } /// Traverse and collect the diagnostic items in the current -fn diagnostic_items(tcx: TyCtxt<'_>, cnum: CrateNum) -> DiagnosticItems { - assert_eq!(cnum, LOCAL_CRATE); - +fn diagnostic_items(tcx: TyCtxt<'_>, (): ()) -> DiagnosticItems { // Initialize the collector. let mut diagnostic_items = DiagnosticItems::default(); diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index 047b9b525e85..5a1ae808e661 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -18,7 +18,7 @@ pub fn test_layout(tcx: TyCtxt<'_>) { tcx.def_kind(id.owner_id), DefKind::TyAlias | DefKind::Enum | DefKind::Struct | DefKind::Union ) { - for attr in tcx.get_attrs(id.owner_id.to_def_id(), sym::rustc_layout) { + for attr in tcx.get_attrs(id.owner_id, sym::rustc_layout) { dump_layout_of(tcx, id.owner_id.def_id, attr); } } diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 36324e6f8da4..a8471ce3b6fb 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -146,7 +146,7 @@ fn check_liveness(tcx: TyCtxt<'_>, def_id: DefId) { // Don't run unused pass for #[derive()] let parent = tcx.local_parent(local_def_id); if let DefKind::Impl { .. } = tcx.def_kind(parent) - && tcx.has_attr(parent.to_def_id(), sym::automatically_derived) + && tcx.has_attr(parent, sym::automatically_derived) { return; } diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index f07a64c7c3ca..c398467f03ef 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -30,7 +30,7 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { continue; } - let naked = tcx.has_attr(def_id.to_def_id(), sym::naked); + let naked = tcx.has_attr(def_id, sym::naked); if !naked { continue; } @@ -59,7 +59,7 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { /// Check that the function isn't inlined. fn check_inline(tcx: TyCtxt<'_>, def_id: LocalDefId) { - let attrs = tcx.get_attrs(def_id.to_def_id(), sym::inline); + let attrs = tcx.get_attrs(def_id, sym::inline); for attr in attrs { tcx.sess.emit_err(CannotInlineNakedFunction { span: attr.span }); } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index d5cc64a54029..6d0cfea00d1f 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -691,14 +691,10 @@ pub(crate) fn provide(providers: &mut Providers) { check_mod_unstable_api_usage, stability_index, stability_implications: |tcx, _| tcx.stability().implications.clone(), - lookup_stability: |tcx, id| tcx.stability().local_stability(id.expect_local()), - lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id.expect_local()), - lookup_default_body_stability: |tcx, id| { - tcx.stability().local_default_body_stability(id.expect_local()) - }, - lookup_deprecation_entry: |tcx, id| { - tcx.stability().local_deprecation_entry(id.expect_local()) - }, + lookup_stability: |tcx, id| tcx.stability().local_stability(id), + lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id), + lookup_default_body_stability: |tcx, id| tcx.stability().local_default_body_stability(id), + lookup_deprecation_entry: |tcx, id| tcx.stability().local_deprecation_entry(id), ..*providers }; } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index cd6764458984..d884ebd9acc7 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -920,7 +920,7 @@ pub struct TestReachabilityVisitor<'tcx, 'a> { impl<'tcx, 'a> TestReachabilityVisitor<'tcx, 'a> { fn effective_visibility_diagnostic(&mut self, def_id: LocalDefId) { - if self.tcx.has_attr(def_id.to_def_id(), sym::rustc_effective_visibility) { + if self.tcx.has_attr(def_id, sym::rustc_effective_visibility) { let mut error_msg = String::new(); let span = self.tcx.def_span(def_id.to_def_id()); if let Some(effective_vis) = self.effective_visibilities.effective_vis(def_id) { @@ -2060,8 +2060,8 @@ pub fn provide(providers: &mut Providers) { }; } -fn visibility(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Visibility { - local_visibility(tcx, def_id.expect_local()).to_def_id() +fn visibility(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Visibility { + local_visibility(tcx, def_id).to_def_id() } fn local_visibility(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Visibility { diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index ca3c3997df00..9bba26cc8e84 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -274,19 +274,19 @@ macro_rules! hash_result { }; } -macro_rules! get_provider { - ([][$tcx:expr, $name:ident, $key:expr]) => {{ - $tcx.queries.local_providers.$name +macro_rules! call_provider { + ([][$qcx:expr, $name:ident, $key:expr]) => {{ + ($qcx.queries.local_providers.$name)($qcx.tcx, $key) }}; - ([(separate_provide_extern) $($rest:tt)*][$tcx:expr, $name:ident, $key:expr]) => {{ - if $key.query_crate_is_local() { - $tcx.queries.local_providers.$name + ([(separate_provide_extern) $($rest:tt)*][$qcx:expr, $name:ident, $key:expr]) => {{ + if let Some(key) = $key.as_local_key() { + ($qcx.queries.local_providers.$name)($qcx.tcx, key) } else { - $tcx.queries.extern_providers.$name + ($qcx.queries.extern_providers.$name)($qcx.tcx, $key) } }}; ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => { - get_provider!([$($modifiers)*][$($args)*]) + call_provider!([$($modifiers)*][$($args)*]) }; } @@ -516,7 +516,7 @@ macro_rules! define_queries { fn compute(self, qcx: QueryCtxt<'tcx>, key: Self::Key) -> Self::Value { query_provided_to_value::$name( qcx.tcx, - get_provider!([$($modifiers)*][qcx, $name, key])(qcx.tcx, key) + call_provider!([$($modifiers)*][qcx, $name, key]) ) } diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs index c6899f8f244e..b4d5b7f3621c 100644 --- a/compiler/rustc_symbol_mangling/src/test.rs +++ b/compiler/rustc_symbol_mangling/src/test.rs @@ -53,7 +53,7 @@ impl SymbolNamesTest<'_> { // The formatting of `tag({})` is chosen so that tests can elect // to test the entirety of the string, if they choose, or else just // some subset. - for attr in tcx.get_attrs(def_id.to_def_id(), SYMBOL_NAME) { + for attr in tcx.get_attrs(def_id, SYMBOL_NAME) { let def_id = def_id.to_def_id(); let instance = Instance::new( def_id, @@ -79,7 +79,7 @@ impl SymbolNamesTest<'_> { } } - for attr in tcx.get_attrs(def_id.to_def_id(), DEF_PATH) { + for attr in tcx.get_attrs(def_id, DEF_PATH) { tcx.sess.emit_err(TestOutput { span: attr.span, kind: Kind::DefPath, diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 87fdaa14f6be..404ebacc15e7 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -18,8 +18,8 @@ pub fn provide(providers: &mut ty::query::Providers) { }; } -fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] { - let item = tcx.hir().expect_item(def_id.expect_local()); +fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[DefId] { + let item = tcx.hir().expect_item(def_id); match item.kind { hir::ItemKind::Trait(.., ref trait_item_refs) => { if tcx.lower_impl_trait_in_trait_to_assoc_ty() { @@ -107,27 +107,26 @@ fn impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> DefIdMap .collect() } -fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem { - let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); +fn associated_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AssocItem { + let id = tcx.hir().local_def_id_to_hir_id(def_id); let parent_def_id = tcx.hir().get_parent_item(id); let parent_item = tcx.hir().expect_item(parent_def_id.def_id); match parent_item.kind { hir::ItemKind::Impl(ref impl_) => { - if let Some(impl_item_ref) = - impl_.items.iter().find(|i| i.id.owner_id.to_def_id() == def_id) + if let Some(impl_item_ref) = impl_.items.iter().find(|i| i.id.owner_id.def_id == def_id) { let assoc_item = associated_item_from_impl_item_ref(impl_item_ref); - debug_assert_eq!(assoc_item.def_id, def_id); + debug_assert_eq!(assoc_item.def_id.expect_local(), def_id); return assoc_item; } } hir::ItemKind::Trait(.., ref trait_item_refs) => { if let Some(trait_item_ref) = - trait_item_refs.iter().find(|i| i.id.owner_id.to_def_id() == def_id) + trait_item_refs.iter().find(|i| i.id.owner_id.def_id == def_id) { let assoc_item = associated_item_from_trait_item_ref(trait_item_ref); - debug_assert_eq!(assoc_item.def_id, def_id); + debug_assert_eq!(assoc_item.def_id.expect_local(), def_id); return assoc_item; } } @@ -191,9 +190,9 @@ fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::A /// above, synthesize a corresponding associated type in the impl. fn associated_types_for_impl_traits_in_associated_fn( tcx: TyCtxt<'_>, - fn_def_id: DefId, + fn_def_id: LocalDefId, ) -> &'_ [DefId] { - let parent_def_id = tcx.parent(fn_def_id); + let parent_def_id = tcx.local_parent(fn_def_id); match tcx.def_kind(parent_def_id) { DefKind::Trait => { @@ -212,7 +211,7 @@ fn associated_types_for_impl_traits_in_associated_fn( let mut visitor = RPITVisitor { rpits: Vec::new() }; - if let Some(output) = tcx.hir().get_fn_output(fn_def_id.expect_local()) { + if let Some(output) = tcx.hir().get_fn_output(fn_def_id) { visitor.visit_fn_ret_ty(output); tcx.arena.alloc_from_iter(visitor.rpits.iter().map(|opaque_ty_def_id| { @@ -232,7 +231,7 @@ fn associated_types_for_impl_traits_in_associated_fn( associated_type_for_impl_trait_in_impl( tcx, trait_assoc_def_id.expect_local(), - fn_def_id.expect_local(), + fn_def_id, ) .to_def_id() }, diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index f2635271609b..4d0fd260de2f 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -425,7 +425,6 @@ pub fn provide(providers: &mut ty::query::Providers) { *providers = ty::query::Providers { destructure_const, thir_abstract_const: |tcx, def_id| { - let def_id = def_id.expect_local(); if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { tcx.thir_abstract_const_of_const_arg(def) } else { diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs index 591017eecd2e..26d6deab883e 100644 --- a/compiler/rustc_ty_utils/src/representability.rs +++ b/compiler/rustc_ty_utils/src/representability.rs @@ -4,7 +4,7 @@ use rustc_hir::def::DefKind; use rustc_index::bit_set::BitSet; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Representability, Ty, TyCtxt}; -use rustc_span::def_id::{DefId, LocalDefId}; +use rustc_span::def_id::LocalDefId; pub fn provide(providers: &mut Providers) { *providers = @@ -85,7 +85,7 @@ fn representability_adt_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Representab Representability::Representable } -fn params_in_repr(tcx: TyCtxt<'_>, def_id: DefId) -> BitSet { +fn params_in_repr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> BitSet { let adt_def = tcx.adt_def(def_id); let generics = tcx.generics_of(def_id); let mut params_in_repr = BitSet::new_empty(generics.params.len()); diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index f53952d25fad..70686eefbca0 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -7,10 +7,8 @@ use rustc_middle::ty::{ TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, }; use rustc_session::config::TraitSolver; -use rustc_span::{ - def_id::{DefId, CRATE_DEF_ID}, - DUMMY_SP, -}; +use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; +use rustc_span::DUMMY_SP; use rustc_trait_selection::traits; fn sized_constraint_for_ty<'tcx>( @@ -79,8 +77,8 @@ fn sized_constraint_for_ty<'tcx>( result } -fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness { - match tcx.hir().get_by_def_id(def_id.expect_local()) { +fn impl_defaultness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Defaultness { + match tcx.hir().get_by_def_id(def_id) { hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.defaultness, hir::Node::ImplItem(hir::ImplItem { defaultness, .. }) | hir::Node::TraitItem(hir::TraitItem { defaultness, .. }) => *defaultness, @@ -516,8 +514,8 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option, def_id: DefId) -> hir::IsAsync { - let node = tcx.hir().get_by_def_id(def_id.expect_local()); +fn asyncness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::IsAsync { + let node = tcx.hir().get_by_def_id(def_id); node.fn_sig().map_or(hir::IsAsync::NotAsync, |sig| sig.header.asyncness) } diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs index e8531157e0f7..a8926b29ac83 100644 --- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs @@ -143,7 +143,7 @@ impl<'tcx> LateLintPass<'tcx> for CognitiveComplexity { span: Span, def_id: LocalDefId, ) { - if !cx.tcx.has_attr(def_id.to_def_id(), sym::test) { + if !cx.tcx.has_attr(def_id, sym::test) { let expr = if is_async_fn(kind) { match get_async_fn_body(cx.tcx, body) { Some(b) => b, diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs index 8a5a28c6b3d8..8f68f90a2a13 100644 --- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs +++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs @@ -181,7 +181,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls { self_ty, .. }) = item.kind; - if !cx.tcx.has_attr(item.owner_id.to_def_id(), sym::automatically_derived); + if !cx.tcx.has_attr(item.owner_id, sym::automatically_derived); if !item.span.from_expansion(); if let Some(def_id) = trait_ref.trait_def_id(); if cx.tcx.is_diagnostic_item(sym::Default, def_id); diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index b8428d66a5dc..715348e869ef 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -212,7 +212,7 @@ impl<'tcx> LateLintPass<'tcx> for Derive { }) = item.kind { let ty = cx.tcx.type_of(item.owner_id).subst_identity(); - let is_automatically_derived = cx.tcx.has_attr(item.owner_id.to_def_id(), sym::automatically_derived); + let is_automatically_derived = cx.tcx.has_attr(item.owner_id, sym::automatically_derived); check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived); check_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived); diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index 29bdc46b647d..eacbf6c6ec9b 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -22,7 +22,7 @@ use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT}; pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { let attrs = cx.tcx.hir().attrs(item.hir_id()); - let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use); + let attr = cx.tcx.get_attr(item.owner_id, sym::must_use); if let hir::ItemKind::Fn(ref sig, _generics, ref body_id) = item.kind { let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); @@ -47,7 +47,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); let attrs = cx.tcx.hir().attrs(item.hir_id()); - let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use); + let attr = cx.tcx.get_attr(item.owner_id, sym::must_use); if let Some(attr) = attr { check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr); } else if is_public @@ -73,7 +73,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); let attrs = cx.tcx.hir().attrs(item.hir_id()); - let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use); + let attr = cx.tcx.get_attr(item.owner_id, sym::must_use); if let Some(attr) = attr { check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr); } else if let hir::TraitFn::Provided(eid) = *eid { diff --git a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs index 5aa3c6f2f934..a8c4823fe538 100644 --- a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs +++ b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs @@ -36,7 +36,7 @@ impl<'tcx> LateLintPass<'tcx> for PartialEqNeImpl { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { if_chain! { if let ItemKind::Impl(Impl { of_trait: Some(ref trait_ref), items: impl_items, .. }) = item.kind; - if !cx.tcx.has_attr(item.owner_id.to_def_id(), sym::automatically_derived); + if !cx.tcx.has_attr(item.owner_id, sym::automatically_derived); if let Some(eq_trait) = cx.tcx.lang_items().eq_trait(); if trait_ref.path.res.def_id() == eq_trait; then { diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 6fe3fa7fb1b6..b6f6ac10fd77 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -22,7 +22,7 @@ use log::debug; use rustc_data_structures::sync::Lrc; use rustc_driver::Compilation; -use rustc_hir::{self as hir, def_id::LOCAL_CRATE, Node}; +use rustc_hir::{self as hir, Node}; use rustc_interface::interface::Config; use rustc_middle::{ middle::exported_symbols::{ @@ -107,8 +107,7 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { config.override_queries = Some(|_, local_providers, _| { // `exported_symbols` and `reachable_non_generics` provided by rustc always returns // an empty result if `tcx.sess.opts.output_types.should_codegen()` is false. - local_providers.exported_symbols = |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); + local_providers.exported_symbols = |tcx, ()| { let reachable_set = tcx.with_stable_hashing_context(|hcx| { tcx.reachable_set(()).to_sorted(&hcx, true) }); From 979ef5981f40f1475aa05095b82a783daf79c352 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 13 Mar 2023 19:06:41 +0000 Subject: [PATCH 61/70] Use LocalDefId in ItemCtxt --- .../rustc_hir_analysis/src/astconv/mod.rs | 7 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 2 +- compiler/rustc_hir_analysis/src/collect.rs | 28 ++-- .../src/collect/item_bounds.rs | 24 +-- .../src/collect/predicates_of.rs | 137 +++++++++--------- .../rustc_hir_analysis/src/collect/type_of.rs | 4 +- .../rustc_hir_analysis/src/hir_wf_check.rs | 2 +- compiler/rustc_hir_analysis/src/lib.rs | 4 +- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 6 +- compiler/rustc_middle/src/query/keys.rs | 6 +- compiler/rustc_middle/src/query/mod.rs | 2 +- 11 files changed, 110 insertions(+), 112 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 6a27383121d2..8a9aac14fb65 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -75,7 +75,7 @@ pub trait AstConv<'tcx> { fn get_type_parameter_bounds( &self, span: Span, - def_id: DefId, + def_id: LocalDefId, assoc_name: Ident, ) -> ty::GenericPredicates<'tcx>; @@ -1773,9 +1773,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ty_param_def_id, assoc_name, span, ); - let predicates = &self - .get_type_parameter_bounds(span, ty_param_def_id.to_def_id(), assoc_name) - .predicates; + let predicates = + &self.get_type_parameter_bounds(span, ty_param_def_id, assoc_name).predicates; debug!("find_bound_for_assoc_item: predicates={:#?}", predicates); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 4120ad45f6a6..737532b98a47 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1794,7 +1794,7 @@ fn check_variances_for_type_defn<'tcx>( // Lazily calculated because it is only needed in case of an error. let explicitly_bounded_params = LazyCell::new(|| { - let icx = crate::collect::ItemCtxt::new(tcx, item.owner_id.to_def_id()); + let icx = crate::collect::ItemCtxt::new(tcx, item.owner_id.def_id); hir_generics .predicates .iter() diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 8a1306aae083..db58f4af8ec3 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -113,7 +113,7 @@ pub fn provide(providers: &mut Providers) { /// the AST (`hir::Generics`), recursively. pub struct ItemCtxt<'tcx> { tcx: TyCtxt<'tcx>, - item_def_id: DefId, + item_def_id: LocalDefId, } /////////////////////////////////////////////////////////////////////////// @@ -347,7 +347,7 @@ fn bad_placeholder<'tcx>( } impl<'tcx> ItemCtxt<'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> ItemCtxt<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId) -> ItemCtxt<'tcx> { ItemCtxt { tcx, item_def_id } } @@ -356,7 +356,7 @@ impl<'tcx> ItemCtxt<'tcx> { } pub fn hir_id(&self) -> hir::HirId { - self.tcx.hir().local_def_id_to_hir_id(self.item_def_id.expect_local()) + self.tcx.hir().local_def_id_to_hir_id(self.item_def_id) } pub fn node(&self) -> hir::Node<'tcx> { @@ -370,20 +370,16 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { } fn item_def_id(&self) -> DefId { - self.item_def_id + self.item_def_id.to_def_id() } fn get_type_parameter_bounds( &self, span: Span, - def_id: DefId, + def_id: LocalDefId, assoc_name: Ident, ) -> ty::GenericPredicates<'tcx> { - self.tcx.at(span).type_param_predicates(( - self.item_def_id, - def_id.expect_local(), - assoc_name, - )) + self.tcx.at(span).type_param_predicates((self.item_def_id, def_id, assoc_name)) } fn re_infer(&self, _: Option<&ty::GenericParamDef>, _: Span) -> Option> { @@ -1095,7 +1091,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder, def_id: LocalDefId) -> ty::EarlyBinder { let abi = tcx.hir().get_foreign_abi(hir_id); - compute_sig_of_foreign_fn_decl(tcx, def_id.to_def_id(), fn_decl, abi) + compute_sig_of_foreign_fn_decl(tcx, def_id, fn_decl, abi) } Ctor(data) | Variant(hir::Variant { data, .. }) if data.ctor().is_some() => { @@ -1339,7 +1335,7 @@ fn impl_trait_ref( tcx: TyCtxt<'_>, def_id: LocalDefId, ) -> Option>> { - let icx = ItemCtxt::new(tcx, def_id.to_def_id()); + let icx = ItemCtxt::new(tcx, def_id); let impl_ = tcx.hir().expect_item(def_id).expect_impl(); impl_ .of_trait @@ -1465,16 +1461,16 @@ fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicate fn compute_sig_of_foreign_fn_decl<'tcx>( tcx: TyCtxt<'tcx>, - def_id: DefId, + def_id: LocalDefId, decl: &'tcx hir::FnDecl<'tcx>, abi: abi::Abi, ) -> ty::PolyFnSig<'tcx> { let unsafety = if abi == abi::Abi::RustIntrinsic { - intrinsic_operation_unsafety(tcx, def_id) + intrinsic_operation_unsafety(tcx, def_id.to_def_id()) } else { hir::Unsafety::Unsafe }; - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let fty = ItemCtxt::new(tcx, def_id).astconv().ty_of_fn(hir_id, unsafety, abi, decl, None, None); diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 3f4125954acb..d000a8e6622f 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -16,13 +16,13 @@ use rustc_span::Span; /// `hr-associated-type-bound-1.rs`. fn associated_type_bounds<'tcx>( tcx: TyCtxt<'tcx>, - assoc_item_def_id: DefId, + assoc_item_def_id: LocalDefId, ast_bounds: &'tcx [hir::GenericBound<'tcx>], span: Span, ) -> &'tcx [(ty::Predicate<'tcx>, Span)] { let item_ty = tcx.mk_projection( - assoc_item_def_id, - InternalSubsts::identity_for_item(tcx, assoc_item_def_id), + assoc_item_def_id.to_def_id(), + InternalSubsts::identity_for_item(tcx, assoc_item_def_id.to_def_id()), ); let icx = ItemCtxt::new(tcx, assoc_item_def_id); @@ -30,8 +30,8 @@ fn associated_type_bounds<'tcx>( // Associated types are implicitly sized unless a `?Sized` bound is found icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span); - let trait_def_id = tcx.parent(assoc_item_def_id); - let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id.expect_local()); + let trait_def_id = tcx.local_parent(assoc_item_def_id); + let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id); let bounds_from_parent = trait_predicates.predicates.iter().copied().filter(|(pred, _)| { match pred.kind().skip_binder() { @@ -45,7 +45,11 @@ fn associated_type_bounds<'tcx>( }); let all_bounds = tcx.arena.alloc_from_iter(bounds.predicates().chain(bounds_from_parent)); - debug!("associated_type_bounds({}) = {:?}", tcx.def_path_str(assoc_item_def_id), all_bounds); + debug!( + "associated_type_bounds({}) = {:?}", + tcx.def_path_str(assoc_item_def_id.to_def_id()), + all_bounds + ); all_bounds } @@ -56,7 +60,7 @@ fn associated_type_bounds<'tcx>( #[instrument(level = "trace", skip(tcx), ret)] fn opaque_type_bounds<'tcx>( tcx: TyCtxt<'tcx>, - opaque_def_id: DefId, + opaque_def_id: LocalDefId, ast_bounds: &'tcx [hir::GenericBound<'tcx>], item_ty: Ty<'tcx>, span: Span, @@ -84,7 +88,7 @@ pub(super) fn explicit_item_bounds( let opaque_ty = item.expect_opaque_ty(); return opaque_type_bounds( tcx, - opaque_def_id, + opaque_def_id.expect_local(), opaque_ty.bounds, tcx.mk_projection( def_id.to_def_id(), @@ -104,7 +108,7 @@ pub(super) fn explicit_item_bounds( kind: hir::TraitItemKind::Type(bounds, _), span, .. - }) => associated_type_bounds(tcx, def_id.to_def_id(), bounds, *span), + }) => associated_type_bounds(tcx, def_id, bounds, *span), hir::Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, in_trait, .. }), span, @@ -116,7 +120,7 @@ pub(super) fn explicit_item_bounds( } else { tcx.mk_opaque(def_id.to_def_id(), substs) }; - opaque_type_bounds(tcx, def_id.to_def_id(), bounds, item_ty, *span) + opaque_type_bounds(tcx, def_id, bounds, item_ty, *span) } _ => bug!("item_bounds called on {:?}", def_id), } diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index c1d61b1efc23..3ec34dfbe3ec 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -72,7 +72,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen let mut is_default_impl_trait = None; // FIXME: Should ItemCtxt take a LocalDefId? - let icx = ItemCtxt::new(tcx, def_id.to_def_id()); + let icx = ItemCtxt::new(tcx, def_id); const NO_GENERICS: &hir::Generics<'_> = hir::Generics::empty(); @@ -551,72 +551,70 @@ pub(super) fn super_predicates_that_define_assoc_type( tcx: TyCtxt<'_>, (trait_def_id, assoc_name): (DefId, Option), ) -> ty::GenericPredicates<'_> { - if trait_def_id.is_local() { - debug!("local trait"); - let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id.expect_local()); - - let Node::Item(item) = tcx.hir().get(trait_hir_id) else { - bug!("trait_node_id {} is not an item", trait_hir_id); - }; - - let (generics, bounds) = match item.kind { - hir::ItemKind::Trait(.., generics, supertraits, _) => (generics, supertraits), - hir::ItemKind::TraitAlias(generics, supertraits) => (generics, supertraits), - _ => span_bug!(item.span, "super_predicates invoked on non-trait"), - }; - - let icx = ItemCtxt::new(tcx, trait_def_id); - - // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`. - let self_param_ty = tcx.types.self_param; - let superbounds1 = if let Some(assoc_name) = assoc_name { - icx.astconv().compute_bounds_that_match_assoc_type(self_param_ty, bounds, assoc_name) - } else { - icx.astconv().compute_bounds(self_param_ty, bounds) - }; - - let superbounds1 = superbounds1.predicates(); - - // Convert any explicit superbounds in the where-clause, - // e.g., `trait Foo where Self: Bar`. - // In the case of trait aliases, however, we include all bounds in the where-clause, - // so e.g., `trait Foo = where u32: PartialEq` would include `u32: PartialEq` - // as one of its "superpredicates". - let is_trait_alias = tcx.is_trait_alias(trait_def_id); - let superbounds2 = icx.type_parameter_bounds_in_generics( - generics, - item.owner_id.def_id, - self_param_ty, - OnlySelfBounds(!is_trait_alias), - assoc_name, - ); - - // Combine the two lists to form the complete set of superbounds: - let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2)); - debug!(?superbounds); - - // Now require that immediate supertraits are converted, - // which will, in turn, reach indirect supertraits. - if assoc_name.is_none() { - // Now require that immediate supertraits are converted, - // which will, in turn, reach indirect supertraits. - for &(pred, span) in superbounds { - debug!("superbound: {:?}", pred); - if let ty::PredicateKind::Clause(ty::Clause::Trait(bound)) = - pred.kind().skip_binder() - { - tcx.at(span).super_predicates_of(bound.def_id()); - } - } - } - - ty::GenericPredicates { parent: None, predicates: superbounds } - } else { + let Some(trait_def_id) = trait_def_id.as_local() else { // if `assoc_name` is None, then the query should've been redirected to an // external provider assert!(assoc_name.is_some()); - tcx.super_predicates_of(trait_def_id) + return tcx.super_predicates_of(trait_def_id); + }; + + debug!("local trait"); + let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id); + + let Node::Item(item) = tcx.hir().get(trait_hir_id) else { + bug!("trait_node_id {} is not an item", trait_hir_id); + }; + + let (generics, bounds) = match item.kind { + hir::ItemKind::Trait(.., generics, supertraits, _) => (generics, supertraits), + hir::ItemKind::TraitAlias(generics, supertraits) => (generics, supertraits), + _ => span_bug!(item.span, "super_predicates invoked on non-trait"), + }; + + let icx = ItemCtxt::new(tcx, trait_def_id); + + // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`. + let self_param_ty = tcx.types.self_param; + let superbounds1 = if let Some(assoc_name) = assoc_name { + icx.astconv().compute_bounds_that_match_assoc_type(self_param_ty, bounds, assoc_name) + } else { + icx.astconv().compute_bounds(self_param_ty, bounds) + }; + + let superbounds1 = superbounds1.predicates(); + + // Convert any explicit superbounds in the where-clause, + // e.g., `trait Foo where Self: Bar`. + // In the case of trait aliases, however, we include all bounds in the where-clause, + // so e.g., `trait Foo = where u32: PartialEq` would include `u32: PartialEq` + // as one of its "superpredicates". + let is_trait_alias = tcx.is_trait_alias(trait_def_id.to_def_id()); + let superbounds2 = icx.type_parameter_bounds_in_generics( + generics, + item.owner_id.def_id, + self_param_ty, + OnlySelfBounds(!is_trait_alias), + assoc_name, + ); + + // Combine the two lists to form the complete set of superbounds: + let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2)); + debug!(?superbounds); + + // Now require that immediate supertraits are converted, + // which will, in turn, reach indirect supertraits. + if assoc_name.is_none() { + // Now require that immediate supertraits are converted, + // which will, in turn, reach indirect supertraits. + for &(pred, span) in superbounds { + debug!("superbound: {:?}", pred); + if let ty::PredicateKind::Clause(ty::Clause::Trait(bound)) = pred.kind().skip_binder() { + tcx.at(span).super_predicates_of(bound.def_id()); + } + } } + + ty::GenericPredicates { parent: None, predicates: superbounds } } /// Returns the predicates defined on `item_def_id` of the form @@ -624,7 +622,7 @@ pub(super) fn super_predicates_that_define_assoc_type( #[instrument(level = "trace", skip(tcx))] pub(super) fn type_param_predicates( tcx: TyCtxt<'_>, - (item_def_id, def_id, assoc_name): (DefId, LocalDefId, Ident), + (item_def_id, def_id, assoc_name): (LocalDefId, LocalDefId, Ident), ) -> ty::GenericPredicates<'_> { use rustc_hir::*; @@ -639,21 +637,21 @@ pub(super) fn type_param_predicates( let ty = tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id)); // Don't look for bounds where the type parameter isn't in scope. - let parent = if item_def_id == param_owner.to_def_id() { + let parent = if item_def_id == param_owner { None } else { - tcx.generics_of(item_def_id).parent + tcx.generics_of(item_def_id).parent.map(|def_id| def_id.expect_local()) }; let mut result = parent .map(|parent| { let icx = ItemCtxt::new(tcx, parent); - icx.get_type_parameter_bounds(DUMMY_SP, def_id.to_def_id(), assoc_name) + icx.get_type_parameter_bounds(DUMMY_SP, def_id, assoc_name) }) .unwrap_or_default(); let mut extend = None; - let item_hir_id = tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()); + let item_hir_id = tcx.hir().local_def_id_to_hir_id(item_def_id); let ast_generics = match tcx.hir().get(item_hir_id) { Node::TraitItem(item) => &item.generics, @@ -675,7 +673,8 @@ pub(super) fn type_param_predicates( ItemKind::Trait(_, _, generics, ..) => { // Implied `Self: Trait` and supertrait bounds. if param_id == item_hir_id { - let identity_trait_ref = ty::TraitRef::identity(tcx, item_def_id); + let identity_trait_ref = + ty::TraitRef::identity(tcx, item_def_id.to_def_id()); extend = Some((identity_trait_ref.without_const().to_predicate(tcx), item.span)); } diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 91eb63bc9f2d..9120d372304e 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -63,7 +63,7 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< .find(|(_, node)| matches!(node, OwnerNode::Item(_))) .unwrap() .0 - .to_def_id(); + .def_id; let item_ctxt = &ItemCtxt::new(tcx, item_def_id) as &dyn crate::astconv::AstConv<'_>; let ty = item_ctxt.ast_ty_to_ty(hir_ty); @@ -269,7 +269,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder match item.kind { diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index e330fcc78577..0b9c8400ad2b 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -31,7 +31,7 @@ fn diagnostic_hir_wf_check<'tcx>( tcx.sess .delay_span_bug(tcx.def_span(def_id), "Performed HIR wfcheck without an existing error!"); - let icx = ItemCtxt::new(tcx, def_id.to_def_id()); + let icx = ItemCtxt::new(tcx, def_id); // To perform HIR-based WF checking, we iterate over all HIR types // that occur 'inside' the item we're checking. For example, diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 08786fe9b1ef..384f3e76b8b1 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -513,7 +513,7 @@ pub fn hir_ty_to_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'_>) -> Ty<'tcx> { // def-ID that will be used to determine the traits/predicates in // scope. This is derived from the enclosing item-like thing. let env_def_id = tcx.hir().get_parent_item(hir_ty.hir_id); - let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id()); + let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.def_id); item_cx.astconv().ast_ty_to_ty(hir_ty) } @@ -526,7 +526,7 @@ pub fn hir_trait_to_predicates<'tcx>( // def-ID that will be used to determine the traits/predicates in // scope. This is derived from the enclosing item-like thing. let env_def_id = tcx.hir().get_parent_item(hir_trait.hir_ref_id); - let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id()); + let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.def_id); let mut bounds = Bounds::default(); let _ = &item_cx.astconv().instantiate_poly_trait_ref( hir_trait, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 1dea3e6f900d..c6fd0b610358 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -211,13 +211,13 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { fn get_type_parameter_bounds( &self, _: Span, - def_id: DefId, + def_id: LocalDefId, _: Ident, ) -> ty::GenericPredicates<'tcx> { let tcx = self.tcx; - let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local()); + let item_def_id = tcx.hir().ty_param_owner(def_id); let generics = tcx.generics_of(item_def_id); - let index = generics.param_def_id_to_index[&def_id]; + let index = generics.param_def_id_to_index[&def_id.to_def_id()]; ty::GenericPredicates { parent: None, predicates: tcx.arena.alloc_from_iter( diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 584e94bf847c..2f99a8874c04 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -316,12 +316,12 @@ impl Key for (DefId, Option) { } } -impl Key for (DefId, LocalDefId, Ident) { +impl Key for (LocalDefId, LocalDefId, Ident) { type CacheSelector = DefaultCacheSelector; - type LocalKey = (LocalDefId, LocalDefId, Ident); + type LocalKey = Self; fn as_local_key(&self) -> Option { - Some((self.0.as_local()?, self.1, self.2)) + Some(*self) } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 4bf81c97d06a..13f6779bd4fa 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -639,7 +639,7 @@ rustc_queries! { /// To avoid cycles within the predicates of a single item we compute /// per-type-parameter predicates for resolving `T::AssocTy`. - query type_param_predicates(key: (DefId, LocalDefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> { + query type_param_predicates(key: (LocalDefId, LocalDefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> { desc { |tcx| "computing the bounds for type parameter `{}`", tcx.hir().ty_param_name(key.1) } } From 7e6506764bf315dee81b403c724d31677b7694f5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 13 Mar 2023 19:35:29 +0000 Subject: [PATCH 62/70] IdentitySubsts::identity_for_item takes Into --- .../src/region_infer/opaque_types.rs | 2 +- compiler/rustc_hir_analysis/src/check/check.rs | 6 +++--- .../rustc_hir_analysis/src/collect/item_bounds.rs | 6 +++--- .../src/collect/predicates_of.rs | 2 +- compiler/rustc_hir_analysis/src/collect/type_of.rs | 14 +++++++------- .../src/impl_wf_check/min_specialization.rs | 2 +- compiler/rustc_hir_analysis/src/variance/mod.rs | 2 +- .../rustc_infer/src/infer/error_reporting/note.rs | 5 ++--- compiler/rustc_middle/src/mir/mod.rs | 4 ++-- compiler/rustc_middle/src/ty/consts.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_middle/src/ty/subst.rs | 4 ++-- compiler/rustc_mir_build/src/lints.rs | 2 +- compiler/rustc_ty_utils/src/assoc.rs | 2 +- 14 files changed, 27 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 748c8b9e4420..e542a1da053b 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -284,7 +284,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { // hidden type is well formed even without those bounds. let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into())); - let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id.to_def_id()); + let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id); // Require that the hidden type actually fulfills all the bounds of the opaque type, even without // the bounds that the function supplies. diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 43703e1e4693..4082759006de 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -211,7 +211,7 @@ fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) { return; } - let substs = InternalSubsts::identity_for_item(tcx, item.owner_id.to_def_id()); + let substs = InternalSubsts::identity_for_item(tcx, item.owner_id); let span = tcx.def_span(item.owner_id.def_id); if !tcx.features().impl_trait_projections { @@ -304,7 +304,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( .. }) = item.kind { - let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + let substs = InternalSubsts::identity_for_item(tcx, def_id); let opaque_identity_ty = if in_trait { tcx.mk_projection(def_id.to_def_id(), substs) } else { @@ -535,7 +535,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { } ty::AssocKind::Type if assoc_item.defaultness(tcx).has_value() => { let trait_substs = - InternalSubsts::identity_for_item(tcx, id.owner_id.to_def_id()); + InternalSubsts::identity_for_item(tcx, id.owner_id); let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds( tcx, assoc_item, diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index d000a8e6622f..aa66d7bb5efc 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -22,7 +22,7 @@ fn associated_type_bounds<'tcx>( ) -> &'tcx [(ty::Predicate<'tcx>, Span)] { let item_ty = tcx.mk_projection( assoc_item_def_id.to_def_id(), - InternalSubsts::identity_for_item(tcx, assoc_item_def_id.to_def_id()), + InternalSubsts::identity_for_item(tcx, assoc_item_def_id), ); let icx = ItemCtxt::new(tcx, assoc_item_def_id); @@ -92,7 +92,7 @@ pub(super) fn explicit_item_bounds( opaque_ty.bounds, tcx.mk_projection( def_id.to_def_id(), - ty::InternalSubsts::identity_for_item(tcx, def_id.to_def_id()), + ty::InternalSubsts::identity_for_item(tcx, def_id), ), item.span, ); @@ -114,7 +114,7 @@ pub(super) fn explicit_item_bounds( span, .. }) => { - let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + let substs = InternalSubsts::identity_for_item(tcx, def_id); let item_ty = if *in_trait && !tcx.lower_impl_trait_in_trait_to_assoc_ty() { tcx.mk_projection(def_id.to_def_id(), substs) } else { diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 3ec34dfbe3ec..fdab87b6acea 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -405,7 +405,7 @@ pub(super) fn explicit_predicates_of<'tcx>( // Remove bounds on associated types from the predicates, they will be // returned by `explicit_item_bounds`. let predicates_and_bounds = tcx.trait_explicit_predicates_and_bounds(def_id); - let trait_identity_substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + let trait_identity_substs = InternalSubsts::identity_for_item(tcx, def_id); let is_assoc_item_ty = |ty: Ty<'tcx>| { // For a predicate from a where clause to become a bound on an diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 9120d372304e..9bbca9b4e969 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -274,7 +274,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder match item.kind { TraitItemKind::Fn(..) => { - let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + let substs = InternalSubsts::identity_for_item(tcx, def_id); tcx.mk_fn_def(def_id.to_def_id(), substs) } TraitItemKind::Const(ty, body_id) => body_id @@ -294,7 +294,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder match item.kind { ImplItemKind::Fn(..) => { - let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + let substs = InternalSubsts::identity_for_item(tcx, def_id); tcx.mk_fn_def(def_id.to_def_id(), substs) } ImplItemKind::Const(ty, body_id) => { @@ -350,12 +350,12 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder icx.to_ty(*self_ty), }, ItemKind::Fn(..) => { - let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + let substs = InternalSubsts::identity_for_item(tcx, def_id); tcx.mk_fn_def(def_id.to_def_id(), substs) } ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => { let def = tcx.adt_def(def_id); - let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + let substs = InternalSubsts::identity_for_item(tcx, def_id); tcx.mk_adt(def, substs) } ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => { @@ -395,7 +395,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder match foreign_item.kind { ForeignItemKind::Fn(..) => { - let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + let substs = InternalSubsts::identity_for_item(tcx, def_id); tcx.mk_fn_def(def_id.to_def_id(), substs) } ForeignItemKind::Static(t, _) => icx.to_ty(t), @@ -407,7 +407,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder { - let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + let substs = InternalSubsts::identity_for_item(tcx, def_id); tcx.mk_fn_def(def_id.to_def_id(), substs) } }, @@ -440,7 +440,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder { - let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + let substs = InternalSubsts::identity_for_item(tcx, def_id); substs.as_inline_const().ty() } diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 58dd03811f78..91c64eeec1eb 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -168,7 +168,7 @@ fn get_impl_substs( let assumed_wf_types = ocx.assumed_wf_types(param_env, tcx.def_span(impl1_def_id), impl1_def_id); - let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id.to_def_id()); + let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id); let impl2_substs = translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node); diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 72be951839d0..0a45119ff055 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -152,7 +152,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc let mut collector = OpaqueTypeLifetimeCollector { tcx, root_def_id: item_def_id.to_def_id(), variances }; - let id_substs = ty::InternalSubsts::identity_for_item(tcx, item_def_id.to_def_id()); + let id_substs = ty::InternalSubsts::identity_for_item(tcx, item_def_id); for pred in tcx.bound_explicit_item_bounds(item_def_id.to_def_id()).transpose_iter() { let pred = pred.map_bound(|(pred, _)| *pred).subst(tcx, id_substs); debug!(?pred); diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 7ffe1fd20b49..e720af73c39f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -306,9 +306,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // Replace the explicit self type with `Self` for better suggestion rendering .with_self_ty(self.tcx, self.tcx.mk_ty_param(0, kw::SelfUpper)) .substs; - let trait_item_substs = - ty::InternalSubsts::identity_for_item(self.tcx, impl_item_def_id.to_def_id()) - .rebase_onto(self.tcx, impl_def_id, trait_substs); + let trait_item_substs = ty::InternalSubsts::identity_for_item(self.tcx, impl_item_def_id) + .rebase_onto(self.tcx, impl_def_id, trait_substs); let Ok(trait_predicates) = self .tcx diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 42c0354d03af..638c082cc84c 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2525,7 +2525,7 @@ impl<'tcx> ConstantKind<'tcx> { let parent_substs = if let Some(parent_hir_id) = tcx.hir().opt_parent_id(hir_id) && let Some(parent_did) = parent_hir_id.as_owner() { - InternalSubsts::identity_for_item(tcx, parent_did.to_def_id()) + InternalSubsts::identity_for_item(tcx, parent_did) } else { List::empty() }; @@ -2554,7 +2554,7 @@ impl<'tcx> ConstantKind<'tcx> { Self::Unevaluated( UnevaluatedConst { def: def.to_global(), - substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()), + substs: InternalSubsts::identity_for_item(tcx, def.did), promoted: None, }, ty, diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 712c1a31a52f..bcedae233d93 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -83,7 +83,7 @@ impl<'tcx> Const<'tcx> { None => tcx.mk_const( ty::UnevaluatedConst { def: def.to_global(), - substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()), + substs: InternalSubsts::identity_for_item(tcx, def.did), }, ty, ), diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index d8da8e0f34a9..5457cac55679 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1385,7 +1385,7 @@ impl<'tcx> OpaqueHiddenType<'tcx> { // lifetimes with 'static and remapping only those used in the // `impl Trait` return type, resulting in the parameters // shifting. - let id_substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + let id_substs = InternalSubsts::identity_for_item(tcx, def_id); debug!(?id_substs); // This zip may have several times the same lifetime in `substs` paired with a different diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index b090bd9d807c..f05b873432d2 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -302,8 +302,8 @@ impl<'tcx> InternalSubsts<'tcx> { } /// Creates an `InternalSubsts` that maps each generic parameter to itself. - pub fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> { - Self::for_item(tcx, def_id, |param, _| tcx.mk_param_from_def(param)) + pub fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: impl Into) -> SubstsRef<'tcx> { + Self::for_item(tcx, def_id.into(), |param, _| tcx.mk_param_from_def(param)) } /// Creates an `InternalSubsts` for generic parameter definitions, diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index f6db329fd7cf..8937b78fe34e 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -18,7 +18,7 @@ pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { let trait_substs = match tcx.trait_of_item(def_id.to_def_id()) { Some(trait_def_id) => { let trait_substs_count = tcx.generics_of(trait_def_id).count(); - &InternalSubsts::identity_for_item(tcx, def_id.to_def_id())[..trait_substs_count] + &InternalSubsts::identity_for_item(tcx, def_id)[..trait_substs_count] } _ => &[], }; diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 404ebacc15e7..6d9ad96fa74d 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -296,7 +296,7 @@ fn associated_type_for_impl_trait_in_trait( // Copy type_of of the opaque. trait_assoc_ty.type_of(ty::EarlyBinder(tcx.mk_opaque( opaque_ty_def_id.to_def_id(), - InternalSubsts::identity_for_item(tcx, opaque_ty_def_id.to_def_id()), + InternalSubsts::identity_for_item(tcx, opaque_ty_def_id), ))); trait_assoc_ty.is_type_alias_impl_trait(false); From dcaf956de0835a391b0dca5f85d38abe641b52e6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 13 Mar 2023 22:11:07 +0000 Subject: [PATCH 63/70] AsLocalKey trait --- compiler/rustc_middle/src/query/keys.rs | 349 +++--------------------- compiler/rustc_middle/src/query/mod.rs | 3 +- compiler/rustc_middle/src/ty/query.rs | 9 +- compiler/rustc_query_impl/src/lib.rs | 2 +- 4 files changed, 49 insertions(+), 314 deletions(-) diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 2f99a8874c04..f161f61d53e7 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -26,12 +26,6 @@ pub trait Key: Sized { // r-a issue: type CacheSelector; - type LocalKey; - - /// Given an instance of this key, what crate is it referring to? - /// This is used to find the provider. - fn as_local_key(&self) -> Option; - /// In the event that a cycle occurs, if no explicit span has been /// given for a query with key `self`, what span should we use? fn default_span(&self, tcx: TyCtxt<'_>) -> Span; @@ -47,14 +41,16 @@ pub trait Key: Sized { } } +pub trait AsLocalKey: Key { + type LocalKey; + + /// Given an instance of this key, what crate is it referring to? + /// This is used to find the provider. + fn as_local_key(&self) -> Option; +} + impl Key for () { type CacheSelector = SingleCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -63,26 +59,23 @@ impl Key for () { impl<'tcx> Key for ty::InstanceDef<'tcx> { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - self.def_id().is_local().then(|| *self) - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.def_id()) } } -impl<'tcx> Key for ty::Instance<'tcx> { - type CacheSelector = DefaultCacheSelector; +impl<'tcx> AsLocalKey for ty::InstanceDef<'tcx> { type LocalKey = Self; #[inline(always)] - fn as_local_key(&self) -> Option { + fn as_local_key(&self) -> Option { self.def_id().is_local().then(|| *self) } +} + +impl<'tcx> Key for ty::Instance<'tcx> { + type CacheSelector = DefaultCacheSelector; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.def_id()) @@ -91,12 +84,6 @@ impl<'tcx> Key for ty::Instance<'tcx> { impl<'tcx> Key for mir::interpret::GlobalId<'tcx> { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.instance.default_span(tcx) @@ -105,12 +92,6 @@ impl<'tcx> Key for mir::interpret::GlobalId<'tcx> { impl<'tcx> Key for (Ty<'tcx>, Option>) { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -119,12 +100,6 @@ impl<'tcx> Key for (Ty<'tcx>, Option>) { impl<'tcx> Key for mir::interpret::LitToConstInput<'tcx> { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP @@ -133,26 +108,23 @@ impl<'tcx> Key for mir::interpret::LitToConstInput<'tcx> { impl Key for CrateNum { type CacheSelector = VecCacheSelector; - type LocalKey = (); - - #[inline(always)] - fn as_local_key(&self) -> Option { - (*self == LOCAL_CRATE).then_some(()) - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } } -impl Key for OwnerId { - type CacheSelector = VecCacheSelector; - type LocalKey = Self; +impl AsLocalKey for CrateNum { + type LocalKey = (); #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) + fn as_local_key(&self) -> Option { + (*self == LOCAL_CRATE).then_some(()) } +} + +impl Key for OwnerId { + type CacheSelector = VecCacheSelector; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.to_def_id().default_span(tcx) @@ -165,12 +137,6 @@ impl Key for OwnerId { impl Key for LocalDefId { type CacheSelector = VecCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.to_def_id().default_span(tcx) @@ -183,12 +149,6 @@ impl Key for LocalDefId { impl Key for DefId { type CacheSelector = DefaultCacheSelector; - type LocalKey = LocalDefId; - - #[inline(always)] - fn as_local_key(&self) -> Option { - self.as_local() - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(*self) @@ -200,14 +160,17 @@ impl Key for DefId { } } -impl Key for ty::WithOptConstParam { - type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; +impl AsLocalKey for DefId { + type LocalKey = LocalDefId; #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) + fn as_local_key(&self) -> Option { + self.as_local() } +} + +impl Key for ty::WithOptConstParam { + type CacheSelector = DefaultCacheSelector; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.did.default_span(tcx) @@ -216,12 +179,6 @@ impl Key for ty::WithOptConstParam { impl Key for SimplifiedType { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -230,12 +187,6 @@ impl Key for SimplifiedType { impl Key for (DefId, DefId) { type CacheSelector = DefaultCacheSelector; - type LocalKey = (LocalDefId, DefId); - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some((self.0.as_local()?, self.1)) - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.1.default_span(tcx) @@ -244,12 +195,6 @@ impl Key for (DefId, DefId) { impl<'tcx> Key for (ty::Instance<'tcx>, LocalDefId) { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) @@ -258,12 +203,6 @@ impl<'tcx> Key for (ty::Instance<'tcx>, LocalDefId) { impl Key for (DefId, LocalDefId) { type CacheSelector = DefaultCacheSelector; - type LocalKey = (LocalDefId, LocalDefId); - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some((self.0.as_local()?, self.1)) - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.1.default_span(tcx) @@ -272,12 +211,6 @@ impl Key for (DefId, LocalDefId) { impl Key for (LocalDefId, DefId) { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) @@ -286,12 +219,6 @@ impl Key for (LocalDefId, DefId) { impl Key for (LocalDefId, LocalDefId) { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) @@ -300,11 +227,6 @@ impl Key for (LocalDefId, LocalDefId) { impl Key for (DefId, Option) { type CacheSelector = DefaultCacheSelector; - type LocalKey = (LocalDefId, Option); - - fn as_local_key(&self) -> Option { - Some((self.0.as_local()?, self.1)) - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.0) @@ -318,11 +240,6 @@ impl Key for (DefId, Option) { impl Key for (LocalDefId, LocalDefId, Ident) { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.1.default_span(tcx) @@ -331,40 +248,40 @@ impl Key for (LocalDefId, LocalDefId, Ident) { impl Key for (CrateNum, DefId) { type CacheSelector = DefaultCacheSelector; - type LocalKey = DefId; - - #[inline(always)] - fn as_local_key(&self) -> Option { - (self.0 == LOCAL_CRATE).then_some(self.1) - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.1.default_span(tcx) } } -impl Key for (CrateNum, SimplifiedType) { - type CacheSelector = DefaultCacheSelector; - type LocalKey = SimplifiedType; +impl AsLocalKey for (CrateNum, DefId) { + type LocalKey = DefId; #[inline(always)] fn as_local_key(&self) -> Option { - (self.0 == LOCAL_CRATE).then_some(self.1) + (self.0 == LOCAL_CRATE).then(|| self.1) } +} + +impl Key for (CrateNum, SimplifiedType) { + type CacheSelector = DefaultCacheSelector; fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } } -impl Key for (DefId, SimplifiedType) { - type CacheSelector = DefaultCacheSelector; - type LocalKey = (LocalDefId, SimplifiedType); +impl AsLocalKey for (CrateNum, SimplifiedType) { + type LocalKey = SimplifiedType; #[inline(always)] fn as_local_key(&self) -> Option { - Some((self.0.as_local()?, self.1)) + (self.0 == LOCAL_CRATE).then(|| self.1) } +} + +impl Key for (DefId, SimplifiedType) { + type CacheSelector = DefaultCacheSelector; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) @@ -373,12 +290,6 @@ impl Key for (DefId, SimplifiedType) { impl<'tcx> Key for SubstsRef<'tcx> { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -387,12 +298,6 @@ impl<'tcx> Key for SubstsRef<'tcx> { impl<'tcx> Key for (DefId, SubstsRef<'tcx>) { type CacheSelector = DefaultCacheSelector; - type LocalKey = (LocalDefId, SubstsRef<'tcx>); - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some((self.0.as_local()?, self.1)) - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) @@ -401,12 +306,6 @@ impl<'tcx> Key for (DefId, SubstsRef<'tcx>) { impl<'tcx> Key for (ty::UnevaluatedConst<'tcx>, ty::UnevaluatedConst<'tcx>) { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - self.0.def.is_local().then_some(*self) - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { (self.0).def.did.default_span(tcx) @@ -415,12 +314,6 @@ impl<'tcx> Key for (ty::UnevaluatedConst<'tcx>, ty::UnevaluatedConst<'tcx>) { impl<'tcx> Key for (LocalDefId, DefId, SubstsRef<'tcx>) { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) @@ -429,12 +322,6 @@ impl<'tcx> Key for (LocalDefId, DefId, SubstsRef<'tcx>) { impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - self.1.def_id().is_local().then_some(*self) - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.1.def_id()) @@ -443,12 +330,6 @@ impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) { impl<'tcx> Key for (ty::Const<'tcx>, mir::Field) { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -457,12 +338,6 @@ impl<'tcx> Key for (ty::Const<'tcx>, mir::Field) { impl<'tcx> Key for mir::interpret::ConstAlloc<'tcx> { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -471,12 +346,6 @@ impl<'tcx> Key for mir::interpret::ConstAlloc<'tcx> { impl<'tcx> Key for ty::PolyTraitRef<'tcx> { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - self.def_id().is_local().then_some(*self) - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.def_id()) @@ -485,12 +354,6 @@ impl<'tcx> Key for ty::PolyTraitRef<'tcx> { impl<'tcx> Key for ty::PolyExistentialTraitRef<'tcx> { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - self.def_id().is_local().then_some(*self) - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.def_id()) @@ -499,12 +362,6 @@ impl<'tcx> Key for ty::PolyExistentialTraitRef<'tcx> { impl<'tcx> Key for (ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>) { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - self.0.def_id().is_local().then_some(*self) - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.0.def_id()) @@ -513,12 +370,6 @@ impl<'tcx> Key for (ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>) { impl<'tcx> Key for GenericArg<'tcx> { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -527,12 +378,6 @@ impl<'tcx> Key for GenericArg<'tcx> { impl<'tcx> Key for mir::ConstantKind<'tcx> { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -541,12 +386,6 @@ impl<'tcx> Key for mir::ConstantKind<'tcx> { impl<'tcx> Key for ty::Const<'tcx> { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -555,12 +394,6 @@ impl<'tcx> Key for ty::Const<'tcx> { impl<'tcx> Key for Ty<'tcx> { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -576,12 +409,6 @@ impl<'tcx> Key for Ty<'tcx> { impl<'tcx> Key for TyAndLayout<'tcx> { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -590,12 +417,6 @@ impl<'tcx> Key for TyAndLayout<'tcx> { impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -604,12 +425,6 @@ impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) { impl<'tcx> Key for &'tcx ty::List> { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -618,12 +433,6 @@ impl<'tcx> Key for &'tcx ty::List> { impl<'tcx> Key for ty::ParamEnv<'tcx> { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -632,11 +441,6 @@ impl<'tcx> Key for ty::ParamEnv<'tcx> { impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> { type CacheSelector = DefaultCacheSelector; - type LocalKey = ty::ParamEnvAnd<'tcx, T::LocalKey>; - - fn as_local_key(&self) -> Option { - self.value.as_local_key().map(|value| ty::ParamEnvAnd { param_env: self.param_env, value }) - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.value.default_span(tcx) @@ -645,12 +449,6 @@ impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> { impl Key for Symbol { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP @@ -659,12 +457,6 @@ impl Key for Symbol { impl Key for Option { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP @@ -675,12 +467,6 @@ impl Key for Option { /// are not tied to any crate in particular. impl<'tcx, T: Clone> Key for Canonical<'tcx, T> { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(self.clone()) - } fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP @@ -689,12 +475,6 @@ impl<'tcx, T: Clone> Key for Canonical<'tcx, T> { impl Key for (Symbol, u32, u32) { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP @@ -703,12 +483,6 @@ impl Key for (Symbol, u32, u32) { impl<'tcx> Key for (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>) { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP @@ -717,12 +491,6 @@ impl<'tcx> Key for (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>) { impl<'tcx> Key for (ty::Predicate<'tcx>, traits::WellFormedLoc) { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP @@ -731,12 +499,6 @@ impl<'tcx> Key for (ty::Predicate<'tcx>, traits::WellFormedLoc) { impl<'tcx> Key for (ty::PolyFnSig<'tcx>, &'tcx ty::List>) { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -745,12 +507,6 @@ impl<'tcx> Key for (ty::PolyFnSig<'tcx>, &'tcx ty::List>) { impl<'tcx> Key for (ty::Instance<'tcx>, &'tcx ty::List>) { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) @@ -759,12 +515,6 @@ impl<'tcx> Key for (ty::Instance<'tcx>, &'tcx ty::List>) { impl<'tcx> Key for (Ty<'tcx>, ty::ValTree<'tcx>) { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -773,12 +523,6 @@ impl<'tcx> Key for (Ty<'tcx>, ty::ValTree<'tcx>) { impl Key for HirId { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; - - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.hir().span(*self) @@ -792,13 +536,8 @@ impl Key for HirId { impl<'tcx> Key for (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>) { type CacheSelector = DefaultCacheSelector; - type LocalKey = Self; // Just forward to `Ty<'tcx>` - #[inline(always)] - fn as_local_key(&self) -> Option { - Some(*self) - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 13f6779bd4fa..f5cbfd6623e3 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -8,7 +8,7 @@ use crate::ty::{self, print::describe_as_module, TyCtxt}; use rustc_span::def_id::LOCAL_CRATE; mod keys; -pub use keys::Key; +pub use keys::{AsLocalKey, Key}; // Each of these queries corresponds to a function pointer field in the // `Providers` struct for requesting a value of that type, and a method @@ -796,7 +796,6 @@ rustc_queries! { query associated_type_for_impl_trait_in_trait(opaque_ty_def_id: LocalDefId) -> LocalDefId { desc { |tcx| "creates the associated item corresponding to the opaque type `{}`", tcx.def_path_str(opaque_ty_def_id.to_def_id()) } cache_on_disk_if { true } - separate_provide_extern } /// Given an `impl_id`, return the trait it implements. diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 3cf28408f690..2771d713c420 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -17,7 +17,7 @@ use crate::mir::interpret::{ }; use crate::mir::interpret::{LitToConstError, LitToConstInput}; use crate::mir::mono::CodegenUnit; -use crate::query::Key; +use crate::query::{AsLocalKey, Key}; use crate::thir; use crate::traits::query::{ CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, @@ -233,7 +233,7 @@ macro_rules! define_callbacks { pub mod query_keys_local { use super::*; - $(pub type $name<'tcx> = <$($K)* as Key>::LocalKey;)* + $(pub type $name<'tcx> = <$($K)* as AsLocalKey>::LocalKey;)* } #[allow(nonstandard_style, unused_lifetimes)] pub mod query_values { @@ -416,17 +416,14 @@ macro_rules! define_callbacks { impl Default for Providers { fn default() -> Self { - use crate::query::Key; - Providers { $($name: |_, key| bug!( - "`tcx.{}({:?})` is not supported for {} crate;\n\ + "`tcx.{}({:?})` is not supported for this key;\n\ hint: Queries can be either made to the local crate, or the external crate. \ This error means you tried to use it for one that's not supported.\n\ If that's not the case, {} was likely never assigned to a provider function.\n", stringify!($name), key, - if key.as_local_key().is_some() { "local" } else { "external" }, stringify!($name), ),)* } diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 035bfe978f20..4cd942370610 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -20,7 +20,7 @@ extern crate rustc_middle; use rustc_data_structures::sync::AtomicU64; use rustc_middle::arena::Arena; use rustc_middle::dep_graph::{self, DepKindStruct}; -use rustc_middle::query::Key; +use rustc_middle::query::AsLocalKey; use rustc_middle::ty::query::{ query_keys, query_provided, query_provided_to_value, query_storage, query_values, }; From d213114cb5ad5bb525e88ec2d2f8e934f8a8f8b8 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 13 Mar 2023 22:22:59 +0000 Subject: [PATCH 64/70] LocalCrate key --- compiler/rustc_codegen_ssa/src/back/symbol_export.rs | 5 +++-- .../rustc_metadata/src/rmeta/decoder/cstore_impl.rs | 11 ++++++----- compiler/rustc_metadata/src/rmeta/encoder.rs | 5 +++-- compiler/rustc_middle/src/hir/map/mod.rs | 3 ++- compiler/rustc_middle/src/query/keys.rs | 8 ++++++-- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 7 ++++--- compiler/rustc_mir_transform/src/ffi_unwind_calls.rs | 3 ++- compiler/rustc_passes/src/debugger_visualizer.rs | 4 ++-- compiler/rustc_passes/src/diagnostic_items.rs | 3 ++- src/tools/miri/src/bin/miri.rs | 3 ++- 11 files changed, 33 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 3380864fbb2a..e403a1fd8ae7 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -10,6 +10,7 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::exported_symbols::{ metadata_symbol_name, ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel, }; +use rustc_middle::query::LocalCrate; use rustc_middle::ty::query::{ExternProviders, Providers}; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; use rustc_middle::ty::Instance; @@ -41,7 +42,7 @@ pub fn crates_export_threshold(crate_types: &[CrateType]) -> SymbolExportLevel { } } -fn reachable_non_generics_provider(tcx: TyCtxt<'_>, (): ()) -> DefIdMap { +fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap { if !tcx.sess.opts.output_types.should_codegen() { return Default::default(); } @@ -168,7 +169,7 @@ fn is_reachable_non_generic_provider_extern(tcx: TyCtxt<'_>, def_id: DefId) -> b fn exported_symbols_provider_local( tcx: TyCtxt<'_>, - (): (), + _: LocalCrate, ) -> &[(ExportedSymbol<'_>, SymbolExportInfo)] { if !tcx.sess.opts.output_types.should_codegen() { return &[]; diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 2da075221db6..9661e815623d 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -13,6 +13,7 @@ use rustc_middle::arena::ArenaAllocatable; use rustc_middle::metadata::ModChild; use rustc_middle::middle::exported_symbols::ExportedSymbol; use rustc_middle::middle::stability::DeprecationEntry; +use rustc_middle::query::LocalCrate; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::query::{ExternProviders, Providers}; use rustc_middle::ty::{self, TyCtxt}; @@ -367,7 +368,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { *providers = Providers { allocator_kind: |tcx, ()| CStore::from_tcx(tcx).allocator_kind(), alloc_error_handler_kind: |tcx, ()| CStore::from_tcx(tcx).alloc_error_handler_kind(), - is_private_dep: |_tcx, ()| false, + is_private_dep: |_tcx, LocalCrate| false, native_library: |tcx, id| { tcx.native_libraries(id.krate) .iter() @@ -383,8 +384,8 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { .contains(&id) }) }, - native_libraries: |tcx, ()| native_libs::collect(tcx), - foreign_modules: |tcx, ()| { + native_libraries: |tcx, LocalCrate| native_libs::collect(tcx), + foreign_modules: |tcx, LocalCrate| { foreign_modules::collect(tcx).into_iter().map(|m| (m.def_id, m)).collect() }, @@ -482,8 +483,8 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { }, dependency_formats: |tcx, ()| Lrc::new(crate::dependency_format::calculate(tcx)), - has_global_allocator: |tcx, ()| CStore::from_tcx(tcx).has_global_allocator(), - has_alloc_error_handler: |tcx, ()| CStore::from_tcx(tcx).has_alloc_error_handler(), + has_global_allocator: |tcx, LocalCrate| CStore::from_tcx(tcx).has_global_allocator(), + has_alloc_error_handler: |tcx, LocalCrate| CStore::from_tcx(tcx).has_alloc_error_handler(), postorder_cnums: |tcx, ()| { tcx.arena .alloc_slice(&CStore::from_tcx(tcx).crate_dependencies_in_postorder(LOCAL_CRATE)) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 97ac3eccae7b..ef3eda584e1b 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -24,6 +24,7 @@ use rustc_middle::middle::exported_symbols::{ metadata_symbol_name, ExportedSymbol, SymbolExportInfo, }; use rustc_middle::mir::interpret; +use rustc_middle::query::LocalCrate; use rustc_middle::traits::specialization_graph; use rustc_middle::ty::codec::TyEncoder; use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams, TreatProjections}; @@ -2240,7 +2241,7 @@ pub fn provide(providers: &mut Providers) { .get(&def_id) .expect("no traits in scope for a doc link") }, - traits_in_crate: |tcx, ()| { + traits_in_crate: |tcx, LocalCrate| { let mut traits = Vec::new(); for id in tcx.hir().items() { if matches!(tcx.def_kind(id.owner_id), DefKind::Trait | DefKind::TraitAlias) { @@ -2252,7 +2253,7 @@ pub fn provide(providers: &mut Providers) { traits.sort_by_cached_key(|&def_id| tcx.def_path_hash(def_id)); tcx.arena.alloc_slice(&traits) }, - trait_impls_in_crate: |tcx, ()| { + trait_impls_in_crate: |tcx, LocalCrate| { let mut trait_impls = Vec::new(); for id in tcx.hir().items() { if matches!(tcx.def_kind(id.owner_id), DefKind::Impl { .. }) diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index d877a2c54942..b2bae47054cc 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1,4 +1,5 @@ use crate::hir::{ModuleItems, Owner}; +use crate::query::LocalCrate; use crate::ty::TyCtxt; use rustc_ast as ast; use rustc_data_structures::fingerprint::Fingerprint; @@ -1131,7 +1132,7 @@ impl<'hir> intravisit::Map<'hir> for Map<'hir> { } } -pub(super) fn crate_hash(tcx: TyCtxt<'_>, (): ()) -> Svh { +pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh { let krate = tcx.hir_crate(()); let hir_body_hash = krate.opt_hir_hash.expect("HIR hash missing while computing crate hash"); diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index f161f61d53e7..ca65fbc2fd47 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -13,6 +13,10 @@ use rustc_query_system::query::{DefaultCacheSelector, SingleCacheSelector, VecCa use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; +/// Placeholder for `CrateNum`'s "local" counterpart +#[derive(Copy, Clone, Debug)] +pub struct LocalCrate; + /// The `Key` trait controls what types can legally be used as the key /// for a query. pub trait Key: Sized { @@ -115,11 +119,11 @@ impl Key for CrateNum { } impl AsLocalKey for CrateNum { - type LocalKey = (); + type LocalKey = LocalCrate; #[inline(always)] fn as_local_key(&self) -> Option { - (*self == LOCAL_CRATE).then_some(()) + (*self == LOCAL_CRATE).then_some(LocalCrate) } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index f5cbfd6623e3..f740ec51080a 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -8,7 +8,7 @@ use crate::ty::{self, print::describe_as_module, TyCtxt}; use rustc_span::def_id::LOCAL_CRATE; mod keys; -pub use keys::{AsLocalKey, Key}; +pub use keys::{AsLocalKey, Key, LocalCrate}; // Each of these queries corresponds to a function pointer field in the // `Providers` struct for requesting a value of that type, and a method diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 23ac99d3397e..653763353987 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -15,6 +15,7 @@ use crate::mir::interpret::{self, Allocation, ConstAllocation}; use crate::mir::{ Body, BorrowCheckResult, Field, Local, Place, PlaceElem, ProjectionKind, Promoted, }; +use crate::query::LocalCrate; use crate::thir::Thir; use crate::traits; use crate::traits::solve; @@ -2519,10 +2520,10 @@ pub fn provide(providers: &mut ty::query::Providers) { providers.extern_mod_stmt_cnum = |tcx, id| tcx.resolutions(()).extern_crate_map.get(&id).cloned(); providers.is_panic_runtime = - |tcx, ()| tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::panic_runtime); + |tcx, LocalCrate| tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::panic_runtime); providers.is_compiler_builtins = - |tcx, ()| tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins); - providers.has_panic_handler = |tcx, ()| { + |tcx, LocalCrate| tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins); + providers.has_panic_handler = |tcx, LocalCrate| { // We want to check if the panic handler was defined in this crate tcx.lang_items().panic_impl().map_or(false, |did| did.is_local()) }; diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs index 1a9b1b8090b8..c9b24adba0ca 100644 --- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs +++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs @@ -1,5 +1,6 @@ use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE}; use rustc_middle::mir::*; +use rustc_middle::query::LocalCrate; use rustc_middle::ty::layout; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt}; @@ -121,7 +122,7 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool { tainted } -fn required_panic_strategy(tcx: TyCtxt<'_>, (): ()) -> Option { +fn required_panic_strategy(tcx: TyCtxt<'_>, _: LocalCrate) -> Option { if tcx.is_panic_runtime(LOCAL_CRATE) { return Some(tcx.sess.panic_strategy()); } diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs index 9c7a3605d080..9dd39a5c9fe0 100644 --- a/compiler/rustc_passes/src/debugger_visualizer.rs +++ b/compiler/rustc_passes/src/debugger_visualizer.rs @@ -5,8 +5,8 @@ use rustc_data_structures::fx::FxHashSet; use rustc_expand::base::resolve_path; use rustc_hir as hir; use rustc_hir::HirId; -use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; +use rustc_middle::{query::LocalCrate, ty::query::Providers}; use rustc_span::{sym, DebuggerVisualizerFile, DebuggerVisualizerType}; use std::sync::Arc; @@ -67,7 +67,7 @@ fn check_for_debugger_visualizer( } /// Traverses and collects the debugger visualizers for a specific crate. -fn debugger_visualizers(tcx: TyCtxt<'_>, (): ()) -> Vec { +fn debugger_visualizers(tcx: TyCtxt<'_>, _: LocalCrate) -> Vec { // Initialize the collector. let mut debugger_visualizers = FxHashSet::default(); diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs index b74fad66c0f0..eb6ea673c85d 100644 --- a/compiler/rustc_passes/src/diagnostic_items.rs +++ b/compiler/rustc_passes/src/diagnostic_items.rs @@ -12,6 +12,7 @@ use rustc_ast as ast; use rustc_hir::diagnostic_items::DiagnosticItems; use rustc_hir::OwnerId; +use rustc_middle::query::LocalCrate; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::{DefId, LOCAL_CRATE}; @@ -62,7 +63,7 @@ fn extract(attrs: &[ast::Attribute]) -> Option { } /// Traverse and collect the diagnostic items in the current -fn diagnostic_items(tcx: TyCtxt<'_>, (): ()) -> DiagnosticItems { +fn diagnostic_items(tcx: TyCtxt<'_>, _: LocalCrate) -> DiagnosticItems { // Initialize the collector. let mut diagnostic_items = DiagnosticItems::default(); diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index b6f6ac10fd77..0aea105ccc49 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -29,6 +29,7 @@ use rustc_middle::{ ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel, }, ty::{query::ExternProviders, TyCtxt}, + query::LocalCrate, }; use rustc_session::{config::CrateType, search_paths::PathKind, CtfeBacktrace}; @@ -107,7 +108,7 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { config.override_queries = Some(|_, local_providers, _| { // `exported_symbols` and `reachable_non_generics` provided by rustc always returns // an empty result if `tcx.sess.opts.output_types.should_codegen()` is false. - local_providers.exported_symbols = |tcx, ()| { + local_providers.exported_symbols = |tcx, LocalCrate| { let reachable_set = tcx.with_stable_hashing_context(|hcx| { tcx.reachable_set(()).to_sorted(&hcx, true) }); From b1a957b0b922aa2ec2d1763f231915dcb58401d9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 18 Mar 2023 19:40:00 +0000 Subject: [PATCH 65/70] query_keys_local is conditional on separate_provide_if_extern --- compiler/rustc_middle/src/ty/query.rs | 29 +++++++++++++-------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 2771d713c420..30246fe4dbeb 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -151,21 +151,17 @@ macro_rules! query_if_arena { }; } -macro_rules! separate_provide_local_decl { - ([][$name:ident]) => { - for<'tcx> fn( - TyCtxt<'tcx>, - query_keys::$name<'tcx>, - ) -> query_provided::$name<'tcx> +/// If `separate_provide_if_extern`, then the key can be projected to its +/// local key via `<$K as AsLocalKey>::LocalKey`. +macro_rules! local_key_if_separate_extern { + ([] $($K:tt)*) => { + $($K)* }; - ([(separate_provide_extern) $($rest:tt)*][$name:ident]) => { - for<'tcx> fn( - TyCtxt<'tcx>, - query_keys_local::$name<'tcx>, - ) -> query_provided::$name<'tcx> + ([(separate_provide_extern) $($rest:tt)*] $($K:tt)*) => { + <$($K)* as AsLocalKey>::LocalKey }; - ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => { - separate_provide_local_decl!([$($modifiers)*][$($args)*]) + ([$other:tt $($modifiers:tt)*] $($K:tt)*) => { + local_key_if_separate_extern!([$($modifiers)*] $($K)*) }; } @@ -233,7 +229,7 @@ macro_rules! define_callbacks { pub mod query_keys_local { use super::*; - $(pub type $name<'tcx> = <$($K)* as AsLocalKey>::LocalKey;)* + $(pub type $name<'tcx> = local_key_if_separate_extern!([$($modifiers)*] $($K)*);)* } #[allow(nonstandard_style, unused_lifetimes)] pub mod query_values { @@ -407,7 +403,10 @@ macro_rules! define_callbacks { } pub struct Providers { - $(pub $name: separate_provide_local_decl!([$($modifiers)*][$name]),)* + $(pub $name: for<'tcx> fn( + TyCtxt<'tcx>, + query_keys_local::$name<'tcx>, + ) -> query_provided::$name<'tcx>,)* } pub struct ExternProviders { From 3b04ad2753d5ace0e8ef17d3625a78b37b2cb500 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 21 Mar 2023 12:01:51 -0300 Subject: [PATCH 66/70] Do not suggest bounds restrictions for synthesized RPITITs --- .../src/traits/error_reporting/suggestions.rs | 1 + ...derr => missing-send-bound.current.stderr} | 8 ++--- .../in-trait/missing-send-bound.next.stderr | 29 +++++++++++++++++++ .../in-trait/missing-send-bound.rs | 2 ++ 4 files changed, 36 insertions(+), 4 deletions(-) rename tests/ui/async-await/in-trait/{missing-send-bound.stderr => missing-send-bound.current.stderr} (87%) create mode 100644 tests/ui/async-await/in-trait/missing-send-bound.next.stderr diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 186bfc701bc4..b501840b9260 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -420,6 +420,7 @@ fn suggest_restriction<'tcx>( ) { if hir_generics.where_clause_span.from_expansion() || hir_generics.where_clause_span.desugaring_kind().is_some() + || projection.map_or(false, |projection| tcx.opt_rpitit_info(projection.def_id).is_some()) { return; } diff --git a/tests/ui/async-await/in-trait/missing-send-bound.stderr b/tests/ui/async-await/in-trait/missing-send-bound.current.stderr similarity index 87% rename from tests/ui/async-await/in-trait/missing-send-bound.stderr rename to tests/ui/async-await/in-trait/missing-send-bound.current.stderr index 5cedf3ddb0f6..319ed582e271 100644 --- a/tests/ui/async-await/in-trait/missing-send-bound.stderr +++ b/tests/ui/async-await/in-trait/missing-send-bound.current.stderr @@ -1,5 +1,5 @@ warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/missing-send-bound.rs:3:12 + --> $DIR/missing-send-bound.rs:5:12 | LL | #![feature(async_fn_in_trait)] | ^^^^^^^^^^^^^^^^^ @@ -8,19 +8,19 @@ LL | #![feature(async_fn_in_trait)] = note: `#[warn(incomplete_features)]` on by default error: future cannot be sent between threads safely - --> $DIR/missing-send-bound.rs:15:20 + --> $DIR/missing-send-bound.rs:17:20 | LL | assert_is_send(test::()); | ^^^^^^^^^^^ future returned by `test` is not `Send` | = help: within `impl Future`, the trait `Send` is not implemented for `impl Future` note: future is not `Send` as it awaits another future which is not `Send` - --> $DIR/missing-send-bound.rs:11:5 + --> $DIR/missing-send-bound.rs:13:5 | LL | T::bar().await; | ^^^^^^^^ await occurs here on type `impl Future`, which is not `Send` note: required by a bound in `assert_is_send` - --> $DIR/missing-send-bound.rs:19:27 + --> $DIR/missing-send-bound.rs:21:27 | LL | fn assert_is_send(_: impl Send) {} | ^^^^ required by this bound in `assert_is_send` diff --git a/tests/ui/async-await/in-trait/missing-send-bound.next.stderr b/tests/ui/async-await/in-trait/missing-send-bound.next.stderr new file mode 100644 index 000000000000..319ed582e271 --- /dev/null +++ b/tests/ui/async-await/in-trait/missing-send-bound.next.stderr @@ -0,0 +1,29 @@ +warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/missing-send-bound.rs:5:12 + | +LL | #![feature(async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #91611 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: future cannot be sent between threads safely + --> $DIR/missing-send-bound.rs:17:20 + | +LL | assert_is_send(test::()); + | ^^^^^^^^^^^ future returned by `test` is not `Send` + | + = help: within `impl Future`, the trait `Send` is not implemented for `impl Future` +note: future is not `Send` as it awaits another future which is not `Send` + --> $DIR/missing-send-bound.rs:13:5 + | +LL | T::bar().await; + | ^^^^^^^^ await occurs here on type `impl Future`, which is not `Send` +note: required by a bound in `assert_is_send` + --> $DIR/missing-send-bound.rs:21:27 + | +LL | fn assert_is_send(_: impl Send) {} + | ^^^^ required by this bound in `assert_is_send` + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/ui/async-await/in-trait/missing-send-bound.rs b/tests/ui/async-await/in-trait/missing-send-bound.rs index 78922b59b27b..705fcf322f9e 100644 --- a/tests/ui/async-await/in-trait/missing-send-bound.rs +++ b/tests/ui/async-await/in-trait/missing-send-bound.rs @@ -1,4 +1,6 @@ // edition:2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait)] //~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes From 30cef3a292343354ba30c30fc845a16a70ac6933 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Tue, 21 Mar 2023 23:49:04 +0800 Subject: [PATCH 67/70] Update cargo --- Cargo.lock | 4 ++-- src/tools/cargo | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 61f2cfb9e22c..2b08aab41edd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1128,9 +1128,9 @@ dependencies = [ [[package]] name = "curl-sys" -version = "0.4.59+curl-7.86.0" +version = "0.4.61+curl-8.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cfce34829f448b08f55b7db6d0009e23e2e86a34e8c2b366269bf5799b4a407" +checksum = "14d05c10f541ae6f3bc5b3d923c20001f47db7d5f0b2bc6ad16490133842db79" dependencies = [ "cc", "libc", diff --git a/src/tools/cargo b/src/tools/cargo index 4a3c588b1f0a..15d090969743 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 4a3c588b1f0a8e2dc8dd8789dbf3b6a71b02ed49 +Subproject commit 15d090969743630bff549a1b068bcaa8174e5ee3 From e7ab0629ecf320f19eb86cbb0b65dbbd6f597bb6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 22 Mar 2023 16:40:08 +0100 Subject: [PATCH 68/70] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index e11b055b8139..e267b08d0829 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -84c47b8279b39e165dfebeb529eb6d92592e4f8d +439292bc7913399e406d9bb7e8da0f70c6317c6e From 72c917d4be2dfb53c01466335175ed69eba9b5ad Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun, 26 Mar 2023 18:55:37 +0200 Subject: [PATCH 69/70] debuginfo: Get pointer size/align from tcx.data_layout instead of layout_of This avoids some type interning and a query execution. It also just makes the code simpler. --- compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index c1b3f34e5a6d..e2a592d851a8 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -176,15 +176,14 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( return_if_di_node_created_in_meantime!(cx, unique_type_id); - let (thin_pointer_size, thin_pointer_align) = - cx.size_and_align_of(cx.tcx.mk_imm_ptr(cx.tcx.types.unit)); + let data_layout = &cx.tcx.data_layout; let ptr_type_debuginfo_name = compute_debuginfo_type_name(cx.tcx, ptr_type, true); match fat_pointer_kind(cx, pointee_type) { None => { // This is a thin pointer. Create a regular pointer type and give it the correct name. debug_assert_eq!( - (thin_pointer_size, thin_pointer_align), + (data_layout.pointer_size, data_layout.pointer_align.abi), cx.size_and_align_of(ptr_type), "ptr_type={}, pointee_type={}", ptr_type, @@ -195,8 +194,8 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( llvm::LLVMRustDIBuilderCreatePointerType( DIB(cx), pointee_type_di_node, - thin_pointer_size.bits(), - thin_pointer_align.bits() as u32, + data_layout.pointer_size.bits(), + data_layout.pointer_align.abi.bits() as u32, 0, // Ignore DWARF address space. ptr_type_debuginfo_name.as_ptr().cast(), ptr_type_debuginfo_name.len(), From 4f8534f446a6c55d5d53e72e4940ad35e9e0d50e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 22 Mar 2023 17:23:23 +0100 Subject: [PATCH 70/70] fmt --- src/tools/miri/src/bin/miri.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index c9c11fde542d..26a7ead2407c 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -28,8 +28,8 @@ use rustc_middle::{ middle::exported_symbols::{ ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel, }, - ty::{query::ExternProviders, TyCtxt}, query::LocalCrate, + ty::{query::ExternProviders, TyCtxt}, }; use rustc_session::config::OptLevel;