diff options
227 files changed, 5029 insertions, 3803 deletions
diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index a34ec44566b..a8c00c8c3ca 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -47,7 +47,7 @@ fn main() { }; let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set"); let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set"); - let on_fail = env::var_os("RUSTC_ON_FAIL").map(|of| Command::new(of)); + let on_fail = env::var_os("RUSTC_ON_FAIL").map(Command::new); let rustc = env::var_os(rustc).unwrap_or_else(|| panic!("{:?} was not set", rustc)); let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{:?} was not set", libdir)); @@ -64,7 +64,7 @@ fn main() { if let Some(crate_name) = crate_name { if let Some(target) = env::var_os("RUSTC_TIME") { if target == "all" - || target.into_string().unwrap().split(",").any(|c| c.trim() == crate_name) + || target.into_string().unwrap().split(',').any(|c| c.trim() == crate_name) { cmd.arg("-Ztime"); } @@ -189,7 +189,7 @@ fn main() { crate_name, is_test, dur.as_secs(), - dur.subsec_nanos() / 1_000_000 + dur.subsec_millis() ); match status.code() { diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index 8c8b33a4e4e..04345867bf5 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/bin/rustdoc.rs @@ -61,7 +61,7 @@ fn main() { } // Needed to be able to run all rustdoc tests. - if let Some(_) = env::var_os("RUSTDOC_GENERATE_REDIRECT_PAGES") { + if env::var_os("RUSTDOC_GENERATE_REDIRECT_PAGES").is_some() { // This "unstable-options" can be removed when `--generate-redirect-pages` is stabilized if !has_unstable { cmd.arg("-Z").arg("unstable-options"); diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index d9c894aa9c6..18f6fda7608 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -510,7 +510,7 @@ impl<'a> Builder<'a> { Subcommand::Format { .. } | Subcommand::Clean { .. } => panic!(), }; - let builder = Builder { + Builder { build, top_stage: build.config.stage.unwrap_or(2), kind, @@ -518,9 +518,7 @@ impl<'a> Builder<'a> { stack: RefCell::new(Vec::new()), time_spent_on_dependencies: Cell::new(Duration::new(0, 0)), paths: paths.to_owned(), - }; - - builder + } } pub fn execute_cli(&self) { @@ -753,13 +751,12 @@ impl<'a> Builder<'a> { cargo.env("RUST_CHECK", "1"); } - let stage; - if compiler.stage == 0 && self.local_rebuild { + let stage = if compiler.stage == 0 && self.local_rebuild { // Assume the local-rebuild rustc already has stage1 features. - stage = 1; + 1 } else { - stage = compiler.stage; - } + compiler.stage + }; let mut rustflags = Rustflags::new(&target); if stage != 0 { @@ -1252,12 +1249,7 @@ impl<'a> Builder<'a> { }; if self.config.print_step_timings && dur > Duration::from_millis(100) { - println!( - "[TIMING] {:?} -- {}.{:03}", - step, - dur.as_secs(), - dur.subsec_nanos() / 1_000_000 - ); + println!("[TIMING] {:?} -- {}.{:03}", step, dur.as_secs(), dur.subsec_millis()); } { @@ -1302,7 +1294,7 @@ impl Rustflags { fn arg(&mut self, arg: &str) -> &mut Self { assert_eq!(arg.split_whitespace().count(), 1); - if self.0.len() > 0 { + if !self.0.is_empty() { self.0.push_str(" "); } self.0.push_str(arg); diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index 5fefb972866..cca8ab80c93 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -19,7 +19,6 @@ fn configure(host: &[&str], target: &[&str]) -> Config { config.out = dir; config.build = INTERNER.intern_str("A"); config.hosts = vec![config.build] - .clone() .into_iter() .chain(host.iter().map(|s| INTERNER.intern_str(s))) .collect::<Vec<_>>(); diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index eced03506ab..7dded96e18e 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -18,7 +18,6 @@ use std::str; use build_helper::{output, t, up_to_date}; use filetime::FileTime; use serde::Deserialize; -use serde_json; use crate::builder::Cargo; use crate::dist; @@ -149,7 +148,8 @@ fn copy_third_party_objects( // which is provided by std for this target. if target == "x86_64-fortanix-unknown-sgx" { let src_path_env = "X86_FORTANIX_SGX_LIBS"; - let src = env::var(src_path_env).expect(&format!("{} not found in env", src_path_env)); + let src = + env::var(src_path_env).unwrap_or_else(|_| panic!("{} not found in env", src_path_env)); copy_and_stamp(Path::new(&src), "libunwind.a"); } @@ -361,7 +361,7 @@ impl Step for StartupObjects { ); } - let target = sysroot_dir.join(file.to_string() + ".o"); + let target = sysroot_dir.join((*file).to_string() + ".o"); builder.copy(dst_file, &target); target_deps.push(target); } @@ -515,7 +515,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: Interne .env("CFG_VERSION", builder.rust_version()) .env("CFG_PREFIX", builder.config.prefix.clone().unwrap_or_default()); - let libdir_relative = builder.config.libdir_relative().unwrap_or(Path::new("lib")); + let libdir_relative = builder.config.libdir_relative().unwrap_or_else(|| Path::new("lib")); cargo.env("CFG_LIBDIR_RELATIVE", libdir_relative); if let Some(ref ver_date) = builder.rust_info.commit_date() { @@ -843,11 +843,11 @@ pub fn run_cargo( }; for filename in filenames { // Skip files like executables - if !filename.ends_with(".rlib") - && !filename.ends_with(".lib") - && !filename.ends_with(".a") - && !is_dylib(&filename) - && !(is_check && filename.ends_with(".rmeta")) + if !(filename.ends_with(".rlib") + || filename.ends_with(".lib") + || filename.ends_with(".a") + || is_dylib(&filename) + || (is_check && filename.ends_with(".rmeta"))) { continue; } @@ -905,7 +905,7 @@ pub fn run_cargo( for (prefix, extension, expected_len) in toplevel { let candidates = contents.iter().filter(|&&(_, ref filename, ref meta)| { filename.starts_with(&prefix[..]) - && filename[prefix.len()..].starts_with("-") + && filename[prefix.len()..].starts_with('-') && filename.ends_with(&extension[..]) && meta.len() == expected_len }); diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 110c8b844d5..709cf2908ea 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -16,7 +16,6 @@ use crate::flags::Flags; pub use crate::flags::Subcommand; use build_helper::t; use serde::Deserialize; -use toml; /// Global configuration for the entire build and/or bootstrap. /// @@ -440,7 +439,7 @@ impl Config { } } }) - .unwrap_or_else(|| TomlConfig::default()); + .unwrap_or_else(TomlConfig::default); let build = toml.build.clone().unwrap_or_default(); // set by bootstrap.py @@ -539,7 +538,7 @@ impl Config { config.llvm_ldflags = llvm.ldflags.clone(); set(&mut config.llvm_use_libcxx, llvm.use_libcxx); config.llvm_use_linker = llvm.use_linker.clone(); - config.llvm_allow_old_toolchain = llvm.allow_old_toolchain.clone(); + config.llvm_allow_old_toolchain = llvm.allow_old_toolchain; } if let Some(ref rust) = toml.rust { @@ -606,7 +605,7 @@ impl Config { target.ar = cfg.ar.clone().map(PathBuf::from); target.ranlib = cfg.ranlib.clone().map(PathBuf::from); target.linker = cfg.linker.clone().map(PathBuf::from); - target.crt_static = cfg.crt_static.clone(); + target.crt_static = cfg.crt_static; target.musl_root = cfg.musl_root.clone().map(PathBuf::from); target.wasi_root = cfg.wasi_root.clone().map(PathBuf::from); target.qemu_rootfs = cfg.qemu_rootfs.clone().map(PathBuf::from); diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index facf816857f..8003d8906e8 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -828,7 +828,7 @@ impl Step for Analysis { assert!(builder.config.extended); let name = pkgname(builder, "rust-analysis"); - if &compiler.host != builder.config.build { + if compiler.host != builder.config.build { return distdir(builder).join(format!("{}-{}.tar.gz", name, target)); } @@ -877,7 +877,7 @@ fn copy_src_dirs(builder: &Builder<'_>, src_dirs: &[&str], exclude_dirs: &[&str] Some(path) => path, None => return false, }; - if spath.ends_with("~") || spath.ends_with(".pyc") { + if spath.ends_with('~') || spath.ends_with(".pyc") { return false; } diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 204056598d9..b0d9a5b9464 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -560,7 +560,7 @@ impl Step for Rustdoc { builder.ensure(Rustc { stage, target }); // Build rustdoc. - builder.ensure(tool::Rustdoc { compiler: compiler }); + builder.ensure(tool::Rustdoc { compiler }); // Symlink compiler docs to the output directory of rustdoc documentation. let out_dir = builder.stage_out(compiler, Mode::ToolRustc).join(target).join("doc"); diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 2101ef27f9d..516be6a30c2 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -571,7 +571,7 @@ fn split(s: &[String]) -> Vec<String> { } fn parse_deny_warnings(matches: &getopts::Matches) -> Option<bool> { - match matches.opt_str("warnings").as_ref().map(|v| v.as_str()) { + match matches.opt_str("warnings").as_deref() { Some("deny") => Some(true), Some("warn") => Some(false), Some(value) => { diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index f8734ebdf42..6549262811b 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -126,9 +126,8 @@ fn add_destdir(path: &Path, destdir: &Option<PathBuf>) -> PathBuf { None => return path.to_path_buf(), }; for part in path.components() { - match part { - Component::Normal(s) => ret.push(s), - _ => {} + if let Component::Normal(s) = part { + ret.push(s) } } ret diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 637323331f5..0db4fb38901 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -444,7 +444,7 @@ impl Build { builder.execute_cli(); } else { let builder = builder::Builder::new(&self); - let _ = builder.execute_cli(); + builder.execute_cli(); } // Check for postponed failures from `test --no-fail-fast`. @@ -839,7 +839,7 @@ impl Build { .target_config .get(&target) .and_then(|t| t.musl_root.as_ref()) - .or(self.config.musl_root.as_ref()) + .or_else(|| self.config.musl_root.as_ref()) .map(|p| &**p) } diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs index 8a26adc7ed5..292aa3b1e24 100644 --- a/src/bootstrap/metadata.rs +++ b/src/bootstrap/metadata.rs @@ -5,7 +5,6 @@ use std::process::Command; use build_helper::output; use serde::Deserialize; -use serde_json; use crate::cache::INTERNER; use crate::{Build, Crate}; diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 5bbd9f47fc9..1cfb4b2f63b 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -15,8 +15,6 @@ use std::path::{Path, PathBuf}; use std::process::Command; use build_helper::{output, t}; -use cc; -use cmake; use crate::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::cache::Interned; @@ -205,7 +203,7 @@ impl Step for Llvm { cfg.define("LLVM_ENABLE_LIBXML2", "OFF"); } - if enabled_llvm_projects.len() > 0 { + if !enabled_llvm_projects.is_empty() { enabled_llvm_projects.sort(); enabled_llvm_projects.dedup(); cfg.define("LLVM_ENABLE_PROJECTS", enabled_llvm_projects.join(";")); diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 6adf9ddaf34..8d9e6201001 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1424,13 +1424,10 @@ impl Step for ErrorIndex { } fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> bool { - match fs::read_to_string(markdown) { - Ok(contents) => { - if !contents.contains("```") { - return true; - } + if let Ok(contents) = fs::read_to_string(markdown) { + if !contents.contains("```") { + return true; } - Err(_) => {} } builder.info(&format!("doc tests for: {}", markdown.display())); diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 7f24768a4f1..67e0ed5c580 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -234,7 +234,7 @@ pub fn prepare_tool_cargo( cargo.env("RUSTC_EXTERNAL_TOOL", "1"); } - let mut features = extra_features.iter().cloned().collect::<Vec<_>>(); + let mut features = extra_features.to_vec(); if builder.build.config.cargo_native_static { if path.ends_with("cargo") || path.ends_with("rls") diff --git a/src/bootstrap/toolstate.rs b/src/bootstrap/toolstate.rs index b068c8200ac..bb012a38855 100644 --- a/src/bootstrap/toolstate.rs +++ b/src/bootstrap/toolstate.rs @@ -124,7 +124,7 @@ fn check_changed_files(toolstates: &HashMap<Box<str>, ToolState>) { let output = t!(String::from_utf8(output.stdout)); for (tool, submodule) in STABLE_TOOLS.iter().chain(NIGHTLY_TOOLS.iter()) { - let changed = output.lines().any(|l| l.starts_with("M") && l.ends_with(submodule)); + let changed = output.lines().any(|l| l.starts_with('M') && l.ends_with(submodule)); eprintln!("Verifying status of {}...", tool); if !changed { continue; diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 7d1efe4610f..eac790fe504 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -98,7 +98,7 @@ impl Drop for TimeIt { fn drop(&mut self) { let time = self.1.elapsed(); if !self.0 { - println!("\tfinished in {}.{:03}", time.as_secs(), time.subsec_nanos() / 1_000_000); + println!("\tfinished in {}.{:03}", time.as_secs(), time.subsec_millis()); } } } diff --git a/src/doc/rustdoc/src/the-doc-attribute.md b/src/doc/rustdoc/src/the-doc-attribute.md index 80ac405eb2f..ef143c8727e 100644 --- a/src/doc/rustdoc/src/the-doc-attribute.md +++ b/src/doc/rustdoc/src/the-doc-attribute.md @@ -39,7 +39,7 @@ crate level, and ones that are useful at the item level. ## At the crate level -These options control how the docs look at a macro level. +These options control how the docs look at a crate level. ### `html_favicon_url` diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md index 64bff2a6fe0..414ac7e63a3 100644 --- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md +++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md @@ -170,7 +170,7 @@ Shadow byte legend (one shadow byte represents 8 application bytes): ## MemorySanitizer Use of uninitialized memory. Note that we are using `-Zbuild-std` to instrument -standard library, and passing `-msan-track-origins=2` to the LLVM to track +the standard library, and passing `-Zsanitizer-track-origins` to track the origins of uninitialized memory: ```shell @@ -185,7 +185,15 @@ fn main() { } } -$ env RUSTFLAGS="-Zsanitizer=memory -Cllvm-args=-msan-track-origins=2" cargo -Zbuild-std run --target x86_64-unknown-linux-gnu +$ export \ + CC=clang \ + CXX=clang++ \ + CFLAGS='-fsanitize=memory -fsanitize-memory-track-origins' \ + CXXFLAGS='-fsanitize=memory -fsanitize-memory-track-origins' \ + RUSTFLAGS='-Zsanitizer=memory -Zsanitizer-memory-track-origins' \ + RUSTDOCFLAGS='-Zsanitizer=memory -Zsanitizer-memory-track-origins' +$ cargo clean +$ cargo -Zbuild-std run --target x86_64-unknown-linux-gnu ==9416==WARNING: MemorySanitizer: use-of-uninitialized-value #0 0x560c04f7488a in core::fmt::num::imp::fmt_u64::haa293b0b098501ca $RUST/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/src/rust/src/libcore/fmt/num.rs:202:16 ... diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 416c73f50bd..2cee23a5c75 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1305,9 +1305,11 @@ extern "rust-intrinsic" { /// Performs an unchecked division, resulting in undefined behavior /// where y = 0 or x = `T::min_value()` and y = -1 + #[rustc_const_unstable(feature = "const_int_unchecked_arith", issue = "none")] pub fn unchecked_div<T>(x: T, y: T) -> T; /// Returns the remainder of an unchecked division, resulting in /// undefined behavior where y = 0 or x = `T::min_value()` and y = -1 + #[rustc_const_unstable(feature = "const_int_unchecked_arith", issue = "none")] pub fn unchecked_rem<T>(x: T, y: T) -> T; /// Performs an unchecked left shift, resulting in undefined behavior when @@ -1321,14 +1323,17 @@ extern "rust-intrinsic" { /// Returns the result of an unchecked addition, resulting in /// undefined behavior when `x + y > T::max_value()` or `x + y < T::min_value()`. + #[rustc_const_unstable(feature = "const_int_unchecked_arith", issue = "none")] pub fn unchecked_add<T>(x: T, y: T) -> T; /// Returns the result of an unchecked subtraction, resulting in /// undefined behavior when `x - y > T::max_value()` or `x - y < T::min_value()`. + #[rustc_const_unstable(feature = "const_int_unchecked_arith", issue = "none")] pub fn unchecked_sub<T>(x: T, y: T) -> T; /// Returns the result of an unchecked multiplication, resulting in /// undefined behavior when `x * y > T::max_value()` or `x * y < T::min_value()`. + #[rustc_const_unstable(feature = "const_int_unchecked_arith", issue = "none")] pub fn unchecked_mul<T>(x: T, y: T) -> T; /// Performs rotate left. diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index 5a31acab273..a1d4e1b31e9 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -398,7 +398,7 @@ pub fn once<T>(value: T) -> Once<T> { /// See its documentation for more. /// /// [`once_with`]: fn.once_with.html -#[derive(Copy, Clone, Debug)] +#[derive(Clone, Debug)] #[stable(feature = "iter_once_with", since = "1.43.0")] pub struct OnceWith<F> { gen: Option<F>, diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 6edf253d4bb..1fd70e1a1b0 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -72,6 +72,11 @@ #![feature(concat_idents)] #![feature(const_alloc_layout)] #![feature(const_if_match)] +#![feature(const_checked_int_methods)] +#![feature(const_euclidean_int_methods)] +#![feature(const_overflowing_int_methods)] +#![feature(const_saturating_int_methods)] +#![feature(const_int_unchecked_arith)] #![feature(const_panic)] #![feature(const_fn_union)] #![feature(const_generics)] diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 39c7d6d24ed..ed37b48b3e8 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -701,10 +701,11 @@ assert_eq!((", stringify!($SelfT), "::max_value() - 2).checked_add(3), None);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub fn checked_add(self, rhs: Self) -> Option<Self> { + pub const fn checked_add(self, rhs: Self) -> Option<Self> { let (a, b) = self.overflowing_add(rhs); if b {None} else {Some(a)} } @@ -725,10 +726,11 @@ assert_eq!((", stringify!($SelfT), "::min_value() + 2).checked_sub(3), None);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub fn checked_sub(self, rhs: Self) -> Option<Self> { + pub const fn checked_sub(self, rhs: Self) -> Option<Self> { let (a, b) = self.overflowing_sub(rhs); if b {None} else {Some(a)} } @@ -749,10 +751,11 @@ assert_eq!(", stringify!($SelfT), "::max_value().checked_mul(2), None);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub fn checked_mul(self, rhs: Self) -> Option<Self> { + pub const fn checked_mul(self, rhs: Self) -> Option<Self> { let (a, b) = self.overflowing_mul(rhs); if b {None} else {Some(a)} } @@ -774,10 +777,11 @@ assert_eq!((1", stringify!($SelfT), ").checked_div(0), None);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub fn checked_div(self, rhs: Self) -> Option<Self> { + pub const fn checked_div(self, rhs: Self) -> Option<Self> { if rhs == 0 || (self == Self::min_value() && rhs == -1) { None } else { @@ -802,10 +806,11 @@ assert_eq!(", stringify!($SelfT), "::min_value().checked_div_euclid(-1), None); assert_eq!((1", stringify!($SelfT), ").checked_div_euclid(0), None); ```"), #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub fn checked_div_euclid(self, rhs: Self) -> Option<Self> { + pub const fn checked_div_euclid(self, rhs: Self) -> Option<Self> { if rhs == 0 || (self == Self::min_value() && rhs == -1) { None } else { @@ -831,10 +836,11 @@ assert_eq!(", stringify!($SelfT), "::MIN.checked_rem(-1), None);", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub fn checked_rem(self, rhs: Self) -> Option<Self> { + pub const fn checked_rem(self, rhs: Self) -> Option<Self> { if rhs == 0 || (self == Self::min_value() && rhs == -1) { None } else { @@ -860,10 +866,11 @@ assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None); assert_eq!(", stringify!($SelfT), "::MIN.checked_rem_euclid(-1), None); ```"), #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub fn checked_rem_euclid(self, rhs: Self) -> Option<Self> { + pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> { if rhs == 0 || (self == Self::min_value() && rhs == -1) { None } else { @@ -887,8 +894,9 @@ assert_eq!(", stringify!($SelfT), "::MIN.checked_neg(), None);", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] #[inline] - pub fn checked_neg(self) -> Option<Self> { + pub const fn checked_neg(self) -> Option<Self> { let (a, b) = self.overflowing_neg(); if b {None} else {Some(a)} } @@ -908,10 +916,11 @@ assert_eq!(0x1", stringify!($SelfT), ".checked_shl(129), None);", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub fn checked_shl(self, rhs: u32) -> Option<Self> { + pub const fn checked_shl(self, rhs: u32) -> Option<Self> { let (a, b) = self.overflowing_shl(rhs); if b {None} else {Some(a)} } @@ -931,10 +940,11 @@ assert_eq!(0x10", stringify!($SelfT), ".checked_shr(128), None);", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub fn checked_shr(self, rhs: u32) -> Option<Self> { + pub const fn checked_shr(self, rhs: u32) -> Option<Self> { let (a, b) = self.overflowing_shr(rhs); if b {None} else {Some(a)} } @@ -956,8 +966,9 @@ assert_eq!(", stringify!($SelfT), "::MIN.checked_abs(), None);", $EndFeature, " ```"), #[stable(feature = "no_panic_abs", since = "1.13.0")] + #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] #[inline] - pub fn checked_abs(self) -> Option<Self> { + pub const fn checked_abs(self) -> Option<Self> { if self.is_negative() { self.checked_neg() } else { @@ -1080,8 +1091,9 @@ $EndFeature, " ```"), #[unstable(feature = "saturating_neg", issue = "59983")] + #[rustc_const_unstable(feature = "const_saturating_int_methods", issue = "53718")] #[inline] - pub fn saturating_neg(self) -> Self { + pub const fn saturating_neg(self) -> Self { intrinsics::saturating_sub(0, self) } } @@ -1106,8 +1118,9 @@ $EndFeature, " ```"), #[unstable(feature = "saturating_neg", issue = "59983")] + #[rustc_const_unstable(feature = "const_saturating_int_methods", issue = "53718")] #[inline] - pub fn saturating_abs(self) -> Self { + pub const fn saturating_abs(self) -> Self { if self.is_negative() { self.saturating_neg() } else { @@ -1133,17 +1146,19 @@ assert_eq!(", stringify!($SelfT), "::MIN.saturating_mul(10), ", stringify!($Self $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_saturating_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub fn saturating_mul(self, rhs: Self) -> Self { - self.checked_mul(rhs).unwrap_or_else(|| { - if (self < 0) == (rhs < 0) { + pub const fn saturating_mul(self, rhs: Self) -> Self { + match self.checked_mul(rhs) { + Some(x) => x, + None => if (self < 0) == (rhs < 0) { Self::max_value() } else { Self::min_value() } - }) + } } } @@ -1269,10 +1284,11 @@ assert_eq!((-128i8).wrapping_div(-1), -128);", $EndFeature, " ```"), #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub fn wrapping_div(self, rhs: Self) -> Self { + pub const fn wrapping_div(self, rhs: Self) -> Self { self.overflowing_div(rhs).0 } } @@ -1298,10 +1314,11 @@ assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10); assert_eq!((-128i8).wrapping_div_euclid(-1), -128); ```"), #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub fn wrapping_div_euclid(self, rhs: Self) -> Self { + pub const fn wrapping_div_euclid(self, rhs: Self) -> Self { self.overflowing_div_euclid(rhs).0 } } @@ -1328,10 +1345,11 @@ assert_eq!((-128i8).wrapping_rem(-1), 0);", $EndFeature, " ```"), #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub fn wrapping_rem(self, rhs: Self) -> Self { + pub const fn wrapping_rem(self, rhs: Self) -> Self { self.overflowing_rem(rhs).0 } } @@ -1356,10 +1374,11 @@ assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0); assert_eq!((-128i8).wrapping_rem_euclid(-1), 0); ```"), #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub fn wrapping_rem_euclid(self, rhs: Self) -> Self { + pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self { self.overflowing_rem_euclid(rhs).0 } } @@ -1635,9 +1654,10 @@ $EndFeature, " ```"), #[inline] #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - pub fn overflowing_div(self, rhs: Self) -> (Self, bool) { + pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) { if self == Self::min_value() && rhs == -1 { (self, true) } else { @@ -1669,9 +1689,10 @@ assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div_euclid(-1), (", stringi ```"), #[inline] #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - pub fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { + pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { if self == Self::min_value() && rhs == -1 { (self, true) } else { @@ -1703,9 +1724,10 @@ $EndFeature, " ```"), #[inline] #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - pub fn overflowing_rem(self, rhs: Self) -> (Self, bool) { + pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) { if self == Self::min_value() && rhs == -1 { (0, true) } else { @@ -1736,10 +1758,11 @@ assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false)); assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem_euclid(-1), (0, true)); ```"), #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { + pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { if self == Self::min_value() && rhs == -1 { (0, true) } else { @@ -1981,11 +2004,12 @@ assert_eq!((-a).div_euclid(b), -2); // -7 >= 4 * -2 assert_eq!((-a).div_euclid(-b), 2); // -7 >= -4 * 2 ```"), #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] - pub fn div_euclid(self, rhs: Self) -> Self { + pub const fn div_euclid(self, rhs: Self) -> Self { let q = self / rhs; if self % rhs < 0 { return if rhs > 0 { q - 1 } else { q + 1 } @@ -2020,11 +2044,12 @@ assert_eq!(a.rem_euclid(-b), 3); assert_eq!((-a).rem_euclid(-b), 1); ```"), #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] - pub fn rem_euclid(self, rhs: Self) -> Self { + pub const fn rem_euclid(self, rhs: Self) -> Self { let r = self % rhs; if r < 0 { if rhs < 0 { @@ -2847,10 +2872,11 @@ Basic usage: assert_eq!((", stringify!($SelfT), "::max_value() - 2).checked_add(3), None);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub fn checked_add(self, rhs: Self) -> Option<Self> { + pub const fn checked_add(self, rhs: Self) -> Option<Self> { let (a, b) = self.overflowing_add(rhs); if b {None} else {Some(a)} } @@ -2869,10 +2895,11 @@ Basic usage: assert_eq!(0", stringify!($SelfT), ".checked_sub(1), None);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub fn checked_sub(self, rhs: Self) -> Option<Self> { + pub const fn checked_sub(self, rhs: Self) -> Option<Self> { let (a, b) = self.overflowing_sub(rhs); if b {None} else {Some(a)} } @@ -2891,10 +2918,11 @@ Basic usage: assert_eq!(", stringify!($SelfT), "::max_value().checked_mul(2), None);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub fn checked_mul(self, rhs: Self) -> Option<Self> { + pub const fn checked_mul(self, rhs: Self) -> Option<Self> { let (a, b) = self.overflowing_mul(rhs); if b {None} else {Some(a)} } @@ -2913,10 +2941,11 @@ Basic usage: assert_eq!(1", stringify!($SelfT), ".checked_div(0), None);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub fn checked_div(self, rhs: Self) -> Option<Self> { + pub const fn checked_div(self, rhs: Self) -> Option<Self> { match rhs { 0 => None, // SAFETY: div by zero has been checked above and unsigned types have no other @@ -2939,10 +2968,11 @@ assert_eq!(128", stringify!($SelfT), ".checked_div_euclid(2), Some(64)); assert_eq!(1", stringify!($SelfT), ".checked_div_euclid(0), None); ```"), #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub fn checked_div_euclid(self, rhs: Self) -> Option<Self> { + pub const fn checked_div_euclid(self, rhs: Self) -> Option<Self> { if rhs == 0 { None } else { @@ -2965,10 +2995,11 @@ Basic usage: assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub fn checked_rem(self, rhs: Self) -> Option<Self> { + pub const fn checked_rem(self, rhs: Self) -> Option<Self> { if rhs == 0 { None } else { @@ -2992,10 +3023,11 @@ assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1)); assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None); ```"), #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub fn checked_rem_euclid(self, rhs: Self) -> Option<Self> { + pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> { if rhs == 0 { None } else { @@ -3019,8 +3051,9 @@ Basic usage: assert_eq!(1", stringify!($SelfT), ".checked_neg(), None);", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] #[inline] - pub fn checked_neg(self) -> Option<Self> { + pub const fn checked_neg(self) -> Option<Self> { let (a, b) = self.overflowing_neg(); if b {None} else {Some(a)} } @@ -3039,10 +3072,11 @@ Basic usage: assert_eq!(0x10", stringify!($SelfT), ".checked_shl(129), None);", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub fn checked_shl(self, rhs: u32) -> Option<Self> { + pub const fn checked_shl(self, rhs: u32) -> Option<Self> { let (a, b) = self.overflowing_shl(rhs); if b {None} else {Some(a)} } @@ -3061,10 +3095,11 @@ Basic usage: assert_eq!(0x10", stringify!($SelfT), ".checked_shr(129), None);", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub fn checked_shr(self, rhs: u32) -> Option<Self> { + pub const fn checked_shr(self, rhs: u32) -> Option<Self> { let (a, b) = self.overflowing_shr(rhs); if b {None} else {Some(a)} } @@ -3170,11 +3205,15 @@ assert_eq!((", stringify!($SelfT), "::MAX).saturating_mul(10), ", stringify!($Se "::MAX);", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_saturating_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub fn saturating_mul(self, rhs: Self) -> Self { - self.checked_mul(rhs).unwrap_or(Self::max_value()) + pub const fn saturating_mul(self, rhs: Self) -> Self { + match self.checked_mul(rhs) { + Some(x) => x, + None => Self::max_value(), + } } } @@ -3289,10 +3328,11 @@ Basic usage: ", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10);", $EndFeature, " ```"), #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub fn wrapping_div(self, rhs: Self) -> Self { + pub const fn wrapping_div(self, rhs: Self) -> Self { self / rhs } } @@ -3315,10 +3355,11 @@ Basic usage: assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10); ```"), #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub fn wrapping_div_euclid(self, rhs: Self) -> Self { + pub const fn wrapping_div_euclid(self, rhs: Self) -> Self { self / rhs } } @@ -3339,10 +3380,11 @@ Basic usage: ", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0);", $EndFeature, " ```"), #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub fn wrapping_rem(self, rhs: Self) -> Self { + pub const fn wrapping_rem(self, rhs: Self) -> Self { self % rhs } } @@ -3366,10 +3408,11 @@ Basic usage: assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0); ```"), #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub fn wrapping_rem_euclid(self, rhs: Self) -> Self { + pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self { self % rhs } } @@ -3614,9 +3657,10 @@ Basic usage ```"), #[inline] #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - pub fn overflowing_div(self, rhs: Self) -> (Self, bool) { + pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) { (self / rhs, false) } } @@ -3645,9 +3689,10 @@ assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false)); ```"), #[inline] #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - pub fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { + pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { (self / rhs, false) } } @@ -3673,9 +3718,10 @@ Basic usage ```"), #[inline] #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - pub fn overflowing_rem(self, rhs: Self) -> (Self, bool) { + pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) { (self % rhs, false) } } @@ -3704,9 +3750,10 @@ assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false)); ```"), #[inline] #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - pub fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { + pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { (self % rhs, false) } } @@ -3897,11 +3944,12 @@ Basic usage: assert_eq!(7", stringify!($SelfT), ".div_euclid(4), 1); // or any other integer type ```"), #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] - pub fn div_euclid(self, rhs: Self) -> Self { + pub const fn div_euclid(self, rhs: Self) -> Self { self / rhs } } @@ -3926,11 +3974,12 @@ Basic usage: assert_eq!(7", stringify!($SelfT), ".rem_euclid(4), 3); // or any other integer type ```"), #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] - pub fn rem_euclid(self, rhs: Self) -> Self { + pub const fn rem_euclid(self, rhs: Self) -> Self { self % rhs } } diff --git a/src/librustc/arena.rs b/src/librustc/arena.rs index 15e92d8d842..92f5bf87535 100644 --- a/src/librustc/arena.rs +++ b/src/librustc/arena.rs @@ -216,6 +216,7 @@ arena_types!(declare_arena, [], 'tcx); arena_types!(impl_arena_allocatable, [], 'tcx); +#[marker] pub trait ArenaAllocatable {} impl<T: Copy> ArenaAllocatable for T {} diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 061b82ebb43..01558615497 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -40,40 +40,14 @@ impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> { } } - // The following implementations of HashStable for `ItemId`, `TraitItemId`, and - // `ImplItemId` deserve special attention. Normally we do not hash `NodeId`s within - // the HIR, since they just signify a HIR nodes own path. But `ItemId` et al - // are used when another item in the HIR is *referenced* and we certainly - // want to pick up on a reference changing its target, so we hash the NodeIds - // in "DefPath Mode". - - fn hash_item_id(&mut self, id: hir::ItemId, hasher: &mut StableHasher) { + fn hash_reference_to_item(&mut self, id: hir::HirId, hasher: &mut StableHasher) { let hcx = self; - let hir::ItemId { id } = id; hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { id.hash_stable(hcx, hasher); }) } - fn hash_impl_item_id(&mut self, id: hir::ImplItemId, hasher: &mut StableHasher) { - let hcx = self; - let hir::ImplItemId { hir_id } = id; - - hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { - hir_id.hash_stable(hcx, hasher); - }) - } - - fn hash_trait_item_id(&mut self, id: hir::TraitItemId, hasher: &mut StableHasher) { - let hcx = self; - let hir::TraitItemId { hir_id } = id; - - hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { - hir_id.hash_stable(hcx, hasher); - }) - } - fn hash_hir_mod(&mut self, module: &hir::Mod<'_>, hasher: &mut StableHasher) { let hcx = self; let hir::Mod { inner: ref inner_span, ref item_ids } = *module; diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs index a588d3d028a..f157d805bcd 100644 --- a/src/librustc/infer/canonical/mod.rs +++ b/src/librustc/infer/canonical/mod.rs @@ -21,18 +21,15 @@ //! //! [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html -use crate::infer::region_constraints::MemberConstraint; use crate::infer::{ConstVariableOrigin, ConstVariableOriginKind}; use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin, TypeVariableOriginKind}; -use crate::ty::fold::TypeFoldable; -use crate::ty::subst::GenericArg; -use crate::ty::{self, BoundVar, List, Region, TyCtxt}; +use rustc::ty::fold::TypeFoldable; +use rustc::ty::subst::GenericArg; +use rustc::ty::{self, BoundVar, List}; use rustc_index::vec::IndexVec; -use rustc_macros::HashStable; -use rustc_serialize::UseSpecializedDecodable; use rustc_span::source_map::Span; -use smallvec::SmallVec; -use std::ops::Index; + +pub use rustc::infer::types::canonical::*; mod canonicalizer; @@ -40,265 +37,6 @@ pub mod query_response; mod substitute; -/// A "canonicalized" type `V` is one where all free inference -/// variables have been rewritten to "canonical vars". These are -/// numbered starting from 0 in order of first appearance. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] -#[derive(HashStable, TypeFoldable, Lift)] -pub struct Canonical<'tcx, V> { - pub max_universe: ty::UniverseIndex, - pub variables: CanonicalVarInfos<'tcx>, - pub value: V, -} - -pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo>; - -impl<'tcx> UseSpecializedDecodable for CanonicalVarInfos<'tcx> {} - -/// A set of values corresponding to the canonical variables from some -/// `Canonical`. You can give these values to -/// `canonical_value.substitute` to substitute them into the canonical -/// value at the right places. -/// -/// When you canonicalize a value `V`, you get back one of these -/// vectors with the original values that were replaced by canonical -/// variables. You will need to supply it later to instantiate the -/// canonicalized query response. -#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] -#[derive(HashStable, TypeFoldable, Lift)] -pub struct CanonicalVarValues<'tcx> { - pub var_values: IndexVec<BoundVar, GenericArg<'tcx>>, -} - -/// When we canonicalize a value to form a query, we wind up replacing -/// various parts of it with canonical variables. This struct stores -/// those replaced bits to remember for when we process the query -/// result. -#[derive(Clone, Debug)] -pub struct OriginalQueryValues<'tcx> { - /// Map from the universes that appear in the query to the - /// universes in the caller context. For the time being, we only - /// ever put ROOT values into the query, so this map is very - /// simple. - pub universe_map: SmallVec<[ty::UniverseIndex; 4]>, - - /// This is equivalent to `CanonicalVarValues`, but using a - /// `SmallVec` yields a significant performance win. - pub var_values: SmallVec<[GenericArg<'tcx>; 8]>, -} - -impl Default for OriginalQueryValues<'tcx> { - fn default() -> Self { - let mut universe_map = SmallVec::default(); - universe_map.push(ty::UniverseIndex::ROOT); - - Self { universe_map, var_values: SmallVec::default() } - } -} - -/// Information about a canonical variable that is included with the -/// canonical value. This is sufficient information for code to create -/// a copy of the canonical value in some other inference context, -/// with fresh inference variables replacing the canonical values. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable, HashStable)] -pub struct CanonicalVarInfo { - pub kind: CanonicalVarKind, -} - -impl CanonicalVarInfo { - pub fn universe(&self) -> ty::UniverseIndex { - self.kind.universe() - } - - pub fn is_existential(&self) -> bool { - match self.kind { - CanonicalVarKind::Ty(_) => true, - CanonicalVarKind::PlaceholderTy(_) => false, - CanonicalVarKind::Region(_) => true, - CanonicalVarKind::PlaceholderRegion(..) => false, - CanonicalVarKind::Const(_) => true, - CanonicalVarKind::PlaceholderConst(_) => false, - } - } -} - -/// Describes the "kind" of the canonical variable. This is a "kind" -/// in the type-theory sense of the term -- i.e., a "meta" type system -/// that analyzes type-like values. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable, HashStable)] -pub enum CanonicalVarKind { - /// Some kind of type inference variable. - Ty(CanonicalTyVarKind), - - /// A "placeholder" that represents "any type". - PlaceholderTy(ty::PlaceholderType), - - /// Region variable `'?R`. - Region(ty::UniverseIndex), - - /// A "placeholder" that represents "any region". Created when you - /// are solving a goal like `for<'a> T: Foo<'a>` to represent the - /// bound region `'a`. - PlaceholderRegion(ty::PlaceholderRegion), - - /// Some kind of const inference variable. - Const(ty::UniverseIndex), - - /// A "placeholder" that represents "any const". - PlaceholderConst(ty::PlaceholderConst), -} - -impl CanonicalVarKind { - pub fn universe(self) -> ty::UniverseIndex { - match self { - CanonicalVarKind::Ty(kind) => match kind { - CanonicalTyVarKind::General(ui) => ui, - CanonicalTyVarKind::Float | CanonicalTyVarKind::Int => ty::UniverseIndex::ROOT, - }, - - CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe, - CanonicalVarKind::Region(ui) => ui, - CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe, - CanonicalVarKind::Const(ui) => ui, - CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.universe, - } - } -} - -/// Rust actually has more than one category of type variables; -/// notably, the type variables we create for literals (e.g., 22 or -/// 22.) can only be instantiated with integral/float types (e.g., -/// usize or f32). In order to faithfully reproduce a type, we need to -/// know what set of types a given type variable can be unified with. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable, HashStable)] -pub enum CanonicalTyVarKind { - /// General type variable `?T` that can be unified with arbitrary types. - General(ty::UniverseIndex), - - /// Integral type variable `?I` (that can only be unified with integral types). - Int, - - /// Floating-point type variable `?F` (that can only be unified with float types). - Float, -} - -/// After we execute a query with a canonicalized key, we get back a -/// `Canonical<QueryResponse<..>>`. You can use -/// `instantiate_query_result` to access the data in this result. -#[derive(Clone, Debug, HashStable, TypeFoldable, Lift)] -pub struct QueryResponse<'tcx, R> { - pub var_values: CanonicalVarValues<'tcx>, - pub region_constraints: QueryRegionConstraints<'tcx>, - pub certainty: Certainty, - pub value: R, -} - -#[derive(Clone, Debug, Default, HashStable, TypeFoldable, Lift)] -pub struct QueryRegionConstraints<'tcx> { - pub outlives: Vec<QueryOutlivesConstraint<'tcx>>, - pub member_constraints: Vec<MemberConstraint<'tcx>>, -} - -impl QueryRegionConstraints<'_> { - /// Represents an empty (trivially true) set of region - /// constraints. - pub fn is_empty(&self) -> bool { - self.outlives.is_empty() && self.member_constraints.is_empty() - } -} - -pub type Canonicalized<'tcx, V> = Canonical<'tcx, V>; - -pub type CanonicalizedQueryResponse<'tcx, T> = &'tcx Canonical<'tcx, QueryResponse<'tcx, T>>; - -/// Indicates whether or not we were able to prove the query to be -/// true. -#[derive(Copy, Clone, Debug, HashStable)] -pub enum Certainty { - /// The query is known to be true, presuming that you apply the - /// given `var_values` and the region-constraints are satisfied. - Proven, - - /// The query is not known to be true, but also not known to be - /// false. The `var_values` represent *either* values that must - /// hold in order for the query to be true, or helpful tips that - /// *might* make it true. Currently rustc's trait solver cannot - /// distinguish the two (e.g., due to our preference for where - /// clauses over impls). - /// - /// After some unifiations and things have been done, it makes - /// sense to try and prove again -- of course, at that point, the - /// canonical form will be different, making this a distinct - /// query. - Ambiguous, -} - -impl Certainty { - pub fn is_proven(&self) -> bool { - match self { - Certainty::Proven => true, - Certainty::Ambiguous => false, - } - } - - pub fn is_ambiguous(&self) -> bool { - !self.is_proven() - } -} - -impl<'tcx, R> QueryResponse<'tcx, R> { - pub fn is_proven(&self) -> bool { - self.certainty.is_proven() - } - - pub fn is_ambiguous(&self) -> bool { - !self.is_proven() - } -} - -impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> { - pub fn is_proven(&self) -> bool { - self.value.is_proven() - } - - pub fn is_ambiguous(&self) -> bool { - !self.is_proven() - } -} - -impl<'tcx, V> Canonical<'tcx, V> { - /// Allows you to map the `value` of a canonical while keeping the - /// same set of bound variables. - /// - /// **WARNING:** This function is very easy to mis-use, hence the - /// name! In particular, the new value `W` must use all **the - /// same type/region variables** in **precisely the same order** - /// as the original! (The ordering is defined by the - /// `TypeFoldable` implementation of the type in question.) - /// - /// An example of a **correct** use of this: - /// - /// ```rust,ignore (not real code) - /// let a: Canonical<'_, T> = ...; - /// let b: Canonical<'_, (T,)> = a.unchecked_map(|v| (v, )); - /// ``` - /// - /// An example of an **incorrect** use of this: - /// - /// ```rust,ignore (not real code) - /// let a: Canonical<'tcx, T> = ...; - /// let ty: Ty<'tcx> = ...; - /// let b: Canonical<'tcx, (T, Ty<'tcx>)> = a.unchecked_map(|v| (v, ty)); - /// ``` - pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<'tcx, W> { - let Canonical { max_universe, variables, value } = self; - Canonical { max_universe, variables, value: map_op(value) } - } -} - -pub type QueryOutlivesConstraint<'tcx> = - ty::Binder<ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>; - impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// Creates a substitution S for the canonical value with fresh /// inference variables and applies it to the canonical value. @@ -424,70 +162,3 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { } } } - -CloneTypeFoldableAndLiftImpls! { - crate::infer::canonical::Certainty, - crate::infer::canonical::CanonicalVarInfo, - crate::infer::canonical::CanonicalVarKind, -} - -CloneTypeFoldableImpls! { - for <'tcx> { - crate::infer::canonical::CanonicalVarInfos<'tcx>, - } -} - -impl<'tcx> CanonicalVarValues<'tcx> { - pub fn len(&self) -> usize { - self.var_values.len() - } - - /// Makes an identity substitution from this one: each bound var - /// is matched to the same bound var, preserving the original kinds. - /// For example, if we have: - /// `self.var_values == [Type(u32), Lifetime('a), Type(u64)]` - /// we'll return a substitution `subst` with: - /// `subst.var_values == [Type(^0), Lifetime(^1), Type(^2)]`. - pub fn make_identity(&self, tcx: TyCtxt<'tcx>) -> Self { - use crate::ty::subst::GenericArgKind; - - CanonicalVarValues { - var_values: self - .var_values - .iter() - .zip(0..) - .map(|(kind, i)| match kind.unpack() { - GenericArgKind::Type(..) => { - tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i).into())).into() - } - GenericArgKind::Lifetime(..) => tcx - .mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(i))) - .into(), - GenericArgKind::Const(ct) => tcx - .mk_const(ty::Const { - ty: ct.ty, - val: ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i)), - }) - .into(), - }) - .collect(), - } - } -} - -impl<'a, 'tcx> IntoIterator for &'a CanonicalVarValues<'tcx> { - type Item = GenericArg<'tcx>; - type IntoIter = ::std::iter::Cloned<::std::slice::Iter<'a, GenericArg<'tcx>>>; - - fn into_iter(self) -> Self::IntoIter { - self.var_values.iter().cloned() - } -} - -impl<'tcx> Index<BoundVar> for CanonicalVarValues<'tcx> { - type Output = GenericArg<'tcx>; - - fn index(&self, value: BoundVar) -> &GenericArg<'tcx> { - &self.var_values[value] - } -} diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index f67669e367f..4681a47317c 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -61,6 +61,7 @@ pub mod region_constraints; pub mod resolve; mod sub; pub mod type_variable; +mod types; pub mod unify_key; #[must_use] @@ -556,16 +557,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> { } } -impl<T> ExpectedFound<T> { - pub fn new(a_is_expected: bool, a: T, b: T) -> Self { - if a_is_expected { - ExpectedFound { expected: a, found: b } - } else { - ExpectedFound { expected: b, found: a } - } - } -} - impl<'tcx, T> InferOk<'tcx, T> { pub fn unit(self) -> InferOk<'tcx, ()> { InferOk { value: (), obligations: self.obligations } diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs index 27ed3c78138..410058b70b5 100644 --- a/src/librustc/infer/region_constraints/mod.rs +++ b/src/librustc/infer/region_constraints/mod.rs @@ -23,6 +23,8 @@ use std::{cmp, fmt, mem}; mod leak_check; +pub use rustc::infer::types::MemberConstraint; + #[derive(Default)] pub struct RegionConstraintCollector<'tcx> { /// For each `RegionVid`, the corresponding `RegionVariableOrigin`. @@ -145,30 +147,6 @@ impl Constraint<'_> { } } -/// Requires that `region` must be equal to one of the regions in `choice_regions`. -/// We often denote this using the syntax: -/// -/// ``` -/// R0 member of [O1..On] -/// ``` -#[derive(Debug, Clone, HashStable, TypeFoldable, Lift)] -pub struct MemberConstraint<'tcx> { - /// The `DefId` of the opaque type causing this constraint: used for error reporting. - pub opaque_type_def_id: DefId, - - /// The span where the hidden type was instantiated. - pub definition_span: Span, - - /// The hidden type in which `member_region` appears: used for error reporting. - pub hidden_ty: Ty<'tcx>, - - /// The region `R0`. - pub member_region: Region<'tcx>, - - /// The options `O1..On`. - pub choice_regions: Lrc<Vec<Region<'tcx>>>, -} - /// `VerifyGenericBound(T, _, R, RS)`: the parameter type `T` (or /// associated type) must outlive the region `R`. `T` is known to /// outlive `RS`. Therefore, verify that `R <= RS[i]` for some diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 8ea1b705d44..f391a054a2a 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -453,18 +453,3 @@ impl<'tcx> ut::UnifyValue for TypeVariableValue<'tcx> { } } } - -/// Raw `TyVid` are used as the unification key for `sub_relations`; -/// they carry no values. -impl ut::UnifyKey for ty::TyVid { - type Value = (); - fn index(&self) -> u32 { - self.index - } - fn from_index(i: u32) -> ty::TyVid { - ty::TyVid { index: i } - } - fn tag() -> &'static str { - "TyVid" - } -} diff --git a/src/librustc/infer/types/canonical.rs b/src/librustc/infer/types/canonical.rs new file mode 100644 index 00000000000..133cf1b5928 --- /dev/null +++ b/src/librustc/infer/types/canonical.rs @@ -0,0 +1,357 @@ +//! **Canonicalization** is the key to constructing a query in the +//! middle of type inference. Ordinarily, it is not possible to store +//! types from type inference in query keys, because they contain +//! references to inference variables whose lifetimes are too short +//! and so forth. Canonicalizing a value T1 using `canonicalize_query` +//! produces two things: +//! +//! - a value T2 where each unbound inference variable has been +//! replaced with a **canonical variable**; +//! - a map M (of type `CanonicalVarValues`) from those canonical +//! variables back to the original. +//! +//! We can then do queries using T2. These will give back constraints +//! on the canonical variables which can be translated, using the map +//! M, into constraints in our source context. This process of +//! translating the results back is done by the +//! `instantiate_query_result` method. +//! +//! For a more detailed look at what is happening here, check +//! out the [chapter in the rustc guide][c]. +//! +//! [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html + +use crate::infer::region_constraints::MemberConstraint; +use crate::ty::subst::GenericArg; +use crate::ty::{self, BoundVar, List, Region, TyCtxt}; +use rustc_index::vec::IndexVec; +use rustc_macros::HashStable; +use rustc_serialize::UseSpecializedDecodable; +use smallvec::SmallVec; +use std::ops::Index; + +/// A "canonicalized" type `V` is one where all free inference +/// variables have been rewritten to "canonical vars". These are +/// numbered starting from 0 in order of first appearance. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] +#[derive(HashStable, TypeFoldable, Lift)] +pub struct Canonical<'tcx, V> { + pub max_universe: ty::UniverseIndex, + pub variables: CanonicalVarInfos<'tcx>, + pub value: V, +} + +pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo>; + +impl<'tcx> UseSpecializedDecodable for CanonicalVarInfos<'tcx> {} + +/// A set of values corresponding to the canonical variables from some +/// `Canonical`. You can give these values to +/// `canonical_value.substitute` to substitute them into the canonical +/// value at the right places. +/// +/// When you canonicalize a value `V`, you get back one of these +/// vectors with the original values that were replaced by canonical +/// variables. You will need to supply it later to instantiate the +/// canonicalized query response. +#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] +#[derive(HashStable, TypeFoldable, Lift)] +pub struct CanonicalVarValues<'tcx> { + pub var_values: IndexVec<BoundVar, GenericArg<'tcx>>, +} + +/// When we canonicalize a value to form a query, we wind up replacing +/// various parts of it with canonical variables. This struct stores +/// those replaced bits to remember for when we process the query +/// result. +#[derive(Clone, Debug)] +pub struct OriginalQueryValues<'tcx> { + /// Map from the universes that appear in the query to the + /// universes in the caller context. For the time being, we only + /// ever put ROOT values into the query, so this map is very + /// simple. + pub universe_map: SmallVec<[ty::UniverseIndex; 4]>, + + /// This is equivalent to `CanonicalVarValues`, but using a + /// `SmallVec` yields a significant performance win. + pub var_values: SmallVec<[GenericArg<'tcx>; 8]>, +} + +impl Default for OriginalQueryValues<'tcx> { + fn default() -> Self { + let mut universe_map = SmallVec::default(); + universe_map.push(ty::UniverseIndex::ROOT); + + Self { universe_map, var_values: SmallVec::default() } + } +} + +/// Information about a canonical variable that is included with the +/// canonical value. This is sufficient information for code to create +/// a copy of the canonical value in some other inference context, +/// with fresh inference variables replacing the canonical values. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable, HashStable)] +pub struct CanonicalVarInfo { + pub kind: CanonicalVarKind, +} + +impl CanonicalVarInfo { + pub fn universe(&self) -> ty::UniverseIndex { + self.kind.universe() + } + + pub fn is_existential(&self) -> bool { + match self.kind { + CanonicalVarKind::Ty(_) => true, + CanonicalVarKind::PlaceholderTy(_) => false, + CanonicalVarKind::Region(_) => true, + CanonicalVarKind::PlaceholderRegion(..) => false, + CanonicalVarKind::Const(_) => true, + CanonicalVarKind::PlaceholderConst(_) => false, + } + } +} + +/// Describes the "kind" of the canonical variable. This is a "kind" +/// in the type-theory sense of the term -- i.e., a "meta" type system +/// that analyzes type-like values. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable, HashStable)] +pub enum CanonicalVarKind { + /// Some kind of type inference variable. + Ty(CanonicalTyVarKind), + + /// A "placeholder" that represents "any type". + PlaceholderTy(ty::PlaceholderType), + + /// Region variable `'?R`. + Region(ty::UniverseIndex), + + /// A "placeholder" that represents "any region". Created when you + /// are solving a goal like `for<'a> T: Foo<'a>` to represent the + /// bound region `'a`. + PlaceholderRegion(ty::PlaceholderRegion), + + /// Some kind of const inference variable. + Const(ty::UniverseIndex), + + /// A "placeholder" that represents "any const". + PlaceholderConst(ty::PlaceholderConst), +} + +impl CanonicalVarKind { + pub fn universe(self) -> ty::UniverseIndex { + match self { + CanonicalVarKind::Ty(kind) => match kind { + CanonicalTyVarKind::General(ui) => ui, + CanonicalTyVarKind::Float | CanonicalTyVarKind::Int => ty::UniverseIndex::ROOT, + }, + + CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe, + CanonicalVarKind::Region(ui) => ui, + CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe, + CanonicalVarKind::Const(ui) => ui, + CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.universe, + } + } +} + +/// Rust actually has more than one category of type variables; +/// notably, the type variables we create for literals (e.g., 22 or +/// 22.) can only be instantiated with integral/float types (e.g., +/// usize or f32). In order to faithfully reproduce a type, we need to +/// know what set of types a given type variable can be unified with. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable, HashStable)] +pub enum CanonicalTyVarKind { + /// General type variable `?T` that can be unified with arbitrary types. + General(ty::UniverseIndex), + + /// Integral type variable `?I` (that can only be unified with integral types). + Int, + + /// Floating-point type variable `?F` (that can only be unified with float types). + Float, +} + +/// After we execute a query with a canonicalized key, we get back a +/// `Canonical<QueryResponse<..>>`. You can use +/// `instantiate_query_result` to access the data in this result. +#[derive(Clone, Debug, HashStable, TypeFoldable, Lift)] +pub struct QueryResponse<'tcx, R> { + pub var_values: CanonicalVarValues<'tcx>, + pub region_constraints: QueryRegionConstraints<'tcx>, + pub certainty: Certainty, + pub value: R, +} + +#[derive(Clone, Debug, Default, HashStable, TypeFoldable, Lift)] +pub struct QueryRegionConstraints<'tcx> { + pub outlives: Vec<QueryOutlivesConstraint<'tcx>>, + pub member_constraints: Vec<MemberConstraint<'tcx>>, +} + +impl QueryRegionConstraints<'_> { + /// Represents an empty (trivially true) set of region + /// constraints. + pub fn is_empty(&self) -> bool { + self.outlives.is_empty() && self.member_constraints.is_empty() + } +} + +pub type Canonicalized<'tcx, V> = Canonical<'tcx, V>; + +pub type CanonicalizedQueryResponse<'tcx, T> = &'tcx Canonical<'tcx, QueryResponse<'tcx, T>>; + +/// Indicates whether or not we were able to prove the query to be +/// true. +#[derive(Copy, Clone, Debug, HashStable)] +pub enum Certainty { + /// The query is known to be true, presuming that you apply the + /// given `var_values` and the region-constraints are satisfied. + Proven, + + /// The query is not known to be true, but also not known to be + /// false. The `var_values` represent *either* values that must + /// hold in order for the query to be true, or helpful tips that + /// *might* make it true. Currently rustc's trait solver cannot + /// distinguish the two (e.g., due to our preference for where + /// clauses over impls). + /// + /// After some unifiations and things have been done, it makes + /// sense to try and prove again -- of course, at that point, the + /// canonical form will be different, making this a distinct + /// query. + Ambiguous, +} + +impl Certainty { + pub fn is_proven(&self) -> bool { + match self { + Certainty::Proven => true, + Certainty::Ambiguous => false, + } + } + + pub fn is_ambiguous(&self) -> bool { + !self.is_proven() + } +} + +impl<'tcx, R> QueryResponse<'tcx, R> { + pub fn is_proven(&self) -> bool { + self.certainty.is_proven() + } + + pub fn is_ambiguous(&self) -> bool { + !self.is_proven() + } +} + +impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> { + pub fn is_proven(&self) -> bool { + self.value.is_proven() + } + + pub fn is_ambiguous(&self) -> bool { + !self.is_proven() + } +} + +impl<'tcx, V> Canonical<'tcx, V> { + /// Allows you to map the `value` of a canonical while keeping the + /// same set of bound variables. + /// + /// **WARNING:** This function is very easy to mis-use, hence the + /// name! In particular, the new value `W` must use all **the + /// same type/region variables** in **precisely the same order** + /// as the original! (The ordering is defined by the + /// `TypeFoldable` implementation of the type in question.) + /// + /// An example of a **correct** use of this: + /// + /// ```rust,ignore (not real code) + /// let a: Canonical<'_, T> = ...; + /// let b: Canonical<'_, (T,)> = a.unchecked_map(|v| (v, )); + /// ``` + /// + /// An example of an **incorrect** use of this: + /// + /// ```rust,ignore (not real code) + /// let a: Canonical<'tcx, T> = ...; + /// let ty: Ty<'tcx> = ...; + /// let b: Canonical<'tcx, (T, Ty<'tcx>)> = a.unchecked_map(|v| (v, ty)); + /// ``` + pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<'tcx, W> { + let Canonical { max_universe, variables, value } = self; + Canonical { max_universe, variables, value: map_op(value) } + } +} + +pub type QueryOutlivesConstraint<'tcx> = + ty::Binder<ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>; + +CloneTypeFoldableAndLiftImpls! { + crate::infer::canonical::Certainty, + crate::infer::canonical::CanonicalVarInfo, + crate::infer::canonical::CanonicalVarKind, +} + +CloneTypeFoldableImpls! { + for <'tcx> { + crate::infer::canonical::CanonicalVarInfos<'tcx>, + } +} + +impl<'tcx> CanonicalVarValues<'tcx> { + pub fn len(&self) -> usize { + self.var_values.len() + } + + /// Makes an identity substitution from this one: each bound var + /// is matched to the same bound var, preserving the original kinds. + /// For example, if we have: + /// `self.var_values == [Type(u32), Lifetime('a), Type(u64)]` + /// we'll return a substitution `subst` with: + /// `subst.var_values == [Type(^0), Lifetime(^1), Type(^2)]`. + pub fn make_identity(&self, tcx: TyCtxt<'tcx>) -> Self { + use crate::ty::subst::GenericArgKind; + + CanonicalVarValues { + var_values: self + .var_values + .iter() + .zip(0..) + .map(|(kind, i)| match kind.unpack() { + GenericArgKind::Type(..) => { + tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i).into())).into() + } + GenericArgKind::Lifetime(..) => tcx + .mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(i))) + .into(), + GenericArgKind::Const(ct) => tcx + .mk_const(ty::Const { + ty: ct.ty, + val: ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i)), + }) + .into(), + }) + .collect(), + } + } +} + +impl<'a, 'tcx> IntoIterator for &'a CanonicalVarValues<'tcx> { + type Item = GenericArg<'tcx>; + type IntoIter = ::std::iter::Cloned<::std::slice::Iter<'a, GenericArg<'tcx>>>; + + fn into_iter(self) -> Self::IntoIter { + self.var_values.iter().cloned() + } +} + +impl<'tcx> Index<BoundVar> for CanonicalVarValues<'tcx> { + type Output = GenericArg<'tcx>; + + fn index(&self, value: BoundVar) -> &GenericArg<'tcx> { + &self.var_values[value] + } +} diff --git a/src/librustc/infer/types/mod.rs b/src/librustc/infer/types/mod.rs new file mode 100644 index 00000000000..534f4cb179c --- /dev/null +++ b/src/librustc/infer/types/mod.rs @@ -0,0 +1,31 @@ +pub mod canonical; + +use crate::ty::Region; +use crate::ty::Ty; +use rustc_data_structures::sync::Lrc; +use rustc_hir::def_id::DefId; +use rustc_span::Span; + +/// Requires that `region` must be equal to one of the regions in `choice_regions`. +/// We often denote this using the syntax: +/// +/// ``` +/// R0 member of [O1..On] +/// ``` +#[derive(Debug, Clone, HashStable, TypeFoldable, Lift)] +pub struct MemberConstraint<'tcx> { + /// The `DefId` of the opaque type causing this constraint: used for error reporting. + pub opaque_type_def_id: DefId, + + /// The span where the hidden type was instantiated. + pub definition_span: Span, + + /// The hidden type in which `member_region` appears: used for error reporting. + pub hidden_ty: Ty<'tcx>, + + /// The region `R0`. + pub member_region: Region<'tcx>, + + /// The options `O1..On`. + pub choice_regions: Lrc<Vec<Region<'tcx>>>, +} diff --git a/src/librustc/infer/unify_key.rs b/src/librustc/infer/unify_key.rs index c5ec0ba73e4..d88188538fc 100644 --- a/src/librustc/infer/unify_key.rs +++ b/src/librustc/infer/unify_key.rs @@ -12,6 +12,21 @@ pub trait ToType { fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>; } +/// Raw `TyVid` are used as the unification key for `sub_relations`; +/// they carry no values. +impl UnifyKey for ty::TyVid { + type Value = (); + fn index(&self) -> u32 { + self.index + } + fn from_index(i: u32) -> ty::TyVid { + ty::TyVid { index: i } + } + fn tag() -> &'static str { + "TyVid" + } +} + impl UnifyKey for ty::IntVid { type Value = Option<IntVarValue>; fn index(&self) -> u32 { diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 744ee1a65e1..2f77792f7a1 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -36,7 +36,7 @@ #![feature(drain_filter)] #![feature(never_type)] #![feature(exhaustive_patterns)] -#![feature(overlapping_marker_traits)] +#![feature(marker_trait_attr)] #![feature(extern_types)] #![feature(nll)] #![feature(optin_builtin_traits)] diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 37d5e23535b..228271e0c4c 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -310,6 +310,11 @@ rustc_queries! { /// Maps from a trait item to the trait item "descriptor". query associated_item(_: DefId) -> ty::AssocItem {} + /// Collects the associated items defined on a trait or impl. + query associated_items(key: DefId) -> ty::AssocItemsIterator<'tcx> { + desc { |tcx| "collecting associated items of {}", tcx.def_path_str(key) } + } + query impl_trait_ref(_: DefId) -> Option<ty::TraitRef<'tcx>> {} query impl_polarity(_: DefId) -> ty::ImplPolarity {} diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs index fdb6432f7c9..d775393a808 100644 --- a/src/librustc/traits/auto_trait.rs +++ b/src/librustc/traits/auto_trait.rs @@ -9,6 +9,7 @@ use crate::ty::fold::TypeFolder; use crate::ty::{Region, RegionVid}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use syntax::ast; use std::collections::hash_map::Entry; use std::collections::VecDeque; diff --git a/src/librustc/traits/error_reporting/suggestions.rs b/src/librustc/traits/error_reporting/suggestions.rs index c1facd34dfe..b2973c642a2 100644 --- a/src/librustc/traits/error_reporting/suggestions.rs +++ b/src/librustc/traits/error_reporting/suggestions.rs @@ -1646,8 +1646,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let current_limit = self.tcx.sess.recursion_limit.get(); let suggested_limit = current_limit * 2; err.help(&format!( - "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", - suggested_limit + "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)", + suggested_limit, self.tcx.crate_name, )); } } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index daaba95cf6b..e88f4e65c7e 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -19,32 +19,25 @@ mod select; mod specialize; mod structural_impls; mod structural_match; +mod types; mod util; pub mod wf; use crate::infer::outlives::env::OutlivesEnvironment; use crate::infer::{InferCtxt, SuppressRegionErrors}; use crate::middle::region; -use crate::mir::interpret::ErrorHandled; use crate::ty::error::{ExpectedFound, TypeError}; -use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; +use crate::ty::fold::TypeFoldable; use crate::ty::subst::{InternalSubsts, SubstsRef}; -use crate::ty::{self, AdtKind, GenericParamDefKind, List, ToPredicate, Ty, TyCtxt, WithConstness}; +use crate::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, WithConstness}; use crate::util::common::ErrorReported; -use chalk_engine; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_macros::HashStable; use rustc_span::{Span, DUMMY_SP}; -use syntax::ast; use std::fmt::Debug; -use std::rc::Rc; pub use self::FulfillmentErrorCode::*; -pub use self::ObligationCauseCode::*; -pub use self::SelectionError::*; -pub use self::Vtable::*; pub use self::coherence::{add_placeholder_note, orphan_check, overlapping_impls}; pub use self::coherence::{OrphanCheckErr, OverlapResult}; @@ -58,9 +51,8 @@ pub use self::object_safety::ObjectSafetyViolation; pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote}; pub use self::project::MismatchedProjectionTypes; pub use self::project::{normalize, normalize_projection_type, poly_project_and_unify_type}; -pub use self::project::{Normalized, ProjectionCache, ProjectionCacheSnapshot, Reveal}; -pub use self::select::{EvaluationCache, SelectionCache, SelectionContext}; -pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError}; +pub use self::project::{Normalized, ProjectionCache, ProjectionCacheSnapshot}; +pub use self::select::{IntercrateAmbiguityCause, SelectionContext}; pub use self::specialize::find_associated_item; pub use self::specialize::specialization_graph::FutureCompatOverlapError; pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind; @@ -82,10 +74,7 @@ pub use self::chalk_fulfill::{ CanonicalGoal as ChalkCanonicalGoal, FulfillmentContext as ChalkFulfillmentContext, }; -pub use self::FulfillmentErrorCode::*; -pub use self::ObligationCauseCode::*; -pub use self::SelectionError::*; -pub use self::Vtable::*; +pub use self::types::*; /// Whether to enable bug compatibility with issue #43355. #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -139,392 +128,12 @@ pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>; #[cfg(target_arch = "x86_64")] static_assert_size!(PredicateObligation<'_>, 112); -/// The reason why we incurred this obligation; used for error reporting. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct ObligationCause<'tcx> { - pub span: Span, - - /// The ID of the fn body that triggered this obligation. This is - /// used for region obligations to determine the precise - /// environment in which the region obligation should be evaluated - /// (in particular, closures can add new assumptions). See the - /// field `region_obligations` of the `FulfillmentContext` for more - /// information. - pub body_id: hir::HirId, - - pub code: ObligationCauseCode<'tcx>, -} - -impl ObligationCause<'_> { - pub fn span(&self, tcx: TyCtxt<'_>) -> Span { - match self.code { - ObligationCauseCode::CompareImplMethodObligation { .. } - | ObligationCauseCode::MainFunctionType - | ObligationCauseCode::StartFunctionType => tcx.sess.source_map().def_span(self.span), - ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { - arm_span, - .. - }) => arm_span, - _ => self.span, - } - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub enum ObligationCauseCode<'tcx> { - /// Not well classified or should be obvious from the span. - MiscObligation, - - /// A slice or array is WF only if `T: Sized`. - SliceOrArrayElem, - - /// A tuple is WF only if its middle elements are `Sized`. - TupleElem, - - /// This is the trait reference from the given projection. - ProjectionWf(ty::ProjectionTy<'tcx>), - - /// In an impl of trait `X` for type `Y`, type `Y` must - /// also implement all supertraits of `X`. - ItemObligation(DefId), - - /// Like `ItemObligation`, but with extra detail on the source of the obligation. - BindingObligation(DefId, Span), - - /// A type like `&'a T` is WF only if `T: 'a`. - ReferenceOutlivesReferent(Ty<'tcx>), - - /// A type like `Box<Foo<'a> + 'b>` is WF only if `'b: 'a`. - ObjectTypeBound(Ty<'tcx>, ty::Region<'tcx>), - - /// Obligation incurred due to an object cast. - ObjectCastObligation(/* Object type */ Ty<'tcx>), - - /// Obligation incurred due to a coercion. - Coercion { - source: Ty<'tcx>, - target: Ty<'tcx>, - }, - - /// Various cases where expressions must be `Sized` / `Copy` / etc. - /// `L = X` implies that `L` is `Sized`. - AssignmentLhsSized, - /// `(x1, .., xn)` must be `Sized`. - TupleInitializerSized, - /// `S { ... }` must be `Sized`. - StructInitializerSized, - /// Type of each variable must be `Sized`. - VariableType(hir::HirId), - /// Argument type must be `Sized`. - SizedArgumentType, - /// Return type must be `Sized`. - SizedReturnType, - /// Yield type must be `Sized`. - SizedYieldType, - /// `[T, ..n]` implies that `T` must be `Copy`. - /// If `true`, suggest `const_in_array_repeat_expressions` feature flag. - RepeatVec(bool), - - /// Types of fields (other than the last, except for packed structs) in a struct must be sized. - FieldSized { - adt_kind: AdtKind, - last: bool, - }, - - /// Constant expressions must be sized. - ConstSized, - - /// `static` items must have `Sync` type. - SharedStatic, - - BuiltinDerivedObligation(DerivedObligationCause<'tcx>), - - ImplDerivedObligation(DerivedObligationCause<'tcx>), - - /// Error derived when matching traits/impls; see ObligationCause for more details - CompareImplMethodObligation { - item_name: ast::Name, - impl_item_def_id: DefId, - trait_item_def_id: DefId, - }, - - /// Error derived when matching traits/impls; see ObligationCause for more details - CompareImplTypeObligation { - item_name: ast::Name, - impl_item_def_id: DefId, - trait_item_def_id: DefId, - }, - - /// Checking that this expression can be assigned where it needs to be - // FIXME(eddyb) #11161 is the original Expr required? - ExprAssignable, - - /// Computing common supertype in the arms of a match expression - MatchExpressionArm(Box<MatchExpressionArmCause<'tcx>>), - - /// Type error arising from type checking a pattern against an expected type. - Pattern { - /// The span of the scrutinee or type expression which caused the `root_ty` type. - span: Option<Span>, - /// The root expected type induced by a scrutinee or type expression. - root_ty: Ty<'tcx>, - /// Whether the `Span` came from an expression or a type expression. - origin_expr: bool, - }, - - /// Constants in patterns must have `Structural` type. - ConstPatternStructural, - - /// Computing common supertype in an if expression - IfExpression(Box<IfExpressionCause>), - - /// Computing common supertype of an if expression with no else counter-part - IfExpressionWithNoElse, - - /// `main` has wrong type - MainFunctionType, - - /// `start` has wrong type - StartFunctionType, - - /// Intrinsic has wrong type - IntrinsicType, - - /// Method receiver - MethodReceiver, - - /// `return` with no expression - ReturnNoExpression, - - /// `return` with an expression - ReturnValue(hir::HirId), - - /// Return type of this function - ReturnType, - - /// Block implicit return - BlockTailExpression(hir::HirId), - - /// #[feature(trivial_bounds)] is not enabled - TrivialBound, - - AssocTypeBound(Box<AssocTypeBoundData>), -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct AssocTypeBoundData { - pub impl_span: Option<Span>, - pub original: Span, - pub bounds: Vec<Span>, -} - -// `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(target_arch = "x86_64")] -static_assert_size!(ObligationCauseCode<'_>, 32); - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct MatchExpressionArmCause<'tcx> { - pub arm_span: Span, - pub source: hir::MatchSource, - pub prior_arms: Vec<Span>, - pub last_ty: Ty<'tcx>, - pub scrut_hir_id: hir::HirId, -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct IfExpressionCause { - pub then: Span, - pub outer: Option<Span>, - pub semicolon: Option<Span>, -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct DerivedObligationCause<'tcx> { - /// The trait reference of the parent obligation that led to the - /// current obligation. Note that only trait obligations lead to - /// derived obligations, so we just store the trait reference here - /// directly. - parent_trait_ref: ty::PolyTraitRef<'tcx>, - - /// The parent trait had this cause. - parent_code: Rc<ObligationCauseCode<'tcx>>, -} - pub type Obligations<'tcx, O> = Vec<Obligation<'tcx, O>>; pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>; pub type TraitObligations<'tcx> = Vec<TraitObligation<'tcx>>; -/// The following types: -/// * `WhereClause`, -/// * `WellFormed`, -/// * `FromEnv`, -/// * `DomainGoal`, -/// * `Goal`, -/// * `Clause`, -/// * `Environment`, -/// * `InEnvironment`, -/// are used for representing the trait system in the form of -/// logic programming clauses. They are part of the interface -/// for the chalk SLG solver. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)] -pub enum WhereClause<'tcx> { - Implemented(ty::TraitPredicate<'tcx>), - ProjectionEq(ty::ProjectionPredicate<'tcx>), - RegionOutlives(ty::RegionOutlivesPredicate<'tcx>), - TypeOutlives(ty::TypeOutlivesPredicate<'tcx>), -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)] -pub enum WellFormed<'tcx> { - Trait(ty::TraitPredicate<'tcx>), - Ty(Ty<'tcx>), -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)] -pub enum FromEnv<'tcx> { - Trait(ty::TraitPredicate<'tcx>), - Ty(Ty<'tcx>), -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)] -pub enum DomainGoal<'tcx> { - Holds(WhereClause<'tcx>), - WellFormed(WellFormed<'tcx>), - FromEnv(FromEnv<'tcx>), - Normalize(ty::ProjectionPredicate<'tcx>), -} - -pub type PolyDomainGoal<'tcx> = ty::Binder<DomainGoal<'tcx>>; - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable)] -pub enum QuantifierKind { - Universal, - Existential, -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)] -pub enum GoalKind<'tcx> { - Implies(Clauses<'tcx>, Goal<'tcx>), - And(Goal<'tcx>, Goal<'tcx>), - Not(Goal<'tcx>), - DomainGoal(DomainGoal<'tcx>), - Quantified(QuantifierKind, ty::Binder<Goal<'tcx>>), - Subtype(Ty<'tcx>, Ty<'tcx>), - CannotProve, -} - -pub type Goal<'tcx> = &'tcx GoalKind<'tcx>; - -pub type Goals<'tcx> = &'tcx List<Goal<'tcx>>; - -impl<'tcx> DomainGoal<'tcx> { - pub fn into_goal(self) -> GoalKind<'tcx> { - GoalKind::DomainGoal(self) - } - - pub fn into_program_clause(self) -> ProgramClause<'tcx> { - ProgramClause { - goal: self, - hypotheses: ty::List::empty(), - category: ProgramClauseCategory::Other, - } - } -} - -impl<'tcx> GoalKind<'tcx> { - pub fn from_poly_domain_goal( - domain_goal: PolyDomainGoal<'tcx>, - tcx: TyCtxt<'tcx>, - ) -> GoalKind<'tcx> { - match domain_goal.no_bound_vars() { - Some(p) => p.into_goal(), - None => GoalKind::Quantified( - QuantifierKind::Universal, - domain_goal.map_bound(|p| tcx.mk_goal(p.into_goal())), - ), - } - } -} - -/// This matches the definition from Page 7 of "A Proof Procedure for the Logic of Hereditary -/// Harrop Formulas". -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)] -pub enum Clause<'tcx> { - Implies(ProgramClause<'tcx>), - ForAll(ty::Binder<ProgramClause<'tcx>>), -} - -impl Clause<'tcx> { - pub fn category(self) -> ProgramClauseCategory { - match self { - Clause::Implies(clause) => clause.category, - Clause::ForAll(clause) => clause.skip_binder().category, - } - } -} - -/// Multiple clauses. -pub type Clauses<'tcx> = &'tcx List<Clause<'tcx>>; - -/// A "program clause" has the form `D :- G1, ..., Gn`. It is saying -/// that the domain goal `D` is true if `G1...Gn` are provable. This -/// is equivalent to the implication `G1..Gn => D`; we usually write -/// it with the reverse implication operator `:-` to emphasize the way -/// that programs are actually solved (via backchaining, which starts -/// with the goal to solve and proceeds from there). -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)] -pub struct ProgramClause<'tcx> { - /// This goal will be considered true ... - pub goal: DomainGoal<'tcx>, - - /// ... if we can prove these hypotheses (there may be no hypotheses at all): - pub hypotheses: Goals<'tcx>, - - /// Useful for filtering clauses. - pub category: ProgramClauseCategory, -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable)] -pub enum ProgramClauseCategory { - ImpliedBound, - WellFormed, - Other, -} - -/// A set of clauses that we assume to be true. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)] -pub struct Environment<'tcx> { - pub clauses: Clauses<'tcx>, -} - -impl Environment<'tcx> { - pub fn with<G>(self, goal: G) -> InEnvironment<'tcx, G> { - InEnvironment { environment: self, goal } - } -} - -/// Something (usually a goal), along with an environment. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)] -pub struct InEnvironment<'tcx, G> { - pub environment: Environment<'tcx>, - pub goal: G, -} - pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>; -#[derive(Clone, Debug, TypeFoldable)] -pub enum SelectionError<'tcx> { - Unimplemented, - OutputTypeParameterMismatch( - ty::PolyTraitRef<'tcx>, - ty::PolyTraitRef<'tcx>, - ty::error::TypeError<'tcx>, - ), - TraitNotObjectSafe(DefId), - ConstEvalFailure(ErrorHandled), - Overflow, -} - pub struct FulfillmentError<'tcx> { pub obligation: PredicateObligation<'tcx>, pub code: FulfillmentErrorCode<'tcx>, @@ -542,164 +151,6 @@ pub enum FulfillmentErrorCode<'tcx> { CodeAmbiguity, } -/// When performing resolution, it is typically the case that there -/// can be one of three outcomes: -/// -/// - `Ok(Some(r))`: success occurred with result `r` -/// - `Ok(None)`: could not definitely determine anything, usually due -/// to inconclusive type inference. -/// - `Err(e)`: error `e` occurred -pub type SelectionResult<'tcx, T> = Result<Option<T>, SelectionError<'tcx>>; - -/// Given the successful resolution of an obligation, the `Vtable` -/// indicates where the vtable comes from. Note that while we call this -/// a "vtable", it does not necessarily indicate dynamic dispatch at -/// runtime. `Vtable` instances just tell the compiler where to find -/// methods, but in generic code those methods are typically statically -/// dispatched -- only when an object is constructed is a `Vtable` -/// instance reified into an actual vtable. -/// -/// For example, the vtable may be tied to a specific impl (case A), -/// or it may be relative to some bound that is in scope (case B). -/// -/// ``` -/// impl<T:Clone> Clone<T> for Option<T> { ... } // Impl_1 -/// impl<T:Clone> Clone<T> for Box<T> { ... } // Impl_2 -/// impl Clone for int { ... } // Impl_3 -/// -/// fn foo<T:Clone>(concrete: Option<Box<int>>, -/// param: T, -/// mixed: Option<T>) { -/// -/// // Case A: Vtable points at a specific impl. Only possible when -/// // type is concretely known. If the impl itself has bounded -/// // type parameters, Vtable will carry resolutions for those as well: -/// concrete.clone(); // Vtable(Impl_1, [Vtable(Impl_2, [Vtable(Impl_3)])]) -/// -/// // Case B: Vtable must be provided by caller. This applies when -/// // type is a type parameter. -/// param.clone(); // VtableParam -/// -/// // Case C: A mix of cases A and B. -/// mixed.clone(); // Vtable(Impl_1, [VtableParam]) -/// } -/// ``` -/// -/// ### The type parameter `N` -/// -/// See explanation on `VtableImplData`. -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub enum Vtable<'tcx, N> { - /// Vtable identifying a particular impl. - VtableImpl(VtableImplData<'tcx, N>), - - /// Vtable for auto trait implementations. - /// This carries the information and nested obligations with regards - /// to an auto implementation for a trait `Trait`. The nested obligations - /// ensure the trait implementation holds for all the constituent types. - VtableAutoImpl(VtableAutoImplData<N>), - - /// Successful resolution to an obligation provided by the caller - /// for some type parameter. The `Vec<N>` represents the - /// obligations incurred from normalizing the where-clause (if - /// any). - VtableParam(Vec<N>), - - /// Virtual calls through an object. - VtableObject(VtableObjectData<'tcx, N>), - - /// Successful resolution for a builtin trait. - VtableBuiltin(VtableBuiltinData<N>), - - /// Vtable automatically generated for a closure. The `DefId` is the ID - /// of the closure expression. This is a `VtableImpl` in spirit, but the - /// impl is generated by the compiler and does not appear in the source. - VtableClosure(VtableClosureData<'tcx, N>), - - /// Same as above, but for a function pointer type with the given signature. - VtableFnPointer(VtableFnPointerData<'tcx, N>), - - /// Vtable automatically generated for a generator. - VtableGenerator(VtableGeneratorData<'tcx, N>), - - /// Vtable for a trait alias. - VtableTraitAlias(VtableTraitAliasData<'tcx, N>), -} - -/// Identifies a particular impl in the source, along with a set of -/// substitutions from the impl's type/lifetime parameters. The -/// `nested` vector corresponds to the nested obligations attached to -/// the impl's type parameters. -/// -/// The type parameter `N` indicates the type used for "nested -/// obligations" that are required by the impl. During type-check, this -/// is `Obligation`, as one might expect. During codegen, however, this -/// is `()`, because codegen only requires a shallow resolution of an -/// impl, and nested obligations are satisfied later. -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableImplData<'tcx, N> { - pub impl_def_id: DefId, - pub substs: SubstsRef<'tcx>, - pub nested: Vec<N>, -} - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableGeneratorData<'tcx, N> { - pub generator_def_id: DefId, - pub substs: SubstsRef<'tcx>, - /// Nested obligations. This can be non-empty if the generator - /// signature contains associated types. - pub nested: Vec<N>, -} - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableClosureData<'tcx, N> { - pub closure_def_id: DefId, - pub substs: SubstsRef<'tcx>, - /// Nested obligations. This can be non-empty if the closure - /// signature contains associated types. - pub nested: Vec<N>, -} - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableAutoImplData<N> { - pub trait_def_id: DefId, - pub nested: Vec<N>, -} - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableBuiltinData<N> { - pub nested: Vec<N>, -} - -/// A vtable for some object-safe trait `Foo` automatically derived -/// for the object type `Foo`. -#[derive(PartialEq, Eq, Clone, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableObjectData<'tcx, N> { - /// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`. - pub upcast_trait_ref: ty::PolyTraitRef<'tcx>, - - /// The vtable is formed by concatenating together the method lists of - /// the base object trait and all supertraits; this is the start of - /// `upcast_trait_ref`'s methods in that vtable. - pub vtable_base: usize, - - pub nested: Vec<N>, -} - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableFnPointerData<'tcx, N> { - pub fn_ty: Ty<'tcx>, - pub nested: Vec<N>, -} - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableTraitAliasData<'tcx, N> { - pub alias_def_id: DefId, - pub substs: SubstsRef<'tcx>, - pub nested: Vec<N>, -} - /// Creates predicate obligations from the generic bounds. pub fn predicates_for_generics<'tcx>( cause: ObligationCause<'tcx>, @@ -1148,97 +599,6 @@ impl<'tcx, O> Obligation<'tcx, O> { } } -impl<'tcx> ObligationCause<'tcx> { - #[inline] - pub fn new( - span: Span, - body_id: hir::HirId, - code: ObligationCauseCode<'tcx>, - ) -> ObligationCause<'tcx> { - ObligationCause { span, body_id, code } - } - - pub fn misc(span: Span, body_id: hir::HirId) -> ObligationCause<'tcx> { - ObligationCause { span, body_id, code: MiscObligation } - } - - pub fn dummy() -> ObligationCause<'tcx> { - ObligationCause { span: DUMMY_SP, body_id: hir::CRATE_HIR_ID, code: MiscObligation } - } -} - -impl ObligationCauseCode<'_> { - // Return the base obligation, ignoring derived obligations. - pub fn peel_derives(&self) -> &Self { - let mut base_cause = self; - while let BuiltinDerivedObligation(cause) | ImplDerivedObligation(cause) = base_cause { - base_cause = &cause.parent_code; - } - base_cause - } -} - -impl<'tcx, N> Vtable<'tcx, N> { - pub fn nested_obligations(self) -> Vec<N> { - match self { - VtableImpl(i) => i.nested, - VtableParam(n) => n, - VtableBuiltin(i) => i.nested, - VtableAutoImpl(d) => d.nested, - VtableClosure(c) => c.nested, - VtableGenerator(c) => c.nested, - VtableObject(d) => d.nested, - VtableFnPointer(d) => d.nested, - VtableTraitAlias(d) => d.nested, - } - } - - pub fn map<M, F>(self, f: F) -> Vtable<'tcx, M> - where - F: FnMut(N) -> M, - { - match self { - VtableImpl(i) => VtableImpl(VtableImplData { - impl_def_id: i.impl_def_id, - substs: i.substs, - nested: i.nested.into_iter().map(f).collect(), - }), - VtableParam(n) => VtableParam(n.into_iter().map(f).collect()), - VtableBuiltin(i) => { - VtableBuiltin(VtableBuiltinData { nested: i.nested.into_iter().map(f).collect() }) - } - VtableObject(o) => VtableObject(VtableObjectData { - upcast_trait_ref: o.upcast_trait_ref, - vtable_base: o.vtable_base, - nested: o.nested.into_iter().map(f).collect(), - }), - VtableAutoImpl(d) => VtableAutoImpl(VtableAutoImplData { - trait_def_id: d.trait_def_id, - nested: d.nested.into_iter().map(f).collect(), - }), - VtableClosure(c) => VtableClosure(VtableClosureData { - closure_def_id: c.closure_def_id, - substs: c.substs, - nested: c.nested.into_iter().map(f).collect(), - }), - VtableGenerator(c) => VtableGenerator(VtableGeneratorData { - generator_def_id: c.generator_def_id, - substs: c.substs, - nested: c.nested.into_iter().map(f).collect(), - }), - VtableFnPointer(p) => VtableFnPointer(VtableFnPointerData { - fn_ty: p.fn_ty, - nested: p.nested.into_iter().map(f).collect(), - }), - VtableTraitAlias(d) => VtableTraitAlias(VtableTraitAliasData { - alias_def_id: d.alias_def_id, - substs: d.substs, - nested: d.nested.into_iter().map(f).collect(), - }), - } - } -} - impl<'tcx> FulfillmentError<'tcx> { fn new( obligation: PredicateObligation<'tcx>, @@ -1266,42 +626,3 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { ..*providers }; } - -pub trait ExClauseFold<'tcx> -where - Self: chalk_engine::context::Context + Clone, -{ - fn fold_ex_clause_with<F: TypeFolder<'tcx>>( - ex_clause: &chalk_engine::ExClause<Self>, - folder: &mut F, - ) -> chalk_engine::ExClause<Self>; - - fn visit_ex_clause_with<V: TypeVisitor<'tcx>>( - ex_clause: &chalk_engine::ExClause<Self>, - visitor: &mut V, - ) -> bool; -} - -pub trait ChalkContextLift<'tcx> -where - Self: chalk_engine::context::Context + Clone, -{ - type LiftedExClause: Debug + 'tcx; - type LiftedDelayedLiteral: Debug + 'tcx; - type LiftedLiteral: Debug + 'tcx; - - fn lift_ex_clause_to_tcx( - ex_clause: &chalk_engine::ExClause<Self>, - tcx: TyCtxt<'tcx>, - ) -> Option<Self::LiftedExClause>; - - fn lift_delayed_literal_to_tcx( - ex_clause: &chalk_engine::DelayedLiteral<Self>, - tcx: TyCtxt<'tcx>, - ) -> Option<Self::LiftedDelayedLiteral>; - - fn lift_literal_to_tcx( - ex_clause: &chalk_engine::Literal<Self>, - tcx: TyCtxt<'tcx>, - ) -> Option<Self::LiftedLiteral>; -} diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 3085837335a..fffcf66075f 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -19,52 +19,11 @@ use crate::ty::subst::{InternalSubsts, Subst}; use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness}; use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap}; use rustc_hir::def_id::DefId; -use rustc_macros::HashStable; use rustc_span::symbol::sym; use rustc_span::DUMMY_SP; use syntax::ast::Ident; -/// Depending on the stage of compilation, we want projection to be -/// more or less conservative. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)] -pub enum Reveal { - /// At type-checking time, we refuse to project any associated - /// type that is marked `default`. Non-`default` ("final") types - /// are always projected. This is necessary in general for - /// soundness of specialization. However, we *could* allow - /// projections in fully-monomorphic cases. We choose not to, - /// because we prefer for `default type` to force the type - /// definition to be treated abstractly by any consumers of the - /// impl. Concretely, that means that the following example will - /// fail to compile: - /// - /// ``` - /// trait Assoc { - /// type Output; - /// } - /// - /// impl<T> Assoc for T { - /// default type Output = bool; - /// } - /// - /// fn main() { - /// let <() as Assoc>::Output = true; - /// } - UserFacing, - - /// At codegen time, all monomorphic projections will succeed. - /// Also, `impl Trait` is normalized to the concrete type, - /// which has to be already collected by type-checking. - /// - /// NOTE: as `impl Trait`'s concrete type should *never* - /// be observable directly by the user, `Reveal::All` - /// should not be used by checks which may expose - /// type equality or type contents to the user. - /// There are some exceptions, e.g., around OIBITS and - /// transmute-checking, which expose some details, but - /// not the whole concrete type of the `impl Trait`. - All, -} +pub use rustc::traits::Reveal; pub type PolyProjectionObligation<'tcx> = Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>; diff --git a/src/librustc/traits/query/dropck_outlives.rs b/src/librustc/traits/query/dropck_outlives.rs index 2e5ef5adcd3..a1d7a2836e4 100644 --- a/src/librustc/traits/query/dropck_outlives.rs +++ b/src/librustc/traits/query/dropck_outlives.rs @@ -1,10 +1,11 @@ use crate::infer::at::At; use crate::infer::canonical::OriginalQueryValues; use crate::infer::InferOk; -use crate::ty::subst::GenericArg; -use crate::ty::{self, Ty, TyCtxt}; -use rustc_span::source_map::Span; -use std::iter::FromIterator; + +use rustc::ty::subst::GenericArg; +use rustc::ty::{self, Ty, TyCtxt}; + +pub use rustc::traits::query::{DropckOutlivesResult, DtorckConstraint}; impl<'cx, 'tcx> At<'cx, 'tcx> { /// Given a type `ty` of some value being dropped, computes a set @@ -65,76 +66,6 @@ impl<'cx, 'tcx> At<'cx, 'tcx> { } } -#[derive(Clone, Debug, Default, HashStable, TypeFoldable, Lift)] -pub struct DropckOutlivesResult<'tcx> { - pub kinds: Vec<GenericArg<'tcx>>, - pub overflows: Vec<Ty<'tcx>>, -} - -impl<'tcx> DropckOutlivesResult<'tcx> { - pub fn report_overflows(&self, tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) { - if let Some(overflow_ty) = self.overflows.iter().next() { - rustc_errors::struct_span_err!( - tcx.sess, - span, - E0320, - "overflow while adding drop-check rules for {}", - ty, - ) - .note(&format!("overflowed on {}", overflow_ty)) - .emit(); - } - } - - pub fn into_kinds_reporting_overflows( - self, - tcx: TyCtxt<'tcx>, - span: Span, - ty: Ty<'tcx>, - ) -> Vec<GenericArg<'tcx>> { - self.report_overflows(tcx, span, ty); - let DropckOutlivesResult { kinds, overflows: _ } = self; - kinds - } -} - -/// A set of constraints that need to be satisfied in order for -/// a type to be valid for destruction. -#[derive(Clone, Debug, HashStable)] -pub struct DtorckConstraint<'tcx> { - /// Types that are required to be alive in order for this - /// type to be valid for destruction. - pub outlives: Vec<ty::subst::GenericArg<'tcx>>, - - /// Types that could not be resolved: projections and params. - pub dtorck_types: Vec<Ty<'tcx>>, - - /// If, during the computation of the dtorck constraint, we - /// overflow, that gets recorded here. The caller is expected to - /// report an error. - pub overflows: Vec<Ty<'tcx>>, -} - -impl<'tcx> DtorckConstraint<'tcx> { - pub fn empty() -> DtorckConstraint<'tcx> { - DtorckConstraint { outlives: vec![], dtorck_types: vec![], overflows: vec![] } - } -} - -impl<'tcx> FromIterator<DtorckConstraint<'tcx>> for DtorckConstraint<'tcx> { - fn from_iter<I: IntoIterator<Item = DtorckConstraint<'tcx>>>(iter: I) -> Self { - let mut result = Self::empty(); - - for DtorckConstraint { outlives, dtorck_types, overflows } in iter { - result.outlives.extend(outlives); - result.dtorck_types.extend(dtorck_types); - result.overflows.extend(overflows); - } - - result - } -} - /// This returns true if the type `ty` is "trivial" for /// dropck-outlives -- that is, if it doesn't require any types to /// outlive. This is similar but not *quite* the same as the diff --git a/src/librustc/traits/query/method_autoderef.rs b/src/librustc/traits/query/method_autoderef.rs index 4ef775750ec..80748c5ef38 100644 --- a/src/librustc/traits/query/method_autoderef.rs +++ b/src/librustc/traits/query/method_autoderef.rs @@ -1,33 +1 @@ -use crate::infer::canonical::{Canonical, QueryResponse}; -use crate::ty::Ty; -use rustc_data_structures::sync::Lrc; - -#[derive(Debug, HashStable)] -pub struct CandidateStep<'tcx> { - pub self_ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, - pub autoderefs: usize, - /// `true` if the type results from a dereference of a raw pointer. - /// when assembling candidates, we include these steps, but not when - /// picking methods. This so that if we have `foo: *const Foo` and `Foo` has methods - /// `fn by_raw_ptr(self: *const Self)` and `fn by_ref(&self)`, then - /// `foo.by_raw_ptr()` will work and `foo.by_ref()` won't. - pub from_unsafe_deref: bool, - pub unsize: bool, -} - -#[derive(Clone, Debug, HashStable)] -pub struct MethodAutoderefStepsResult<'tcx> { - /// The valid autoderef steps that could be find. - pub steps: Lrc<Vec<CandidateStep<'tcx>>>, - /// If Some(T), a type autoderef reported an error on. - pub opt_bad_ty: Option<Lrc<MethodAutoderefBadTy<'tcx>>>, - /// If `true`, `steps` has been truncated due to reaching the - /// recursion limit. - pub reached_recursion_limit: bool, -} - -#[derive(Debug, HashStable)] -pub struct MethodAutoderefBadTy<'tcx> { - pub reached_raw_pointer: bool, - pub ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, -} +pub use rustc::traits::query::{CandidateStep, MethodAutoderefBadTy, MethodAutoderefStepsResult}; diff --git a/src/librustc/traits/query/mod.rs b/src/librustc/traits/query/mod.rs index 440268aab8f..20a873dc4c6 100644 --- a/src/librustc/traits/query/mod.rs +++ b/src/librustc/traits/query/mod.rs @@ -5,10 +5,6 @@ //! The providers for the queries defined here can be found in //! `librustc_traits`. -use crate::infer::canonical::Canonical; -use crate::ty::error::TypeError; -use crate::ty::{self, Ty}; - pub mod dropck_outlives; pub mod evaluate_obligation; pub mod method_autoderef; @@ -16,35 +12,4 @@ pub mod normalize; pub mod outlives_bounds; pub mod type_op; -pub type CanonicalProjectionGoal<'tcx> = - Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::ProjectionTy<'tcx>>>; - -pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>; - -pub type CanonicalPredicateGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>>; - -pub type CanonicalTypeOpAscribeUserTypeGoal<'tcx> = - Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::ascribe_user_type::AscribeUserType<'tcx>>>; - -pub type CanonicalTypeOpEqGoal<'tcx> = - Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::eq::Eq<'tcx>>>; - -pub type CanonicalTypeOpSubtypeGoal<'tcx> = - Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::subtype::Subtype<'tcx>>>; - -pub type CanonicalTypeOpProvePredicateGoal<'tcx> = - Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>; - -pub type CanonicalTypeOpNormalizeGoal<'tcx, T> = - Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::normalize::Normalize<T>>>; - -#[derive(Clone, Debug, HashStable)] -pub struct NoSolution; - -pub type Fallible<T> = Result<T, NoSolution>; - -impl<'tcx> From<TypeError<'tcx>> for NoSolution { - fn from(_: TypeError<'tcx>) -> NoSolution { - NoSolution - } -} +pub use rustc::traits::types::query::*; diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs index 20d7b556377..737b4fc6bb9 100644 --- a/src/librustc/traits/query/normalize.rs +++ b/src/librustc/traits/query/normalize.rs @@ -13,6 +13,8 @@ use crate::ty::{self, Ty, TyCtxt}; use super::NoSolution; +pub use rustc::traits::query::NormalizationResult; + impl<'cx, 'tcx> At<'cx, 'tcx> { /// Normalize `value` in the context of the inference context, /// yielding a resulting type, or an error if `value` cannot be @@ -59,13 +61,6 @@ impl<'cx, 'tcx> At<'cx, 'tcx> { } } -/// Result from the `normalize_projection_ty` query. -#[derive(Clone, Debug, HashStable, TypeFoldable, Lift)] -pub struct NormalizationResult<'tcx> { - /// Result of normalization. - pub normalized_ty: Ty<'tcx>, -} - struct QueryNormalizer<'cx, 'tcx> { infcx: &'cx InferCtxt<'cx, 'tcx>, cause: &'cx ObligationCause<'tcx>, diff --git a/src/librustc/traits/query/outlives_bounds.rs b/src/librustc/traits/query/outlives_bounds.rs index 07e57e847b1..594faffa5f3 100644 --- a/src/librustc/traits/query/outlives_bounds.rs +++ b/src/librustc/traits/query/outlives_bounds.rs @@ -6,43 +6,7 @@ use crate::ty::{self, Ty}; use rustc_hir as hir; use rustc_span::source_map::Span; -use crate::ich::StableHashingContext; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use std::mem; - -/// Outlives bounds are relationships between generic parameters, -/// whether they both be regions (`'a: 'b`) or whether types are -/// involved (`T: 'a`). These relationships can be extracted from the -/// full set of predicates we understand or also from types (in which -/// case they are called implied bounds). They are fed to the -/// `OutlivesEnv` which in turn is supplied to the region checker and -/// other parts of the inference system. -#[derive(Clone, Debug, TypeFoldable, Lift)] -pub enum OutlivesBound<'tcx> { - RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>), - RegionSubParam(ty::Region<'tcx>, ty::ParamTy), - RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>), -} - -impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for OutlivesBound<'tcx> { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - mem::discriminant(self).hash_stable(hcx, hasher); - match *self { - OutlivesBound::RegionSubRegion(ref a, ref b) => { - a.hash_stable(hcx, hasher); - b.hash_stable(hcx, hasher); - } - OutlivesBound::RegionSubParam(ref a, ref b) => { - a.hash_stable(hcx, hasher); - b.hash_stable(hcx, hasher); - } - OutlivesBound::RegionSubProjection(ref a, ref b) => { - a.hash_stable(hcx, hasher); - b.hash_stable(hcx, hasher); - } - } - } -} +pub use rustc::traits::query::OutlivesBound; impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// Implied bounds are region relationships that we deduce diff --git a/src/librustc/traits/query/type_op/ascribe_user_type.rs b/src/librustc/traits/query/type_op/ascribe_user_type.rs index 46b656eb945..b14b79f0907 100644 --- a/src/librustc/traits/query/type_op/ascribe_user_type.rs +++ b/src/librustc/traits/query/type_op/ascribe_user_type.rs @@ -1,21 +1,8 @@ use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; use crate::traits::query::Fallible; -use crate::ty::subst::UserSubsts; -use crate::ty::{ParamEnvAnd, Ty, TyCtxt}; -use rustc_hir::def_id::DefId; +use rustc::ty::{ParamEnvAnd, TyCtxt}; -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)] -pub struct AscribeUserType<'tcx> { - pub mir_ty: Ty<'tcx>, - pub def_id: DefId, - pub user_substs: UserSubsts<'tcx>, -} - -impl<'tcx> AscribeUserType<'tcx> { - pub fn new(mir_ty: Ty<'tcx>, def_id: DefId, user_substs: UserSubsts<'tcx>) -> Self { - Self { mir_ty, def_id, user_substs } - } -} +pub use rustc::traits::query::type_op::AscribeUserType; impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> { type QueryResponse = (); diff --git a/src/librustc/traits/query/type_op/eq.rs b/src/librustc/traits/query/type_op/eq.rs index 267722362c5..1de13430d46 100644 --- a/src/librustc/traits/query/type_op/eq.rs +++ b/src/librustc/traits/query/type_op/eq.rs @@ -1,18 +1,8 @@ use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; use crate::traits::query::Fallible; -use crate::ty::{ParamEnvAnd, Ty, TyCtxt}; +use crate::ty::{ParamEnvAnd, TyCtxt}; -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)] -pub struct Eq<'tcx> { - pub a: Ty<'tcx>, - pub b: Ty<'tcx>, -} - -impl<'tcx> Eq<'tcx> { - pub fn new(a: Ty<'tcx>, b: Ty<'tcx>) -> Self { - Self { a, b } - } -} +pub use rustc::traits::query::type_op::Eq; impl<'tcx> super::QueryTypeOp<'tcx> for Eq<'tcx> { type QueryResponse = (); diff --git a/src/librustc/traits/query/type_op/mod.rs b/src/librustc/traits/query/type_op/mod.rs index adf63e4d60c..2d03d77cf66 100644 --- a/src/librustc/traits/query/type_op/mod.rs +++ b/src/librustc/traits/query/type_op/mod.rs @@ -19,6 +19,8 @@ pub mod prove_predicate; use self::prove_predicate::ProvePredicate; pub mod subtype; +pub use crate::traits::types::query::type_op::*; + /// "Type ops" are used in NLL to perform some particular action and /// extract out the resulting region constraints (or an error if it /// cannot be completed). diff --git a/src/librustc/traits/query/type_op/normalize.rs b/src/librustc/traits/query/type_op/normalize.rs index 8a028eecd5b..b1e0e29620d 100644 --- a/src/librustc/traits/query/type_op/normalize.rs +++ b/src/librustc/traits/query/type_op/normalize.rs @@ -4,19 +4,7 @@ use crate::ty::fold::TypeFoldable; use crate::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt}; use std::fmt; -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)] -pub struct Normalize<T> { - pub value: T, -} - -impl<'tcx, T> Normalize<T> -where - T: fmt::Debug + TypeFoldable<'tcx>, -{ - pub fn new(value: T) -> Self { - Self { value } - } -} +pub use rustc::traits::query::type_op::Normalize; impl<'tcx, T> super::QueryTypeOp<'tcx> for Normalize<T> where diff --git a/src/librustc/traits/query/type_op/prove_predicate.rs b/src/librustc/traits/query/type_op/prove_predicate.rs index 15870ec95d8..92cfb82e27e 100644 --- a/src/librustc/traits/query/type_op/prove_predicate.rs +++ b/src/librustc/traits/query/type_op/prove_predicate.rs @@ -2,16 +2,7 @@ use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; use crate::traits::query::Fallible; use crate::ty::{ParamEnvAnd, Predicate, TyCtxt}; -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)] -pub struct ProvePredicate<'tcx> { - pub predicate: Predicate<'tcx>, -} - -impl<'tcx> ProvePredicate<'tcx> { - pub fn new(predicate: Predicate<'tcx>) -> Self { - ProvePredicate { predicate } - } -} +pub use rustc::traits::query::type_op::ProvePredicate; impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { type QueryResponse = (); diff --git a/src/librustc/traits/query/type_op/subtype.rs b/src/librustc/traits/query/type_op/subtype.rs index c70508a20a1..2877a74aaff 100644 --- a/src/librustc/traits/query/type_op/subtype.rs +++ b/src/librustc/traits/query/type_op/subtype.rs @@ -1,18 +1,8 @@ use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; use crate::traits::query::Fallible; -use crate::ty::{ParamEnvAnd, Ty, TyCtxt}; +use crate::ty::{ParamEnvAnd, TyCtxt}; -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)] -pub struct Subtype<'tcx> { - pub sub: Ty<'tcx>, - pub sup: Ty<'tcx>, -} - -impl<'tcx> Subtype<'tcx> { - pub fn new(sub: Ty<'tcx>, sup: Ty<'tcx>) -> Self { - Self { sub, sup } - } -} +pub use rustc::traits::query::type_op::Subtype; impl<'tcx> super::QueryTypeOp<'tcx> for Subtype<'tcx> { type QueryResponse = (); diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index ba0a270638c..e4ef68c167f 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -41,7 +41,6 @@ use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, Wit use rustc_hir::def_id::DefId; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::sync::Lock; use rustc_hir as hir; use rustc_index::bit_set::GrowableBitSet; use rustc_span::symbol::sym; @@ -53,6 +52,8 @@ use std::iter; use std::rc::Rc; use syntax::{ast, attr}; +pub use rustc::traits::types::select::*; + pub struct SelectionContext<'cx, 'tcx> { infcx: &'cx InferCtxt<'cx, 'tcx>, @@ -181,146 +182,6 @@ struct TraitObligationStack<'prev, 'tcx> { dfn: usize, } -#[derive(Clone, Default)] -pub struct SelectionCache<'tcx> { - hashmap: Lock< - FxHashMap< - ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>, - WithDepNode<SelectionResult<'tcx, SelectionCandidate<'tcx>>>, - >, - >, -} - -/// The selection process begins by considering all impls, where -/// clauses, and so forth that might resolve an obligation. Sometimes -/// we'll be able to say definitively that (e.g.) an impl does not -/// apply to the obligation: perhaps it is defined for `usize` but the -/// obligation is for `int`. In that case, we drop the impl out of the -/// list. But the other cases are considered *candidates*. -/// -/// For selection to succeed, there must be exactly one matching -/// candidate. If the obligation is fully known, this is guaranteed -/// by coherence. However, if the obligation contains type parameters -/// or variables, there may be multiple such impls. -/// -/// It is not a real problem if multiple matching impls exist because -/// of type variables - it just means the obligation isn't sufficiently -/// elaborated. In that case we report an ambiguity, and the caller can -/// try again after more type information has been gathered or report a -/// "type annotations needed" error. -/// -/// However, with type parameters, this can be a real problem - type -/// parameters don't unify with regular types, but they *can* unify -/// with variables from blanket impls, and (unless we know its bounds -/// will always be satisfied) picking the blanket impl will be wrong -/// for at least *some* substitutions. To make this concrete, if we have -/// -/// trait AsDebug { type Out : fmt::Debug; fn debug(self) -> Self::Out; } -/// impl<T: fmt::Debug> AsDebug for T { -/// type Out = T; -/// fn debug(self) -> fmt::Debug { self } -/// } -/// fn foo<T: AsDebug>(t: T) { println!("{:?}", <T as AsDebug>::debug(t)); } -/// -/// we can't just use the impl to resolve the `<T as AsDebug>` obligation -/// -- a type from another crate (that doesn't implement `fmt::Debug`) could -/// implement `AsDebug`. -/// -/// Because where-clauses match the type exactly, multiple clauses can -/// only match if there are unresolved variables, and we can mostly just -/// report this ambiguity in that case. This is still a problem - we can't -/// *do anything* with ambiguities that involve only regions. This is issue -/// #21974. -/// -/// If a single where-clause matches and there are no inference -/// variables left, then it definitely matches and we can just select -/// it. -/// -/// In fact, we even select the where-clause when the obligation contains -/// inference variables. The can lead to inference making "leaps of logic", -/// for example in this situation: -/// -/// pub trait Foo<T> { fn foo(&self) -> T; } -/// impl<T> Foo<()> for T { fn foo(&self) { } } -/// impl Foo<bool> for bool { fn foo(&self) -> bool { *self } } -/// -/// pub fn foo<T>(t: T) where T: Foo<bool> { -/// println!("{:?}", <T as Foo<_>>::foo(&t)); -/// } -/// fn main() { foo(false); } -/// -/// Here the obligation `<T as Foo<$0>>` can be matched by both the blanket -/// impl and the where-clause. We select the where-clause and unify `$0=bool`, -/// so the program prints "false". However, if the where-clause is omitted, -/// the blanket impl is selected, we unify `$0=()`, and the program prints -/// "()". -/// -/// Exactly the same issues apply to projection and object candidates, except -/// that we can have both a projection candidate and a where-clause candidate -/// for the same obligation. In that case either would do (except that -/// different "leaps of logic" would occur if inference variables are -/// present), and we just pick the where-clause. This is, for example, -/// required for associated types to work in default impls, as the bounds -/// are visible both as projection bounds and as where-clauses from the -/// parameter environment. -#[derive(PartialEq, Eq, Debug, Clone, TypeFoldable)] -enum SelectionCandidate<'tcx> { - BuiltinCandidate { - /// `false` if there are no *further* obligations. - has_nested: bool, - }, - ParamCandidate(ty::PolyTraitRef<'tcx>), - ImplCandidate(DefId), - AutoImplCandidate(DefId), - - /// This is a trait matching with a projected type as `Self`, and - /// we found an applicable bound in the trait definition. - ProjectionCandidate, - - /// Implementation of a `Fn`-family trait by one of the anonymous types - /// generated for a `||` expression. - ClosureCandidate, - - /// Implementation of a `Generator` trait by one of the anonymous types - /// generated for a generator. - GeneratorCandidate, - - /// Implementation of a `Fn`-family trait by one of the anonymous - /// types generated for a fn pointer type (e.g., `fn(int) -> int`) - FnPointerCandidate, - - TraitAliasCandidate(DefId), - - ObjectCandidate, - - BuiltinObjectCandidate, - - BuiltinUnsizeCandidate, -} - -impl<'a, 'tcx> ty::Lift<'tcx> for SelectionCandidate<'a> { - type Lifted = SelectionCandidate<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - Some(match *self { - BuiltinCandidate { has_nested } => BuiltinCandidate { has_nested }, - ImplCandidate(def_id) => ImplCandidate(def_id), - AutoImplCandidate(def_id) => AutoImplCandidate(def_id), - ProjectionCandidate => ProjectionCandidate, - ClosureCandidate => ClosureCandidate, - GeneratorCandidate => GeneratorCandidate, - FnPointerCandidate => FnPointerCandidate, - TraitAliasCandidate(def_id) => TraitAliasCandidate(def_id), - ObjectCandidate => ObjectCandidate, - BuiltinObjectCandidate => BuiltinObjectCandidate, - BuiltinUnsizeCandidate => BuiltinUnsizeCandidate, - - ParamCandidate(ref trait_ref) => { - return tcx.lift(trait_ref).map(ParamCandidate); - } - }) - } -} - struct SelectionCandidateSet<'tcx> { // A list of candidates that definitely apply to the current // obligation (meaning: types unify). @@ -350,134 +211,6 @@ enum BuiltinImplConditions<'tcx> { Ambiguous, } -/// The result of trait evaluation. The order is important -/// here as the evaluation of a list is the maximum of the -/// evaluations. -/// -/// The evaluation results are ordered: -/// - `EvaluatedToOk` implies `EvaluatedToOkModuloRegions` -/// implies `EvaluatedToAmbig` implies `EvaluatedToUnknown` -/// - `EvaluatedToErr` implies `EvaluatedToRecur` -/// - the "union" of evaluation results is equal to their maximum - -/// all the "potential success" candidates can potentially succeed, -/// so they are noops when unioned with a definite error, and within -/// the categories it's easy to see that the unions are correct. -#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, HashStable)] -pub enum EvaluationResult { - /// Evaluation successful. - EvaluatedToOk, - /// Evaluation successful, but there were unevaluated region obligations. - EvaluatedToOkModuloRegions, - /// Evaluation is known to be ambiguous -- it *might* hold for some - /// assignment of inference variables, but it might not. - /// - /// While this has the same meaning as `EvaluatedToUnknown` -- we can't - /// know whether this obligation holds or not -- it is the result we - /// would get with an empty stack, and therefore is cacheable. - EvaluatedToAmbig, - /// Evaluation failed because of recursion involving inference - /// variables. We are somewhat imprecise there, so we don't actually - /// know the real result. - /// - /// This can't be trivially cached for the same reason as `EvaluatedToRecur`. - EvaluatedToUnknown, - /// Evaluation failed because we encountered an obligation we are already - /// trying to prove on this branch. - /// - /// We know this branch can't be a part of a minimal proof-tree for - /// the "root" of our cycle, because then we could cut out the recursion - /// and maintain a valid proof tree. However, this does not mean - /// that all the obligations on this branch do not hold -- it's possible - /// that we entered this branch "speculatively", and that there - /// might be some other way to prove this obligation that does not - /// go through this cycle -- so we can't cache this as a failure. - /// - /// For example, suppose we have this: - /// - /// ```rust,ignore (pseudo-Rust) - /// pub trait Trait { fn xyz(); } - /// // This impl is "useless", but we can still have - /// // an `impl Trait for SomeUnsizedType` somewhere. - /// impl<T: Trait + Sized> Trait for T { fn xyz() {} } - /// - /// pub fn foo<T: Trait + ?Sized>() { - /// <T as Trait>::xyz(); - /// } - /// ``` - /// - /// When checking `foo`, we have to prove `T: Trait`. This basically - /// translates into this: - /// - /// ```plain,ignore - /// (T: Trait + Sized →_\impl T: Trait), T: Trait ⊢ T: Trait - /// ``` - /// - /// When we try to prove it, we first go the first option, which - /// recurses. This shows us that the impl is "useless" -- it won't - /// tell us that `T: Trait` unless it already implemented `Trait` - /// by some other means. However, that does not prevent `T: Trait` - /// does not hold, because of the bound (which can indeed be satisfied - /// by `SomeUnsizedType` from another crate). - // - // FIXME: when an `EvaluatedToRecur` goes past its parent root, we - // ought to convert it to an `EvaluatedToErr`, because we know - // there definitely isn't a proof tree for that obligation. Not - // doing so is still sound -- there isn't any proof tree, so the - // branch still can't be a part of a minimal one -- but does not re-enable caching. - EvaluatedToRecur, - /// Evaluation failed. - EvaluatedToErr, -} - -impl EvaluationResult { - /// Returns `true` if this evaluation result is known to apply, even - /// considering outlives constraints. - pub fn must_apply_considering_regions(self) -> bool { - self == EvaluatedToOk - } - - /// Returns `true` if this evaluation result is known to apply, ignoring - /// outlives constraints. - pub fn must_apply_modulo_regions(self) -> bool { - self <= EvaluatedToOkModuloRegions - } - - pub fn may_apply(self) -> bool { - match self { - EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToUnknown => { - true - } - - EvaluatedToErr | EvaluatedToRecur => false, - } - } - - fn is_stack_dependent(self) -> bool { - match self { - EvaluatedToUnknown | EvaluatedToRecur => true, - - EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToErr => false, - } - } -} - -/// Indicates that trait evaluation caused overflow. -#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)] -pub struct OverflowError; - -impl<'tcx> From<OverflowError> for SelectionError<'tcx> { - fn from(OverflowError: OverflowError) -> SelectionError<'tcx> { - SelectionError::Overflow - } -} - -#[derive(Clone, Default)] -pub struct EvaluationCache<'tcx> { - hashmap: Lock< - FxHashMap<ty::ParamEnvAnd<'tcx, ty::PolyTraitRef<'tcx>>, WithDepNode<EvaluationResult>>, - >, -} - impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> { SelectionContext { @@ -3827,20 +3560,6 @@ impl<'tcx> TraitObligation<'tcx> { } } -impl<'tcx> SelectionCache<'tcx> { - /// Actually frees the underlying memory in contrast to what stdlib containers do on `clear` - pub fn clear(&self) { - *self.hashmap.borrow_mut() = Default::default(); - } -} - -impl<'tcx> EvaluationCache<'tcx> { - /// Actually frees the underlying memory in contrast to what stdlib containers do on `clear` - pub fn clear(&self) { - *self.hashmap.borrow_mut() = Default::default(); - } -} - impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> { fn list(&'o self) -> TraitObligationStackList<'o, 'tcx> { TraitObligationStackList::with(self) @@ -4126,20 +3845,3 @@ impl<'o, 'tcx> fmt::Debug for TraitObligationStack<'o, 'tcx> { write!(f, "TraitObligationStack({:?})", self.obligation) } } - -#[derive(Clone, Eq, PartialEq)] -pub struct WithDepNode<T> { - dep_node: DepNodeIndex, - cached_value: T, -} - -impl<T: Clone> WithDepNode<T> { - pub fn new(dep_node: DepNodeIndex, cached_value: T) -> Self { - WithDepNode { dep_node, cached_value } - } - - pub fn get(&self, tcx: TyCtxt<'_>) -> T { - tcx.dep_graph.read_index(self.dep_node); - self.cached_value.clone() - } -} diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index 9509b6220eb..c90fa428001 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -1,58 +1,11 @@ use super::OverlapError; -use crate::ich::{self, StableHashingContext}; use crate::traits; -use crate::ty::fast_reject::{self, SimplifiedType}; -use crate::ty::{self, TyCtxt, TypeFoldable}; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_hir::def_id::{DefId, DefIdMap}; -use syntax::ast::Ident; - -/// A per-trait graph of impls in specialization order. At the moment, this -/// graph forms a tree rooted with the trait itself, with all other nodes -/// representing impls, and parent-child relationships representing -/// specializations. -/// -/// The graph provides two key services: -/// -/// - Construction. This implicitly checks for overlapping impls (i.e., impls -/// that overlap but where neither specializes the other -- an artifact of the -/// simple "chain" rule. -/// -/// - Parent extraction. In particular, the graph can give you the *immediate* -/// parents of a given specializing impl, which is needed for extracting -/// default items amongst other things. In the simple "chain" rule, every impl -/// has at most one parent. -#[derive(RustcEncodable, RustcDecodable, HashStable)] -pub struct Graph { - // All impls have a parent; the "root" impls have as their parent the `def_id` - // of the trait. - parent: DefIdMap<DefId>, - - // The "root" impls are found by looking up the trait's def_id. - children: DefIdMap<Children>, -} +use rustc::ty::fast_reject::{self, SimplifiedType}; +use rustc::ty::{self, TyCtxt, TypeFoldable}; +use rustc_hir::def_id::DefId; -/// Children of a given impl, grouped into blanket/non-blanket varieties as is -/// done in `TraitDef`. -#[derive(Default, RustcEncodable, RustcDecodable)] -struct Children { - // Impls of a trait (or specializations of a given impl). To allow for - // quicker lookup, the impls are indexed by a simplified version of their - // `Self` type: impls with a simplifiable `Self` are stored in - // `nonblanket_impls` keyed by it, while all other impls are stored in - // `blanket_impls`. - // - // A similar division is used within `TraitDef`, but the lists there collect - // together *all* the impls for a trait, and are populated prior to building - // the specialization graph. - /// Impls of the trait. - nonblanket_impls: FxHashMap<fast_reject::SimplifiedType, Vec<DefId>>, - - /// Blanket impls associated with the trait. - blanket_impls: Vec<DefId>, -} +pub use rustc::traits::types::specialization_graph::*; #[derive(Copy, Clone, Debug)] pub enum FutureCompatOverlapErrorKind { @@ -269,10 +222,6 @@ where } impl<'tcx> Graph { - pub fn new() -> Graph { - Graph { parent: Default::default(), children: Default::default() } - } - /// Insert a local impl into the specialization graph. If an existing impl /// conflicts with it (has overlap, but neither specializes the other), /// information about the area of overlap is returned in the `Err`. @@ -383,145 +332,4 @@ impl<'tcx> Graph { self.children.entry(parent).or_default().insert_blindly(tcx, child); } - - /// The parent of a given impl, which is the `DefId` of the trait when the - /// impl is a "specialization root". - pub fn parent(&self, child: DefId) -> DefId { - *self.parent.get(&child).unwrap_or_else(|| panic!("Failed to get parent for {:?}", child)) - } -} - -/// A node in the specialization graph is either an impl or a trait -/// definition; either can serve as a source of item definitions. -/// There is always exactly one trait definition node: the root. -#[derive(Debug, Copy, Clone)] -pub enum Node { - Impl(DefId), - Trait(DefId), -} - -impl<'tcx> Node { - pub fn is_from_trait(&self) -> bool { - match *self { - Node::Trait(..) => true, - _ => false, - } - } - - /// Iterate over the items defined directly by the given (impl or trait) node. - pub fn items(&self, tcx: TyCtxt<'tcx>) -> ty::AssocItemsIterator<'tcx> { - tcx.associated_items(self.def_id()) - } - - /// Finds an associated item defined in this node. - /// - /// If this returns `None`, the item can potentially still be found in - /// parents of this node. - pub fn item( - &self, - tcx: TyCtxt<'tcx>, - trait_item_name: Ident, - trait_item_kind: ty::AssocKind, - trait_def_id: DefId, - ) -> Option<ty::AssocItem> { - use crate::ty::AssocKind::*; - - tcx.associated_items(self.def_id()).find(move |impl_item| { - match (trait_item_kind, impl_item.kind) { - | (Const, Const) - | (Method, Method) - | (Type, Type) - | (Type, OpaqueTy) // assoc. types can be made opaque in impls - => tcx.hygienic_eq(impl_item.ident, trait_item_name, trait_def_id), - - | (Const, _) - | (Method, _) - | (Type, _) - | (OpaqueTy, _) - => false, - } - }) - } - - pub fn def_id(&self) -> DefId { - match *self { - Node::Impl(did) => did, - Node::Trait(did) => did, - } - } -} - -#[derive(Copy, Clone)] -pub struct Ancestors<'tcx> { - trait_def_id: DefId, - specialization_graph: &'tcx Graph, - current_source: Option<Node>, -} - -impl Iterator for Ancestors<'_> { - type Item = Node; - fn next(&mut self) -> Option<Node> { - let cur = self.current_source.take(); - if let Some(Node::Impl(cur_impl)) = cur { - let parent = self.specialization_graph.parent(cur_impl); - - self.current_source = if parent == self.trait_def_id { - Some(Node::Trait(parent)) - } else { - Some(Node::Impl(parent)) - }; - } - cur - } -} - -pub struct NodeItem<T> { - pub node: Node, - pub item: T, -} - -impl<T> NodeItem<T> { - pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> NodeItem<U> { - NodeItem { node: self.node, item: f(self.item) } - } -} - -impl<'tcx> Ancestors<'tcx> { - /// Finds the bottom-most (ie. most specialized) definition of an associated - /// item. - pub fn leaf_def( - mut self, - tcx: TyCtxt<'tcx>, - trait_item_name: Ident, - trait_item_kind: ty::AssocKind, - ) -> Option<NodeItem<ty::AssocItem>> { - let trait_def_id = self.trait_def_id; - self.find_map(|node| { - node.item(tcx, trait_item_name, trait_item_kind, trait_def_id) - .map(|item| NodeItem { node, item }) - }) - } -} - -/// Walk up the specialization ancestors of a given impl, starting with that -/// impl itself. -pub fn ancestors( - tcx: TyCtxt<'tcx>, - trait_def_id: DefId, - start_from_impl: DefId, -) -> Ancestors<'tcx> { - let specialization_graph = tcx.specialization_graph_of(trait_def_id); - Ancestors { - trait_def_id, - specialization_graph, - current_source: Some(Node::Impl(start_from_impl)), - } -} - -impl<'a> HashStable<StableHashingContext<'a>> for Children { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let Children { ref nonblanket_impls, ref blanket_impls } = *self; - - ich::hash_stable_trait_impls(hcx, hasher, blanket_impls, nonblanket_impls); - } } diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 58204a460d7..80731c7b189 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -1,14 +1,9 @@ use crate::traits; use crate::traits::project::Normalized; +use crate::ty; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; -use crate::ty::{self, Lift, Ty, TyCtxt}; -use chalk_engine; -use rustc_span::symbol::Symbol; -use smallvec::SmallVec; -use std::collections::{BTreeMap, BTreeSet}; use std::fmt; -use std::rc::Rc; // Structural impls for the structs in `traits`. @@ -32,102 +27,6 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for traits::Obligation<'tcx, O> { } } -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::Vtable<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - super::VtableImpl(ref v) => write!(f, "{:?}", v), - - super::VtableAutoImpl(ref t) => write!(f, "{:?}", t), - - super::VtableClosure(ref d) => write!(f, "{:?}", d), - - super::VtableGenerator(ref d) => write!(f, "{:?}", d), - - super::VtableFnPointer(ref d) => write!(f, "VtableFnPointer({:?})", d), - - super::VtableObject(ref d) => write!(f, "{:?}", d), - - super::VtableParam(ref n) => write!(f, "VtableParam({:?})", n), - - super::VtableBuiltin(ref d) => write!(f, "{:?}", d), - - super::VtableTraitAlias(ref d) => write!(f, "{:?}", d), - } - } -} - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableImplData<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "VtableImplData(impl_def_id={:?}, substs={:?}, nested={:?})", - self.impl_def_id, self.substs, self.nested - ) - } -} - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableGeneratorData<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "VtableGeneratorData(generator_def_id={:?}, substs={:?}, nested={:?})", - self.generator_def_id, self.substs, self.nested - ) - } -} - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableClosureData<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "VtableClosureData(closure_def_id={:?}, substs={:?}, nested={:?})", - self.closure_def_id, self.substs, self.nested - ) - } -} - -impl<N: fmt::Debug> fmt::Debug for traits::VtableBuiltinData<N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "VtableBuiltinData(nested={:?})", self.nested) - } -} - -impl<N: fmt::Debug> fmt::Debug for traits::VtableAutoImplData<N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "VtableAutoImplData(trait_def_id={:?}, nested={:?})", - self.trait_def_id, self.nested - ) - } -} - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableObjectData<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "VtableObjectData(upcast={:?}, vtable_base={}, nested={:?})", - self.upcast_trait_ref, self.vtable_base, self.nested - ) - } -} - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableFnPointerData<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "VtableFnPointerData(fn_ty={:?}, nested={:?})", self.fn_ty, self.nested) - } -} - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableTraitAliasData<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "VtableTraitAlias(alias_def_id={:?}, substs={:?}, nested={:?})", - self.alias_def_id, self.substs, self.nested - ) - } -} - impl<'tcx> fmt::Debug for traits::FulfillmentError<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "FulfillmentError({:?},{:?})", self.obligation, self.code) @@ -153,531 +52,6 @@ impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'tcx> { } } -impl<'tcx> fmt::Display for traits::WhereClause<'tcx> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - use crate::traits::WhereClause::*; - - // Bypass `ty::print` because it does not print out anonymous regions. - // FIXME(eddyb) implement a custom `PrettyPrinter`, or move this to `ty::print`. - fn write_region_name<'tcx>( - r: ty::Region<'tcx>, - fmt: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - match r { - ty::ReLateBound(index, br) => match br { - ty::BoundRegion::BrNamed(_, name) => write!(fmt, "{}", name), - ty::BoundRegion::BrAnon(var) => { - if *index == ty::INNERMOST { - write!(fmt, "'^{}", var) - } else { - write!(fmt, "'^{}_{}", index.index(), var) - } - } - _ => write!(fmt, "'_"), - }, - - _ => write!(fmt, "{}", r), - } - } - - match self { - Implemented(trait_ref) => write!(fmt, "Implemented({})", trait_ref), - ProjectionEq(projection) => write!(fmt, "ProjectionEq({})", projection), - RegionOutlives(predicate) => { - write!(fmt, "RegionOutlives({}: ", predicate.0)?; - write_region_name(predicate.1, fmt)?; - write!(fmt, ")") - } - TypeOutlives(predicate) => { - write!(fmt, "TypeOutlives({}: ", predicate.0)?; - write_region_name(predicate.1, fmt)?; - write!(fmt, ")") - } - } - } -} - -impl<'tcx> fmt::Display for traits::WellFormed<'tcx> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - use crate::traits::WellFormed::*; - - match self { - Trait(trait_ref) => write!(fmt, "WellFormed({})", trait_ref), - Ty(ty) => write!(fmt, "WellFormed({})", ty), - } - } -} - -impl<'tcx> fmt::Display for traits::FromEnv<'tcx> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - use crate::traits::FromEnv::*; - - match self { - Trait(trait_ref) => write!(fmt, "FromEnv({})", trait_ref), - Ty(ty) => write!(fmt, "FromEnv({})", ty), - } - } -} - -impl<'tcx> fmt::Display for traits::DomainGoal<'tcx> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - use crate::traits::DomainGoal::*; - - match self { - Holds(wc) => write!(fmt, "{}", wc), - WellFormed(wf) => write!(fmt, "{}", wf), - FromEnv(from_env) => write!(fmt, "{}", from_env), - Normalize(projection) => { - write!(fmt, "Normalize({} -> {})", projection.projection_ty, projection.ty) - } - } - } -} - -impl fmt::Display for traits::QuantifierKind { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - use crate::traits::QuantifierKind::*; - - match self { - Universal => write!(fmt, "forall"), - Existential => write!(fmt, "exists"), - } - } -} - -/// Collect names for regions / types bound by a quantified goal / clause. -/// This collector does not try to do anything clever like in `ty::print`, it's just used -/// for debug output in tests anyway. -struct BoundNamesCollector { - // Just sort by name because `BoundRegion::BrNamed` does not have a `BoundVar` index anyway. - regions: BTreeSet<Symbol>, - - // Sort by `BoundVar` index, so usually this should be equivalent to the order given - // by the list of type parameters. - types: BTreeMap<u32, Symbol>, - - binder_index: ty::DebruijnIndex, -} - -impl BoundNamesCollector { - fn new() -> Self { - BoundNamesCollector { - regions: BTreeSet::new(), - types: BTreeMap::new(), - binder_index: ty::INNERMOST, - } - } - - fn is_empty(&self) -> bool { - self.regions.is_empty() && self.types.is_empty() - } - - fn write_names(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut start = true; - for r in &self.regions { - if !start { - write!(fmt, ", ")?; - } - start = false; - write!(fmt, "{}", r)?; - } - for (_, t) in &self.types { - if !start { - write!(fmt, ", ")?; - } - start = false; - write!(fmt, "{}", t)?; - } - Ok(()) - } -} - -impl<'tcx> TypeVisitor<'tcx> for BoundNamesCollector { - fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool { - self.binder_index.shift_in(1); - let result = t.super_visit_with(self); - self.binder_index.shift_out(1); - result - } - - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - match t.kind { - ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { - self.types.insert( - bound_ty.var.as_u32(), - match bound_ty.kind { - ty::BoundTyKind::Param(name) => name, - ty::BoundTyKind::Anon => { - Symbol::intern(&format!("^{}", bound_ty.var.as_u32())) - } - }, - ); - } - - _ => (), - }; - - t.super_visit_with(self) - } - - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { - match r { - ty::ReLateBound(index, br) if *index == self.binder_index => match br { - ty::BoundRegion::BrNamed(_, name) => { - self.regions.insert(*name); - } - - ty::BoundRegion::BrAnon(var) => { - self.regions.insert(Symbol::intern(&format!("'^{}", var))); - } - - _ => (), - }, - - _ => (), - }; - - r.super_visit_with(self) - } -} - -impl<'tcx> fmt::Display for traits::Goal<'tcx> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - use crate::traits::GoalKind::*; - - match self { - Implies(hypotheses, goal) => { - write!(fmt, "if (")?; - for (index, hyp) in hypotheses.iter().enumerate() { - if index > 0 { - write!(fmt, ", ")?; - } - write!(fmt, "{}", hyp)?; - } - write!(fmt, ") {{ {} }}", goal) - } - And(goal1, goal2) => write!(fmt, "({} && {})", goal1, goal2), - Not(goal) => write!(fmt, "not {{ {} }}", goal), - DomainGoal(goal) => write!(fmt, "{}", goal), - Quantified(qkind, goal) => { - let mut collector = BoundNamesCollector::new(); - goal.skip_binder().visit_with(&mut collector); - - if !collector.is_empty() { - write!(fmt, "{}<", qkind)?; - collector.write_names(fmt)?; - write!(fmt, "> {{ ")?; - } - - write!(fmt, "{}", goal.skip_binder())?; - - if !collector.is_empty() { - write!(fmt, " }}")?; - } - - Ok(()) - } - Subtype(a, b) => write!(fmt, "{} <: {}", a, b), - CannotProve => write!(fmt, "CannotProve"), - } - } -} - -impl<'tcx> fmt::Display for traits::ProgramClause<'tcx> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let traits::ProgramClause { goal, hypotheses, .. } = self; - write!(fmt, "{}", goal)?; - if !hypotheses.is_empty() { - write!(fmt, " :- ")?; - for (index, condition) in hypotheses.iter().enumerate() { - if index > 0 { - write!(fmt, ", ")?; - } - write!(fmt, "{}", condition)?; - } - } - write!(fmt, ".") - } -} - -impl<'tcx> fmt::Display for traits::Clause<'tcx> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - use crate::traits::Clause::*; - - match self { - Implies(clause) => write!(fmt, "{}", clause), - ForAll(clause) => { - let mut collector = BoundNamesCollector::new(); - clause.skip_binder().visit_with(&mut collector); - - if !collector.is_empty() { - write!(fmt, "forall<")?; - collector.write_names(fmt)?; - write!(fmt, "> {{ ")?; - } - - write!(fmt, "{}", clause.skip_binder())?; - - if !collector.is_empty() { - write!(fmt, " }}")?; - } - - Ok(()) - } - } - } -} - -/////////////////////////////////////////////////////////////////////////// -// Lift implementations - -impl<'a, 'tcx> Lift<'tcx> for traits::SelectionError<'a> { - type Lifted = traits::SelectionError<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - match *self { - super::Unimplemented => Some(super::Unimplemented), - super::OutputTypeParameterMismatch(a, b, ref err) => { - tcx.lift(&(a, b)).and_then(|(a, b)| { - tcx.lift(err).map(|err| super::OutputTypeParameterMismatch(a, b, err)) - }) - } - super::TraitNotObjectSafe(def_id) => Some(super::TraitNotObjectSafe(def_id)), - super::ConstEvalFailure(err) => Some(super::ConstEvalFailure(err)), - super::Overflow => Some(super::Overflow), - } - } -} - -impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { - type Lifted = traits::ObligationCauseCode<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - match *self { - super::ReturnNoExpression => Some(super::ReturnNoExpression), - super::MiscObligation => Some(super::MiscObligation), - super::SliceOrArrayElem => Some(super::SliceOrArrayElem), - super::TupleElem => Some(super::TupleElem), - super::ProjectionWf(proj) => tcx.lift(&proj).map(super::ProjectionWf), - super::ItemObligation(def_id) => Some(super::ItemObligation(def_id)), - super::BindingObligation(def_id, span) => Some(super::BindingObligation(def_id, span)), - super::ReferenceOutlivesReferent(ty) => { - tcx.lift(&ty).map(super::ReferenceOutlivesReferent) - } - super::ObjectTypeBound(ty, r) => tcx - .lift(&ty) - .and_then(|ty| tcx.lift(&r).and_then(|r| Some(super::ObjectTypeBound(ty, r)))), - super::ObjectCastObligation(ty) => tcx.lift(&ty).map(super::ObjectCastObligation), - super::Coercion { source, target } => { - Some(super::Coercion { source: tcx.lift(&source)?, target: tcx.lift(&target)? }) - } - super::AssignmentLhsSized => Some(super::AssignmentLhsSized), - super::TupleInitializerSized => Some(super::TupleInitializerSized), - super::StructInitializerSized => Some(super::StructInitializerSized), - super::VariableType(id) => Some(super::VariableType(id)), - super::ReturnValue(id) => Some(super::ReturnValue(id)), - super::ReturnType => Some(super::ReturnType), - super::SizedArgumentType => Some(super::SizedArgumentType), - super::SizedReturnType => Some(super::SizedReturnType), - super::SizedYieldType => Some(super::SizedYieldType), - super::RepeatVec(suggest_flag) => Some(super::RepeatVec(suggest_flag)), - super::FieldSized { adt_kind, last } => Some(super::FieldSized { adt_kind, last }), - super::ConstSized => Some(super::ConstSized), - super::ConstPatternStructural => Some(super::ConstPatternStructural), - super::SharedStatic => Some(super::SharedStatic), - super::BuiltinDerivedObligation(ref cause) => { - tcx.lift(cause).map(super::BuiltinDerivedObligation) - } - super::ImplDerivedObligation(ref cause) => { - tcx.lift(cause).map(super::ImplDerivedObligation) - } - super::CompareImplMethodObligation { - item_name, - impl_item_def_id, - trait_item_def_id, - } => Some(super::CompareImplMethodObligation { - item_name, - impl_item_def_id, - trait_item_def_id, - }), - super::CompareImplTypeObligation { item_name, impl_item_def_id, trait_item_def_id } => { - Some(super::CompareImplTypeObligation { - item_name, - impl_item_def_id, - trait_item_def_id, - }) - } - super::ExprAssignable => Some(super::ExprAssignable), - super::MatchExpressionArm(box super::MatchExpressionArmCause { - arm_span, - source, - ref prior_arms, - last_ty, - scrut_hir_id, - }) => tcx.lift(&last_ty).map(|last_ty| { - super::MatchExpressionArm(box super::MatchExpressionArmCause { - arm_span, - source, - prior_arms: prior_arms.clone(), - last_ty, - scrut_hir_id, - }) - }), - super::Pattern { span, root_ty, origin_expr } => { - tcx.lift(&root_ty).map(|root_ty| super::Pattern { span, root_ty, origin_expr }) - } - super::IfExpression(box super::IfExpressionCause { then, outer, semicolon }) => { - Some(super::IfExpression(box super::IfExpressionCause { then, outer, semicolon })) - } - super::IfExpressionWithNoElse => Some(super::IfExpressionWithNoElse), - super::MainFunctionType => Some(super::MainFunctionType), - super::StartFunctionType => Some(super::StartFunctionType), - super::IntrinsicType => Some(super::IntrinsicType), - super::MethodReceiver => Some(super::MethodReceiver), - super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)), - super::TrivialBound => Some(super::TrivialBound), - super::AssocTypeBound(ref data) => Some(super::AssocTypeBound(data.clone())), - } - } -} - -impl<'a, 'tcx> Lift<'tcx> for traits::DerivedObligationCause<'a> { - type Lifted = traits::DerivedObligationCause<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(&self.parent_trait_ref).and_then(|trait_ref| { - tcx.lift(&*self.parent_code).map(|code| traits::DerivedObligationCause { - parent_trait_ref: trait_ref, - parent_code: Rc::new(code), - }) - }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCause<'a> { - type Lifted = traits::ObligationCause<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(&self.code).map(|code| traits::ObligationCause { - span: self.span, - body_id: self.body_id, - code, - }) - } -} - -// For codegen only. -impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> { - type Lifted = traits::Vtable<'tcx, ()>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - match self.clone() { - traits::VtableImpl(traits::VtableImplData { impl_def_id, substs, nested }) => { - tcx.lift(&substs).map(|substs| { - traits::VtableImpl(traits::VtableImplData { impl_def_id, substs, nested }) - }) - } - traits::VtableAutoImpl(t) => Some(traits::VtableAutoImpl(t)), - traits::VtableGenerator(traits::VtableGeneratorData { - generator_def_id, - substs, - nested, - }) => tcx.lift(&substs).map(|substs| { - traits::VtableGenerator(traits::VtableGeneratorData { - generator_def_id: generator_def_id, - substs: substs, - nested: nested, - }) - }), - traits::VtableClosure(traits::VtableClosureData { closure_def_id, substs, nested }) => { - tcx.lift(&substs).map(|substs| { - traits::VtableClosure(traits::VtableClosureData { - closure_def_id, - substs, - nested, - }) - }) - } - traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested }) => { - tcx.lift(&fn_ty).map(|fn_ty| { - traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested }) - }) - } - traits::VtableParam(n) => Some(traits::VtableParam(n)), - traits::VtableBuiltin(n) => Some(traits::VtableBuiltin(n)), - traits::VtableObject(traits::VtableObjectData { - upcast_trait_ref, - vtable_base, - nested, - }) => tcx.lift(&upcast_trait_ref).map(|trait_ref| { - traits::VtableObject(traits::VtableObjectData { - upcast_trait_ref: trait_ref, - vtable_base, - nested, - }) - }), - traits::VtableTraitAlias(traits::VtableTraitAliasData { - alias_def_id, - substs, - nested, - }) => tcx.lift(&substs).map(|substs| { - traits::VtableTraitAlias(traits::VtableTraitAliasData { - alias_def_id, - substs, - nested, - }) - }), - } - } -} - -impl<'a, 'tcx> Lift<'tcx> for traits::Environment<'a> { - type Lifted = traits::Environment<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(&self.clauses).map(|clauses| traits::Environment { clauses }) - } -} - -impl<'a, 'tcx, G: Lift<'tcx>> Lift<'tcx> for traits::InEnvironment<'a, G> { - type Lifted = traits::InEnvironment<'tcx, G::Lifted>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(&self.environment).and_then(|environment| { - tcx.lift(&self.goal).map(|goal| traits::InEnvironment { environment, goal }) - }) - } -} - -impl<'tcx, C> Lift<'tcx> for chalk_engine::ExClause<C> -where - C: chalk_engine::context::Context + Clone, - C: traits::ChalkContextLift<'tcx>, -{ - type Lifted = C::LiftedExClause; - - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - <C as traits::ChalkContextLift>::lift_ex_clause_to_tcx(self, tcx) - } -} - -impl<'tcx, C> Lift<'tcx> for chalk_engine::DelayedLiteral<C> -where - C: chalk_engine::context::Context + Clone, - C: traits::ChalkContextLift<'tcx>, -{ - type Lifted = C::LiftedDelayedLiteral; - - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - <C as traits::ChalkContextLift>::lift_delayed_literal_to_tcx(self, tcx) - } -} - -impl<'tcx, C> Lift<'tcx> for chalk_engine::Literal<C> -where - C: chalk_engine::context::Context + Clone, - C: traits::ChalkContextLift<'tcx>, -{ - type Lifted = C::LiftedLiteral; - - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - <C as traits::ChalkContextLift>::lift_literal_to_tcx(self, tcx) - } -} - /////////////////////////////////////////////////////////////////////////// // TypeFoldable implementations. @@ -695,80 +69,3 @@ impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx self.predicate.visit_with(visitor) } } - -CloneTypeFoldableAndLiftImpls! { - traits::QuantifierKind, -} - -impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<traits::Goal<'tcx>> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - let v = self.iter().map(|t| t.fold_with(folder)).collect::<SmallVec<[_; 8]>>(); - folder.tcx().intern_goals(&v) - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) - } -} - -impl<'tcx> TypeFoldable<'tcx> for traits::Goal<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - let v = (**self).fold_with(folder); - folder.tcx().mk_goal(v) - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - (**self).visit_with(visitor) - } -} - -CloneTypeFoldableAndLiftImpls! { - traits::ProgramClauseCategory, -} - -impl<'tcx> TypeFoldable<'tcx> for traits::Clauses<'tcx> { - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - let v = self.iter().map(|t| t.fold_with(folder)).collect::<SmallVec<[_; 8]>>(); - folder.tcx().intern_clauses(&v) - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) - } -} - -impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::ExClause<C> -where - C: traits::ExClauseFold<'tcx>, - C::Substitution: Clone, - C::RegionConstraint: Clone, -{ - fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { - <C as traits::ExClauseFold>::fold_ex_clause_with(self, folder) - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - <C as traits::ExClauseFold>::visit_ex_clause_with(self, visitor) - } -} - -EnumTypeFoldableImpl! { - impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::DelayedLiteral<C> { - (chalk_engine::DelayedLiteral::CannotProve)(a), - (chalk_engine::DelayedLiteral::Negative)(a), - (chalk_engine::DelayedLiteral::Positive)(a, b), - } where - C: chalk_engine::context::Context<CanonicalConstrainedSubst: TypeFoldable<'tcx>> + Clone, -} - -EnumTypeFoldableImpl! { - impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::Literal<C> { - (chalk_engine::Literal::Negative)(a), - (chalk_engine::Literal::Positive)(a), - } where - C: chalk_engine::context::Context<GoalInEnvironment: Clone + TypeFoldable<'tcx>> + Clone, -} - -CloneTypeFoldableAndLiftImpls! { - chalk_engine::TableIndex, -} diff --git a/src/librustc/traits/types/mod.rs b/src/librustc/traits/types/mod.rs new file mode 100644 index 00000000000..571fb505779 --- /dev/null +++ b/src/librustc/traits/types/mod.rs @@ -0,0 +1,736 @@ +//! Trait Resolution. See the [rustc guide] for more information on how this works. +//! +//! [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/resolution.html + +pub mod query; +pub mod select; +pub mod specialization_graph; +mod structural_impls; + +use crate::mir::interpret::ErrorHandled; +use crate::ty::fold::{TypeFolder, TypeVisitor}; +use crate::ty::subst::SubstsRef; +use crate::ty::{self, AdtKind, List, Ty, TyCtxt}; + +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_span::{Span, DUMMY_SP}; +use syntax::ast; + +use std::fmt::Debug; +use std::rc::Rc; + +pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache}; + +pub use self::ObligationCauseCode::*; +pub use self::SelectionError::*; +pub use self::Vtable::*; + +/// Depending on the stage of compilation, we want projection to be +/// more or less conservative. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)] +pub enum Reveal { + /// At type-checking time, we refuse to project any associated + /// type that is marked `default`. Non-`default` ("final") types + /// are always projected. This is necessary in general for + /// soundness of specialization. However, we *could* allow + /// projections in fully-monomorphic cases. We choose not to, + /// because we prefer for `default type` to force the type + /// definition to be treated abstractly by any consumers of the + /// impl. Concretely, that means that the following example will + /// fail to compile: + /// + /// ``` + /// trait Assoc { + /// type Output; + /// } + /// + /// impl<T> Assoc for T { + /// default type Output = bool; + /// } + /// + /// fn main() { + /// let <() as Assoc>::Output = true; + /// } + /// ``` + UserFacing, + + /// At codegen time, all monomorphic projections will succeed. + /// Also, `impl Trait` is normalized to the concrete type, + /// which has to be already collected by type-checking. + /// + /// NOTE: as `impl Trait`'s concrete type should *never* + /// be observable directly by the user, `Reveal::All` + /// should not be used by checks which may expose + /// type equality or type contents to the user. + /// There are some exceptions, e.g., around OIBITS and + /// transmute-checking, which expose some details, but + /// not the whole concrete type of the `impl Trait`. + All, +} + +/// The reason why we incurred this obligation; used for error reporting. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct ObligationCause<'tcx> { + pub span: Span, + + /// The ID of the fn body that triggered this obligation. This is + /// used for region obligations to determine the precise + /// environment in which the region obligation should be evaluated + /// (in particular, closures can add new assumptions). See the + /// field `region_obligations` of the `FulfillmentContext` for more + /// information. + pub body_id: hir::HirId, + + pub code: ObligationCauseCode<'tcx>, +} + +impl<'tcx> ObligationCause<'tcx> { + #[inline] + pub fn new( + span: Span, + body_id: hir::HirId, + code: ObligationCauseCode<'tcx>, + ) -> ObligationCause<'tcx> { + ObligationCause { span, body_id, code } + } + + pub fn misc(span: Span, body_id: hir::HirId) -> ObligationCause<'tcx> { + ObligationCause { span, body_id, code: MiscObligation } + } + + pub fn dummy() -> ObligationCause<'tcx> { + ObligationCause { span: DUMMY_SP, body_id: hir::CRATE_HIR_ID, code: MiscObligation } + } + + pub fn span(&self, tcx: TyCtxt<'tcx>) -> Span { + match self.code { + ObligationCauseCode::CompareImplMethodObligation { .. } + | ObligationCauseCode::MainFunctionType + | ObligationCauseCode::StartFunctionType => tcx.sess.source_map().def_span(self.span), + ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { + arm_span, + .. + }) => arm_span, + _ => self.span, + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum ObligationCauseCode<'tcx> { + /// Not well classified or should be obvious from the span. + MiscObligation, + + /// A slice or array is WF only if `T: Sized`. + SliceOrArrayElem, + + /// A tuple is WF only if its middle elements are `Sized`. + TupleElem, + + /// This is the trait reference from the given projection. + ProjectionWf(ty::ProjectionTy<'tcx>), + + /// In an impl of trait `X` for type `Y`, type `Y` must + /// also implement all supertraits of `X`. + ItemObligation(DefId), + + /// Like `ItemObligation`, but with extra detail on the source of the obligation. + BindingObligation(DefId, Span), + + /// A type like `&'a T` is WF only if `T: 'a`. + ReferenceOutlivesReferent(Ty<'tcx>), + + /// A type like `Box<Foo<'a> + 'b>` is WF only if `'b: 'a`. + ObjectTypeBound(Ty<'tcx>, ty::Region<'tcx>), + + /// Obligation incurred due to an object cast. + ObjectCastObligation(/* Object type */ Ty<'tcx>), + + /// Obligation incurred due to a coercion. + Coercion { + source: Ty<'tcx>, + target: Ty<'tcx>, + }, + + /// Various cases where expressions must be `Sized` / `Copy` / etc. + /// `L = X` implies that `L` is `Sized`. + AssignmentLhsSized, + /// `(x1, .., xn)` must be `Sized`. + TupleInitializerSized, + /// `S { ... }` must be `Sized`. + StructInitializerSized, + /// Type of each variable must be `Sized`. + VariableType(hir::HirId), + /// Argument type must be `Sized`. + SizedArgumentType, + /// Return type must be `Sized`. + SizedReturnType, + /// Yield type must be `Sized`. + SizedYieldType, + /// `[T, ..n]` implies that `T` must be `Copy`. + /// If `true`, suggest `const_in_array_repeat_expressions` feature flag. + RepeatVec(bool), + + /// Types of fields (other than the last, except for packed structs) in a struct must be sized. + FieldSized { + adt_kind: AdtKind, + last: bool, + }, + + /// Constant expressions must be sized. + ConstSized, + + /// `static` items must have `Sync` type. + SharedStatic, + + BuiltinDerivedObligation(DerivedObligationCause<'tcx>), + + ImplDerivedObligation(DerivedObligationCause<'tcx>), + + /// Error derived when matching traits/impls; see ObligationCause for more details + CompareImplMethodObligation { + item_name: ast::Name, + impl_item_def_id: DefId, + trait_item_def_id: DefId, + }, + + /// Error derived when matching traits/impls; see ObligationCause for more details + CompareImplTypeObligation { + item_name: ast::Name, + impl_item_def_id: DefId, + trait_item_def_id: DefId, + }, + + /// Checking that this expression can be assigned where it needs to be + // FIXME(eddyb) #11161 is the original Expr required? + ExprAssignable, + + /// Computing common supertype in the arms of a match expression + MatchExpressionArm(Box<MatchExpressionArmCause<'tcx>>), + + /// Type error arising from type checking a pattern against an expected type. + Pattern { + /// The span of the scrutinee or type expression which caused the `root_ty` type. + span: Option<Span>, + /// The root expected type induced by a scrutinee or type expression. + root_ty: Ty<'tcx>, + /// Whether the `Span` came from an expression or a type expression. + origin_expr: bool, + }, + + /// Constants in patterns must have `Structural` type. + ConstPatternStructural, + + /// Computing common supertype in an if expression + IfExpression(Box<IfExpressionCause>), + + /// Computing common supertype of an if expression with no else counter-part + IfExpressionWithNoElse, + + /// `main` has wrong type + MainFunctionType, + + /// `start` has wrong type + StartFunctionType, + + /// Intrinsic has wrong type + IntrinsicType, + + /// Method receiver + MethodReceiver, + + /// `return` with no expression + ReturnNoExpression, + + /// `return` with an expression + ReturnValue(hir::HirId), + + /// Return type of this function + ReturnType, + + /// Block implicit return + BlockTailExpression(hir::HirId), + + /// #[feature(trivial_bounds)] is not enabled + TrivialBound, + + AssocTypeBound(Box<AssocTypeBoundData>), +} + +impl ObligationCauseCode<'_> { + // Return the base obligation, ignoring derived obligations. + pub fn peel_derives(&self) -> &Self { + let mut base_cause = self; + while let BuiltinDerivedObligation(cause) | ImplDerivedObligation(cause) = base_cause { + base_cause = &cause.parent_code; + } + base_cause + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct AssocTypeBoundData { + pub impl_span: Option<Span>, + pub original: Span, + pub bounds: Vec<Span>, +} + +// `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger. +#[cfg(target_arch = "x86_64")] +static_assert_size!(ObligationCauseCode<'_>, 32); + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct MatchExpressionArmCause<'tcx> { + pub arm_span: Span, + pub source: hir::MatchSource, + pub prior_arms: Vec<Span>, + pub last_ty: Ty<'tcx>, + pub scrut_hir_id: hir::HirId, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct IfExpressionCause { + pub then: Span, + pub outer: Option<Span>, + pub semicolon: Option<Span>, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct DerivedObligationCause<'tcx> { + /// The trait reference of the parent obligation that led to the + /// current obligation. Note that only trait obligations lead to + /// derived obligations, so we just store the trait reference here + /// directly. + pub parent_trait_ref: ty::PolyTraitRef<'tcx>, + + /// The parent trait had this cause. + pub parent_code: Rc<ObligationCauseCode<'tcx>>, +} + +/// The following types: +/// * `WhereClause`, +/// * `WellFormed`, +/// * `FromEnv`, +/// * `DomainGoal`, +/// * `Goal`, +/// * `Clause`, +/// * `Environment`, +/// * `InEnvironment`, +/// are used for representing the trait system in the form of +/// logic programming clauses. They are part of the interface +/// for the chalk SLG solver. +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)] +pub enum WhereClause<'tcx> { + Implemented(ty::TraitPredicate<'tcx>), + ProjectionEq(ty::ProjectionPredicate<'tcx>), + RegionOutlives(ty::RegionOutlivesPredicate<'tcx>), + TypeOutlives(ty::TypeOutlivesPredicate<'tcx>), +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)] +pub enum WellFormed<'tcx> { + Trait(ty::TraitPredicate<'tcx>), + Ty(Ty<'tcx>), +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)] +pub enum FromEnv<'tcx> { + Trait(ty::TraitPredicate<'tcx>), + Ty(Ty<'tcx>), +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)] +pub enum DomainGoal<'tcx> { + Holds(WhereClause<'tcx>), + WellFormed(WellFormed<'tcx>), + FromEnv(FromEnv<'tcx>), + Normalize(ty::ProjectionPredicate<'tcx>), +} + +pub type PolyDomainGoal<'tcx> = ty::Binder<DomainGoal<'tcx>>; + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable)] +pub enum QuantifierKind { + Universal, + Existential, +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)] +pub enum GoalKind<'tcx> { + Implies(Clauses<'tcx>, Goal<'tcx>), + And(Goal<'tcx>, Goal<'tcx>), + Not(Goal<'tcx>), + DomainGoal(DomainGoal<'tcx>), + Quantified(QuantifierKind, ty::Binder<Goal<'tcx>>), + Subtype(Ty<'tcx>, Ty<'tcx>), + CannotProve, +} + +pub type Goal<'tcx> = &'tcx GoalKind<'tcx>; + +pub type Goals<'tcx> = &'tcx List<Goal<'tcx>>; + +impl<'tcx> DomainGoal<'tcx> { + pub fn into_goal(self) -> GoalKind<'tcx> { + GoalKind::DomainGoal(self) + } + + pub fn into_program_clause(self) -> ProgramClause<'tcx> { + ProgramClause { + goal: self, + hypotheses: ty::List::empty(), + category: ProgramClauseCategory::Other, + } + } +} + +impl<'tcx> GoalKind<'tcx> { + pub fn from_poly_domain_goal( + domain_goal: PolyDomainGoal<'tcx>, + tcx: TyCtxt<'tcx>, + ) -> GoalKind<'tcx> { + match domain_goal.no_bound_vars() { + Some(p) => p.into_goal(), + None => GoalKind::Quantified( + QuantifierKind::Universal, + domain_goal.map_bound(|p| tcx.mk_goal(p.into_goal())), + ), + } + } +} + +/// This matches the definition from Page 7 of "A Proof Procedure for the Logic of Hereditary +/// Harrop Formulas". +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)] +pub enum Clause<'tcx> { + Implies(ProgramClause<'tcx>), + ForAll(ty::Binder<ProgramClause<'tcx>>), +} + +impl Clause<'tcx> { + pub fn category(self) -> ProgramClauseCategory { + match self { + Clause::Implies(clause) => clause.category, + Clause::ForAll(clause) => clause.skip_binder().category, + } + } +} + +/// Multiple clauses. +pub type Clauses<'tcx> = &'tcx List<Clause<'tcx>>; + +/// A "program clause" has the form `D :- G1, ..., Gn`. It is saying +/// that the domain goal `D` is true if `G1...Gn` are provable. This +/// is equivalent to the implication `G1..Gn => D`; we usually write +/// it with the reverse implication operator `:-` to emphasize the way +/// that programs are actually solved (via backchaining, which starts +/// with the goal to solve and proceeds from there). +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)] +pub struct ProgramClause<'tcx> { + /// This goal will be considered true ... + pub goal: DomainGoal<'tcx>, + + /// ... if we can prove these hypotheses (there may be no hypotheses at all): + pub hypotheses: Goals<'tcx>, + + /// Useful for filtering clauses. + pub category: ProgramClauseCategory, +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable)] +pub enum ProgramClauseCategory { + ImpliedBound, + WellFormed, + Other, +} + +/// A set of clauses that we assume to be true. +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)] +pub struct Environment<'tcx> { + pub clauses: Clauses<'tcx>, +} + +impl Environment<'tcx> { + pub fn with<G>(self, goal: G) -> InEnvironment<'tcx, G> { + InEnvironment { environment: self, goal } + } +} + +/// Something (usually a goal), along with an environment. +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)] +pub struct InEnvironment<'tcx, G> { + pub environment: Environment<'tcx>, + pub goal: G, +} + +#[derive(Clone, Debug, TypeFoldable)] +pub enum SelectionError<'tcx> { + Unimplemented, + OutputTypeParameterMismatch( + ty::PolyTraitRef<'tcx>, + ty::PolyTraitRef<'tcx>, + ty::error::TypeError<'tcx>, + ), + TraitNotObjectSafe(DefId), + ConstEvalFailure(ErrorHandled), + Overflow, +} + +/// When performing resolution, it is typically the case that there +/// can be one of three outcomes: +/// +/// - `Ok(Some(r))`: success occurred with result `r` +/// - `Ok(None)`: could not definitely determine anything, usually due +/// to inconclusive type inference. +/// - `Err(e)`: error `e` occurred +pub type SelectionResult<'tcx, T> = Result<Option<T>, SelectionError<'tcx>>; + +/// Given the successful resolution of an obligation, the `Vtable` +/// indicates where the vtable comes from. Note that while we call this +/// a "vtable", it does not necessarily indicate dynamic dispatch at +/// runtime. `Vtable` instances just tell the compiler where to find +/// methods, but in generic code those methods are typically statically +/// dispatched -- only when an object is constructed is a `Vtable` +/// instance reified into an actual vtable. +/// +/// For example, the vtable may be tied to a specific impl (case A), +/// or it may be relative to some bound that is in scope (case B). +/// +/// ``` +/// impl<T:Clone> Clone<T> for Option<T> { ... } // Impl_1 +/// impl<T:Clone> Clone<T> for Box<T> { ... } // Impl_2 +/// impl Clone for int { ... } // Impl_3 +/// +/// fn foo<T:Clone>(concrete: Option<Box<int>>, +/// param: T, +/// mixed: Option<T>) { +/// +/// // Case A: Vtable points at a specific impl. Only possible when +/// // type is concretely known. If the impl itself has bounded +/// // type parameters, Vtable will carry resolutions for those as well: +/// concrete.clone(); // Vtable(Impl_1, [Vtable(Impl_2, [Vtable(Impl_3)])]) +/// +/// // Case B: Vtable must be provided by caller. This applies when +/// // type is a type parameter. +/// param.clone(); // VtableParam +/// +/// // Case C: A mix of cases A and B. +/// mixed.clone(); // Vtable(Impl_1, [VtableParam]) +/// } +/// ``` +/// +/// ### The type parameter `N` +/// +/// See explanation on `VtableImplData`. +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] +pub enum Vtable<'tcx, N> { + /// Vtable identifying a particular impl. + VtableImpl(VtableImplData<'tcx, N>), + + /// Vtable for auto trait implementations. + /// This carries the information and nested obligations with regards + /// to an auto implementation for a trait `Trait`. The nested obligations + /// ensure the trait implementation holds for all the constituent types. + VtableAutoImpl(VtableAutoImplData<N>), + + /// Successful resolution to an obligation provided by the caller + /// for some type parameter. The `Vec<N>` represents the + /// obligations incurred from normalizing the where-clause (if + /// any). + VtableParam(Vec<N>), + + /// Virtual calls through an object. + VtableObject(VtableObjectData<'tcx, N>), + + /// Successful resolution for a builtin trait. + VtableBuiltin(VtableBuiltinData<N>), + + /// Vtable automatically generated for a closure. The `DefId` is the ID + /// of the closure expression. This is a `VtableImpl` in spirit, but the + /// impl is generated by the compiler and does not appear in the source. + VtableClosure(VtableClosureData<'tcx, N>), + + /// Same as above, but for a function pointer type with the given signature. + VtableFnPointer(VtableFnPointerData<'tcx, N>), + + /// Vtable automatically generated for a generator. + VtableGenerator(VtableGeneratorData<'tcx, N>), + + /// Vtable for a trait alias. + VtableTraitAlias(VtableTraitAliasData<'tcx, N>), +} + +impl<'tcx, N> Vtable<'tcx, N> { + pub fn nested_obligations(self) -> Vec<N> { + match self { + VtableImpl(i) => i.nested, + VtableParam(n) => n, + VtableBuiltin(i) => i.nested, + VtableAutoImpl(d) => d.nested, + VtableClosure(c) => c.nested, + VtableGenerator(c) => c.nested, + VtableObject(d) => d.nested, + VtableFnPointer(d) => d.nested, + VtableTraitAlias(d) => d.nested, + } + } + + pub fn map<M, F>(self, f: F) -> Vtable<'tcx, M> + where + F: FnMut(N) -> M, + { + match self { + VtableImpl(i) => VtableImpl(VtableImplData { + impl_def_id: i.impl_def_id, + substs: i.substs, + nested: i.nested.into_iter().map(f).collect(), + }), + VtableParam(n) => VtableParam(n.into_iter().map(f).collect()), + VtableBuiltin(i) => { + VtableBuiltin(VtableBuiltinData { nested: i.nested.into_iter().map(f).collect() }) + } + VtableObject(o) => VtableObject(VtableObjectData { + upcast_trait_ref: o.upcast_trait_ref, + vtable_base: o.vtable_base, + nested: o.nested.into_iter().map(f).collect(), + }), + VtableAutoImpl(d) => VtableAutoImpl(VtableAutoImplData { + trait_def_id: d.trait_def_id, + nested: d.nested.into_iter().map(f).collect(), + }), + VtableClosure(c) => VtableClosure(VtableClosureData { + closure_def_id: c.closure_def_id, + substs: c.substs, + nested: c.nested.into_iter().map(f).collect(), + }), + VtableGenerator(c) => VtableGenerator(VtableGeneratorData { + generator_def_id: c.generator_def_id, + substs: c.substs, + nested: c.nested.into_iter().map(f).collect(), + }), + VtableFnPointer(p) => VtableFnPointer(VtableFnPointerData { + fn_ty: p.fn_ty, + nested: p.nested.into_iter().map(f).collect(), + }), + VtableTraitAlias(d) => VtableTraitAlias(VtableTraitAliasData { + alias_def_id: d.alias_def_id, + substs: d.substs, + nested: d.nested.into_iter().map(f).collect(), + }), + } + } +} + +/// Identifies a particular impl in the source, along with a set of +/// substitutions from the impl's type/lifetime parameters. The +/// `nested` vector corresponds to the nested obligations attached to +/// the impl's type parameters. +/// +/// The type parameter `N` indicates the type used for "nested +/// obligations" that are required by the impl. During type-check, this +/// is `Obligation`, as one might expect. During codegen, however, this +/// is `()`, because codegen only requires a shallow resolution of an +/// impl, and nested obligations are satisfied later. +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] +pub struct VtableImplData<'tcx, N> { + pub impl_def_id: DefId, + pub substs: SubstsRef<'tcx>, + pub nested: Vec<N>, +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] +pub struct VtableGeneratorData<'tcx, N> { + pub generator_def_id: DefId, + pub substs: SubstsRef<'tcx>, + /// Nested obligations. This can be non-empty if the generator + /// signature contains associated types. + pub nested: Vec<N>, +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] +pub struct VtableClosureData<'tcx, N> { + pub closure_def_id: DefId, + pub substs: SubstsRef<'tcx>, + /// Nested obligations. This can be non-empty if the closure + /// signature contains associated types. + pub nested: Vec<N>, +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] +pub struct VtableAutoImplData<N> { + pub trait_def_id: DefId, + pub nested: Vec<N>, +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] +pub struct VtableBuiltinData<N> { + pub nested: Vec<N>, +} + +/// A vtable for some object-safe trait `Foo` automatically derived +/// for the object type `Foo`. +#[derive(PartialEq, Eq, Clone, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] +pub struct VtableObjectData<'tcx, N> { + /// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`. + pub upcast_trait_ref: ty::PolyTraitRef<'tcx>, + + /// The vtable is formed by concatenating together the method lists of + /// the base object trait and all supertraits; this is the start of + /// `upcast_trait_ref`'s methods in that vtable. + pub vtable_base: usize, + + pub nested: Vec<N>, +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] +pub struct VtableFnPointerData<'tcx, N> { + pub fn_ty: Ty<'tcx>, + pub nested: Vec<N>, +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] +pub struct VtableTraitAliasData<'tcx, N> { + pub alias_def_id: DefId, + pub substs: SubstsRef<'tcx>, + pub nested: Vec<N>, +} + +pub trait ExClauseFold<'tcx> +where + Self: chalk_engine::context::Context + Clone, +{ + fn fold_ex_clause_with<F: TypeFolder<'tcx>>( + ex_clause: &chalk_engine::ExClause<Self>, + folder: &mut F, + ) -> chalk_engine::ExClause<Self>; + + fn visit_ex_clause_with<V: TypeVisitor<'tcx>>( + ex_clause: &chalk_engine::ExClause<Self>, + visitor: &mut V, + ) -> bool; +} + +pub trait ChalkContextLift<'tcx> +where + Self: chalk_engine::context::Context + Clone, +{ + type LiftedExClause: Debug + 'tcx; + type LiftedDelayedLiteral: Debug + 'tcx; + type LiftedLiteral: Debug + 'tcx; + + fn lift_ex_clause_to_tcx( + ex_clause: &chalk_engine::ExClause<Self>, + tcx: TyCtxt<'tcx>, + ) -> Option<Self::LiftedExClause>; + + fn lift_delayed_literal_to_tcx( + ex_clause: &chalk_engine::DelayedLiteral<Self>, + tcx: TyCtxt<'tcx>, + ) -> Option<Self::LiftedDelayedLiteral>; + + fn lift_literal_to_tcx( + ex_clause: &chalk_engine::Literal<Self>, + tcx: TyCtxt<'tcx>, + ) -> Option<Self::LiftedLiteral>; +} diff --git a/src/librustc/traits/types/query.rs b/src/librustc/traits/types/query.rs new file mode 100644 index 00000000000..c9055182620 --- /dev/null +++ b/src/librustc/traits/types/query.rs @@ -0,0 +1,332 @@ +//! Experimental types for the trait query interface. The methods +//! defined in this module are all based on **canonicalization**, +//! which makes a canonical query by replacing unbound inference +//! variables and regions, so that results can be reused more broadly. +//! The providers for the queries defined here can be found in +//! `librustc_traits`. + +use crate::ich::StableHashingContext; +use crate::infer::canonical::{Canonical, QueryResponse}; +use crate::ty::error::TypeError; +use crate::ty::subst::GenericArg; +use crate::ty::{self, Ty, TyCtxt}; + +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::sync::Lrc; +use rustc_errors::struct_span_err; +use rustc_span::source_map::Span; +use std::iter::FromIterator; +use std::mem; + +pub mod type_op { + use crate::ty::fold::TypeFoldable; + use crate::ty::subst::UserSubsts; + use crate::ty::{Predicate, Ty}; + use rustc_hir::def_id::DefId; + use std::fmt; + + #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)] + pub struct AscribeUserType<'tcx> { + pub mir_ty: Ty<'tcx>, + pub def_id: DefId, + pub user_substs: UserSubsts<'tcx>, + } + + impl<'tcx> AscribeUserType<'tcx> { + pub fn new(mir_ty: Ty<'tcx>, def_id: DefId, user_substs: UserSubsts<'tcx>) -> Self { + Self { mir_ty, def_id, user_substs } + } + } + + #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)] + pub struct Eq<'tcx> { + pub a: Ty<'tcx>, + pub b: Ty<'tcx>, + } + + impl<'tcx> Eq<'tcx> { + pub fn new(a: Ty<'tcx>, b: Ty<'tcx>) -> Self { + Self { a, b } + } + } + + #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)] + pub struct Subtype<'tcx> { + pub sub: Ty<'tcx>, + pub sup: Ty<'tcx>, + } + + impl<'tcx> Subtype<'tcx> { + pub fn new(sub: Ty<'tcx>, sup: Ty<'tcx>) -> Self { + Self { sub, sup } + } + } + + #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)] + pub struct ProvePredicate<'tcx> { + pub predicate: Predicate<'tcx>, + } + + impl<'tcx> ProvePredicate<'tcx> { + pub fn new(predicate: Predicate<'tcx>) -> Self { + ProvePredicate { predicate } + } + } + + #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)] + pub struct Normalize<T> { + pub value: T, + } + + impl<'tcx, T> Normalize<T> + where + T: fmt::Debug + TypeFoldable<'tcx>, + { + pub fn new(value: T) -> Self { + Self { value } + } + } +} + +pub type CanonicalProjectionGoal<'tcx> = + Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::ProjectionTy<'tcx>>>; + +pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>; + +pub type CanonicalPredicateGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>>; + +pub type CanonicalTypeOpAscribeUserTypeGoal<'tcx> = + Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>; + +pub type CanonicalTypeOpEqGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Eq<'tcx>>>; + +pub type CanonicalTypeOpSubtypeGoal<'tcx> = + Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Subtype<'tcx>>>; + +pub type CanonicalTypeOpProvePredicateGoal<'tcx> = + Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::ProvePredicate<'tcx>>>; + +pub type CanonicalTypeOpNormalizeGoal<'tcx, T> = + Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>; + +#[derive(Clone, Debug, HashStable)] +pub struct NoSolution; + +pub type Fallible<T> = Result<T, NoSolution>; + +impl<'tcx> From<TypeError<'tcx>> for NoSolution { + fn from(_: TypeError<'tcx>) -> NoSolution { + NoSolution + } +} + +#[derive(Clone, Debug, Default, HashStable, TypeFoldable, Lift)] +pub struct DropckOutlivesResult<'tcx> { + pub kinds: Vec<GenericArg<'tcx>>, + pub overflows: Vec<Ty<'tcx>>, +} + +impl<'tcx> DropckOutlivesResult<'tcx> { + pub fn report_overflows(&self, tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) { + if let Some(overflow_ty) = self.overflows.iter().next() { + let mut err = struct_span_err!( + tcx.sess, + span, + E0320, + "overflow while adding drop-check rules for {}", + ty, + ); + err.note(&format!("overflowed on {}", overflow_ty)); + err.emit(); + } + } + + pub fn into_kinds_reporting_overflows( + self, + tcx: TyCtxt<'tcx>, + span: Span, + ty: Ty<'tcx>, + ) -> Vec<GenericArg<'tcx>> { + self.report_overflows(tcx, span, ty); + let DropckOutlivesResult { kinds, overflows: _ } = self; + kinds + } +} + +/// A set of constraints that need to be satisfied in order for +/// a type to be valid for destruction. +#[derive(Clone, Debug, HashStable)] +pub struct DtorckConstraint<'tcx> { + /// Types that are required to be alive in order for this + /// type to be valid for destruction. + pub outlives: Vec<ty::subst::GenericArg<'tcx>>, + + /// Types that could not be resolved: projections and params. + pub dtorck_types: Vec<Ty<'tcx>>, + + /// If, during the computation of the dtorck constraint, we + /// overflow, that gets recorded here. The caller is expected to + /// report an error. + pub overflows: Vec<Ty<'tcx>>, +} + +impl<'tcx> DtorckConstraint<'tcx> { + pub fn empty() -> DtorckConstraint<'tcx> { + DtorckConstraint { outlives: vec![], dtorck_types: vec![], overflows: vec![] } + } +} + +impl<'tcx> FromIterator<DtorckConstraint<'tcx>> for DtorckConstraint<'tcx> { + fn from_iter<I: IntoIterator<Item = DtorckConstraint<'tcx>>>(iter: I) -> Self { + let mut result = Self::empty(); + + for DtorckConstraint { outlives, dtorck_types, overflows } in iter { + result.outlives.extend(outlives); + result.dtorck_types.extend(dtorck_types); + result.overflows.extend(overflows); + } + + result + } +} + +/// This returns true if the type `ty` is "trivial" for +/// dropck-outlives -- that is, if it doesn't require any types to +/// outlive. This is similar but not *quite* the same as the +/// `needs_drop` test in the compiler already -- that is, for every +/// type T for which this function return true, needs-drop would +/// return `false`. But the reverse does not hold: in particular, +/// `needs_drop` returns false for `PhantomData`, but it is not +/// trivial for dropck-outlives. +/// +/// Note also that `needs_drop` requires a "global" type (i.e., one +/// with erased regions), but this function does not. +pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { + match ty.kind { + // None of these types have a destructor and hence they do not + // require anything in particular to outlive the dtor's + // execution. + ty::Infer(ty::FreshIntTy(_)) + | ty::Infer(ty::FreshFloatTy(_)) + | ty::Bool + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Never + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Char + | ty::GeneratorWitness(..) + | ty::RawPtr(_) + | ty::Ref(..) + | ty::Str + | ty::Foreign(..) + | ty::Error => true, + + // [T; N] and [T] have same properties as T. + ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, ty), + + // (T1..Tn) and closures have same properties as T1..Tn -- + // check if *any* of those are trivial. + ty::Tuple(ref tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t.expect_ty())), + ty::Closure(def_id, ref substs) => { + substs.as_closure().upvar_tys(def_id, tcx).all(|t| trivial_dropck_outlives(tcx, t)) + } + + ty::Adt(def, _) => { + if Some(def.did) == tcx.lang_items().manually_drop() { + // `ManuallyDrop` never has a dtor. + true + } else { + // Other types might. Moreover, PhantomData doesn't + // have a dtor, but it is considered to own its + // content, so it is non-trivial. Unions can have `impl Drop`, + // and hence are non-trivial as well. + false + } + } + + // The following *might* require a destructor: needs deeper inspection. + ty::Dynamic(..) + | ty::Projection(..) + | ty::Param(_) + | ty::Opaque(..) + | ty::Placeholder(..) + | ty::Infer(_) + | ty::Bound(..) + | ty::Generator(..) => false, + + ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), + } +} + +#[derive(Debug, HashStable)] +pub struct CandidateStep<'tcx> { + pub self_ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, + pub autoderefs: usize, + /// `true` if the type results from a dereference of a raw pointer. + /// when assembling candidates, we include these steps, but not when + /// picking methods. This so that if we have `foo: *const Foo` and `Foo` has methods + /// `fn by_raw_ptr(self: *const Self)` and `fn by_ref(&self)`, then + /// `foo.by_raw_ptr()` will work and `foo.by_ref()` won't. + pub from_unsafe_deref: bool, + pub unsize: bool, +} + +#[derive(Clone, Debug, HashStable)] +pub struct MethodAutoderefStepsResult<'tcx> { + /// The valid autoderef steps that could be find. + pub steps: Lrc<Vec<CandidateStep<'tcx>>>, + /// If Some(T), a type autoderef reported an error on. + pub opt_bad_ty: Option<Lrc<MethodAutoderefBadTy<'tcx>>>, + /// If `true`, `steps` has been truncated due to reaching the + /// recursion limit. + pub reached_recursion_limit: bool, +} + +#[derive(Debug, HashStable)] +pub struct MethodAutoderefBadTy<'tcx> { + pub reached_raw_pointer: bool, + pub ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, +} + +/// Result from the `normalize_projection_ty` query. +#[derive(Clone, Debug, HashStable, TypeFoldable, Lift)] +pub struct NormalizationResult<'tcx> { + /// Result of normalization. + pub normalized_ty: Ty<'tcx>, +} + +/// Outlives bounds are relationships between generic parameters, +/// whether they both be regions (`'a: 'b`) or whether types are +/// involved (`T: 'a`). These relationships can be extracted from the +/// full set of predicates we understand or also from types (in which +/// case they are called implied bounds). They are fed to the +/// `OutlivesEnv` which in turn is supplied to the region checker and +/// other parts of the inference system. +#[derive(Clone, Debug, TypeFoldable, Lift)] +pub enum OutlivesBound<'tcx> { + RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>), + RegionSubParam(ty::Region<'tcx>, ty::ParamTy), + RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>), +} + +impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for OutlivesBound<'tcx> { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + OutlivesBound::RegionSubRegion(ref a, ref b) => { + a.hash_stable(hcx, hasher); + b.hash_stable(hcx, hasher); + } + OutlivesBound::RegionSubParam(ref a, ref b) => { + a.hash_stable(hcx, hasher); + b.hash_stable(hcx, hasher); + } + OutlivesBound::RegionSubProjection(ref a, ref b) => { + a.hash_stable(hcx, hasher); + b.hash_stable(hcx, hasher); + } + } + } +} diff --git a/src/librustc/traits/types/select.rs b/src/librustc/traits/types/select.rs new file mode 100644 index 00000000000..ac3d0049c0c --- /dev/null +++ b/src/librustc/traits/types/select.rs @@ -0,0 +1,290 @@ +//! Candidate selection. See the [rustc guide] for more information on how this works. +//! +//! [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/resolution.html#selection + +use self::EvaluationResult::*; + +use super::{SelectionError, SelectionResult}; + +use crate::dep_graph::DepNodeIndex; +use crate::ty::{self, TyCtxt}; + +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::sync::Lock; +use rustc_hir::def_id::DefId; + +#[derive(Clone, Default)] +pub struct SelectionCache<'tcx> { + pub hashmap: Lock< + FxHashMap< + ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>, + WithDepNode<SelectionResult<'tcx, SelectionCandidate<'tcx>>>, + >, + >, +} + +impl<'tcx> SelectionCache<'tcx> { + /// Actually frees the underlying memory in contrast to what stdlib containers do on `clear` + pub fn clear(&self) { + *self.hashmap.borrow_mut() = Default::default(); + } +} + +/// The selection process begins by considering all impls, where +/// clauses, and so forth that might resolve an obligation. Sometimes +/// we'll be able to say definitively that (e.g.) an impl does not +/// apply to the obligation: perhaps it is defined for `usize` but the +/// obligation is for `int`. In that case, we drop the impl out of the +/// list. But the other cases are considered *candidates*. +/// +/// For selection to succeed, there must be exactly one matching +/// candidate. If the obligation is fully known, this is guaranteed +/// by coherence. However, if the obligation contains type parameters +/// or variables, there may be multiple such impls. +/// +/// It is not a real problem if multiple matching impls exist because +/// of type variables - it just means the obligation isn't sufficiently +/// elaborated. In that case we report an ambiguity, and the caller can +/// try again after more type information has been gathered or report a +/// "type annotations needed" error. +/// +/// However, with type parameters, this can be a real problem - type +/// parameters don't unify with regular types, but they *can* unify +/// with variables from blanket impls, and (unless we know its bounds +/// will always be satisfied) picking the blanket impl will be wrong +/// for at least *some* substitutions. To make this concrete, if we have +/// +/// trait AsDebug { type Out : fmt::Debug; fn debug(self) -> Self::Out; } +/// impl<T: fmt::Debug> AsDebug for T { +/// type Out = T; +/// fn debug(self) -> fmt::Debug { self } +/// } +/// fn foo<T: AsDebug>(t: T) { println!("{:?}", <T as AsDebug>::debug(t)); } +/// +/// we can't just use the impl to resolve the `<T as AsDebug>` obligation +/// -- a type from another crate (that doesn't implement `fmt::Debug`) could +/// implement `AsDebug`. +/// +/// Because where-clauses match the type exactly, multiple clauses can +/// only match if there are unresolved variables, and we can mostly just +/// report this ambiguity in that case. This is still a problem - we can't +/// *do anything* with ambiguities that involve only regions. This is issue +/// #21974. +/// +/// If a single where-clause matches and there are no inference +/// variables left, then it definitely matches and we can just select +/// it. +/// +/// In fact, we even select the where-clause when the obligation contains +/// inference variables. The can lead to inference making "leaps of logic", +/// for example in this situation: +/// +/// pub trait Foo<T> { fn foo(&self) -> T; } +/// impl<T> Foo<()> for T { fn foo(&self) { } } +/// impl Foo<bool> for bool { fn foo(&self) -> bool { *self } } +/// +/// pub fn foo<T>(t: T) where T: Foo<bool> { +/// println!("{:?}", <T as Foo<_>>::foo(&t)); +/// } +/// fn main() { foo(false); } +/// +/// Here the obligation `<T as Foo<$0>>` can be matched by both the blanket +/// impl and the where-clause. We select the where-clause and unify `$0=bool`, +/// so the program prints "false". However, if the where-clause is omitted, +/// the blanket impl is selected, we unify `$0=()`, and the program prints +/// "()". +/// +/// Exactly the same issues apply to projection and object candidates, except +/// that we can have both a projection candidate and a where-clause candidate +/// for the same obligation. In that case either would do (except that +/// different "leaps of logic" would occur if inference variables are +/// present), and we just pick the where-clause. This is, for example, +/// required for associated types to work in default impls, as the bounds +/// are visible both as projection bounds and as where-clauses from the +/// parameter environment. +#[derive(PartialEq, Eq, Debug, Clone, TypeFoldable)] +pub enum SelectionCandidate<'tcx> { + BuiltinCandidate { + /// `false` if there are no *further* obligations. + has_nested: bool, + }, + ParamCandidate(ty::PolyTraitRef<'tcx>), + ImplCandidate(DefId), + AutoImplCandidate(DefId), + + /// This is a trait matching with a projected type as `Self`, and + /// we found an applicable bound in the trait definition. + ProjectionCandidate, + + /// Implementation of a `Fn`-family trait by one of the anonymous types + /// generated for a `||` expression. + ClosureCandidate, + + /// Implementation of a `Generator` trait by one of the anonymous types + /// generated for a generator. + GeneratorCandidate, + + /// Implementation of a `Fn`-family trait by one of the anonymous + /// types generated for a fn pointer type (e.g., `fn(int) -> int`) + FnPointerCandidate, + + TraitAliasCandidate(DefId), + + ObjectCandidate, + + BuiltinObjectCandidate, + + BuiltinUnsizeCandidate, +} + +/// The result of trait evaluation. The order is important +/// here as the evaluation of a list is the maximum of the +/// evaluations. +/// +/// The evaluation results are ordered: +/// - `EvaluatedToOk` implies `EvaluatedToOkModuloRegions` +/// implies `EvaluatedToAmbig` implies `EvaluatedToUnknown` +/// - `EvaluatedToErr` implies `EvaluatedToRecur` +/// - the "union" of evaluation results is equal to their maximum - +/// all the "potential success" candidates can potentially succeed, +/// so they are noops when unioned with a definite error, and within +/// the categories it's easy to see that the unions are correct. +#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, HashStable)] +pub enum EvaluationResult { + /// Evaluation successful. + EvaluatedToOk, + /// Evaluation successful, but there were unevaluated region obligations. + EvaluatedToOkModuloRegions, + /// Evaluation is known to be ambiguous -- it *might* hold for some + /// assignment of inference variables, but it might not. + /// + /// While this has the same meaning as `EvaluatedToUnknown` -- we can't + /// know whether this obligation holds or not -- it is the result we + /// would get with an empty stack, and therefore is cacheable. + EvaluatedToAmbig, + /// Evaluation failed because of recursion involving inference + /// variables. We are somewhat imprecise there, so we don't actually + /// know the real result. + /// + /// This can't be trivially cached for the same reason as `EvaluatedToRecur`. + EvaluatedToUnknown, + /// Evaluation failed because we encountered an obligation we are already + /// trying to prove on this branch. + /// + /// We know this branch can't be a part of a minimal proof-tree for + /// the "root" of our cycle, because then we could cut out the recursion + /// and maintain a valid proof tree. However, this does not mean + /// that all the obligations on this branch do not hold -- it's possible + /// that we entered this branch "speculatively", and that there + /// might be some other way to prove this obligation that does not + /// go through this cycle -- so we can't cache this as a failure. + /// + /// For example, suppose we have this: + /// + /// ```rust,ignore (pseudo-Rust) + /// pub trait Trait { fn xyz(); } + /// // This impl is "useless", but we can still have + /// // an `impl Trait for SomeUnsizedType` somewhere. + /// impl<T: Trait + Sized> Trait for T { fn xyz() {} } + /// + /// pub fn foo<T: Trait + ?Sized>() { + /// <T as Trait>::xyz(); + /// } + /// ``` + /// + /// When checking `foo`, we have to prove `T: Trait`. This basically + /// translates into this: + /// + /// ```plain,ignore + /// (T: Trait + Sized →_\impl T: Trait), T: Trait ⊢ T: Trait + /// ``` + /// + /// When we try to prove it, we first go the first option, which + /// recurses. This shows us that the impl is "useless" -- it won't + /// tell us that `T: Trait` unless it already implemented `Trait` + /// by some other means. However, that does not prevent `T: Trait` + /// does not hold, because of the bound (which can indeed be satisfied + /// by `SomeUnsizedType` from another crate). + // + // FIXME: when an `EvaluatedToRecur` goes past its parent root, we + // ought to convert it to an `EvaluatedToErr`, because we know + // there definitely isn't a proof tree for that obligation. Not + // doing so is still sound -- there isn't any proof tree, so the + // branch still can't be a part of a minimal one -- but does not re-enable caching. + EvaluatedToRecur, + /// Evaluation failed. + EvaluatedToErr, +} + +impl EvaluationResult { + /// Returns `true` if this evaluation result is known to apply, even + /// considering outlives constraints. + pub fn must_apply_considering_regions(self) -> bool { + self == EvaluatedToOk + } + + /// Returns `true` if this evaluation result is known to apply, ignoring + /// outlives constraints. + pub fn must_apply_modulo_regions(self) -> bool { + self <= EvaluatedToOkModuloRegions + } + + pub fn may_apply(self) -> bool { + match self { + EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToUnknown => { + true + } + + EvaluatedToErr | EvaluatedToRecur => false, + } + } + + pub fn is_stack_dependent(self) -> bool { + match self { + EvaluatedToUnknown | EvaluatedToRecur => true, + + EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToErr => false, + } + } +} + +/// Indicates that trait evaluation caused overflow. +#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)] +pub struct OverflowError; + +impl<'tcx> From<OverflowError> for SelectionError<'tcx> { + fn from(OverflowError: OverflowError) -> SelectionError<'tcx> { + SelectionError::Overflow + } +} + +#[derive(Clone, Default)] +pub struct EvaluationCache<'tcx> { + pub hashmap: Lock< + FxHashMap<ty::ParamEnvAnd<'tcx, ty::PolyTraitRef<'tcx>>, WithDepNode<EvaluationResult>>, + >, +} + +impl<'tcx> EvaluationCache<'tcx> { + /// Actually frees the underlying memory in contrast to what stdlib containers do on `clear` + pub fn clear(&self) { + *self.hashmap.borrow_mut() = Default::default(); + } +} + +#[derive(Clone, Eq, PartialEq)] +pub struct WithDepNode<T> { + dep_node: DepNodeIndex, + cached_value: T, +} + +impl<T: Clone> WithDepNode<T> { + pub fn new(dep_node: DepNodeIndex, cached_value: T) -> Self { + WithDepNode { dep_node, cached_value } + } + + pub fn get(&self, tcx: TyCtxt<'_>) -> T { + tcx.dep_graph.read_index(self.dep_node); + self.cached_value.clone() + } +} diff --git a/src/librustc/traits/types/specialization_graph.rs b/src/librustc/traits/types/specialization_graph.rs new file mode 100644 index 00000000000..3086850db6d --- /dev/null +++ b/src/librustc/traits/types/specialization_graph.rs @@ -0,0 +1,199 @@ +use crate::ich::{self, StableHashingContext}; +use crate::ty::fast_reject::SimplifiedType; +use crate::ty::{self, TyCtxt}; +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_hir::def_id::{DefId, DefIdMap}; +use syntax::ast::Ident; + +/// A per-trait graph of impls in specialization order. At the moment, this +/// graph forms a tree rooted with the trait itself, with all other nodes +/// representing impls, and parent-child relationships representing +/// specializations. +/// +/// The graph provides two key services: +/// +/// - Construction. This implicitly checks for overlapping impls (i.e., impls +/// that overlap but where neither specializes the other -- an artifact of the +/// simple "chain" rule. +/// +/// - Parent extraction. In particular, the graph can give you the *immediate* +/// parents of a given specializing impl, which is needed for extracting +/// default items amongst other things. In the simple "chain" rule, every impl +/// has at most one parent. +#[derive(RustcEncodable, RustcDecodable, HashStable)] +pub struct Graph { + // All impls have a parent; the "root" impls have as their parent the `def_id` + // of the trait. + pub parent: DefIdMap<DefId>, + + // The "root" impls are found by looking up the trait's def_id. + pub children: DefIdMap<Children>, +} + +impl Graph { + pub fn new() -> Graph { + Graph { parent: Default::default(), children: Default::default() } + } + + /// The parent of a given impl, which is the `DefId` of the trait when the + /// impl is a "specialization root". + pub fn parent(&self, child: DefId) -> DefId { + *self.parent.get(&child).unwrap_or_else(|| panic!("Failed to get parent for {:?}", child)) + } +} + +/// Children of a given impl, grouped into blanket/non-blanket varieties as is +/// done in `TraitDef`. +#[derive(Default, RustcEncodable, RustcDecodable)] +pub struct Children { + // Impls of a trait (or specializations of a given impl). To allow for + // quicker lookup, the impls are indexed by a simplified version of their + // `Self` type: impls with a simplifiable `Self` are stored in + // `nonblanket_impls` keyed by it, while all other impls are stored in + // `blanket_impls`. + // + // A similar division is used within `TraitDef`, but the lists there collect + // together *all* the impls for a trait, and are populated prior to building + // the specialization graph. + /// Impls of the trait. + pub nonblanket_impls: FxHashMap<SimplifiedType, Vec<DefId>>, + + /// Blanket impls associated with the trait. + pub blanket_impls: Vec<DefId>, +} + +/// A node in the specialization graph is either an impl or a trait +/// definition; either can serve as a source of item definitions. +/// There is always exactly one trait definition node: the root. +#[derive(Debug, Copy, Clone)] +pub enum Node { + Impl(DefId), + Trait(DefId), +} + +impl<'tcx> Node { + pub fn is_from_trait(&self) -> bool { + match *self { + Node::Trait(..) => true, + _ => false, + } + } + + /// Iterate over the items defined directly by the given (impl or trait) node. + pub fn items(&self, tcx: TyCtxt<'tcx>) -> ty::AssocItemsIterator<'tcx> { + tcx.associated_items(self.def_id()) + } + + /// Finds an associated item defined in this node. + /// + /// If this returns `None`, the item can potentially still be found in + /// parents of this node. + pub fn item( + &self, + tcx: TyCtxt<'tcx>, + trait_item_name: Ident, + trait_item_kind: ty::AssocKind, + trait_def_id: DefId, + ) -> Option<ty::AssocItem> { + use crate::ty::AssocKind::*; + + tcx.associated_items(self.def_id()).find(move |impl_item| { + match (trait_item_kind, impl_item.kind) { + | (Const, Const) + | (Method, Method) + | (Type, Type) + | (Type, OpaqueTy) // assoc. types can be made opaque in impls + => tcx.hygienic_eq(impl_item.ident, trait_item_name, trait_def_id), + + | (Const, _) + | (Method, _) + | (Type, _) + | (OpaqueTy, _) + => false, + } + }) + } + + pub fn def_id(&self) -> DefId { + match *self { + Node::Impl(did) => did, + Node::Trait(did) => did, + } + } +} + +#[derive(Copy, Clone)] +pub struct Ancestors<'tcx> { + trait_def_id: DefId, + specialization_graph: &'tcx Graph, + current_source: Option<Node>, +} + +impl Iterator for Ancestors<'_> { + type Item = Node; + fn next(&mut self) -> Option<Node> { + let cur = self.current_source.take(); + if let Some(Node::Impl(cur_impl)) = cur { + let parent = self.specialization_graph.parent(cur_impl); + + self.current_source = if parent == self.trait_def_id { + Some(Node::Trait(parent)) + } else { + Some(Node::Impl(parent)) + }; + } + cur + } +} + +pub struct NodeItem<T> { + pub node: Node, + pub item: T, +} + +impl<T> NodeItem<T> { + pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> NodeItem<U> { + NodeItem { node: self.node, item: f(self.item) } + } +} + +impl<'tcx> Ancestors<'tcx> { + /// Finds the bottom-most (ie. most specialized) definition of an associated + /// item. + pub fn leaf_def( + mut self, + tcx: TyCtxt<'tcx>, + trait_item_name: Ident, + trait_item_kind: ty::AssocKind, + ) -> Option<NodeItem<ty::AssocItem>> { + let trait_def_id = self.trait_def_id; + self.find_map(|node| { + node.item(tcx, trait_item_name, trait_item_kind, trait_def_id) + .map(|item| NodeItem { node, item }) + }) + } +} + +/// Walk up the specialization ancestors of a given impl, starting with that +/// impl itself. +pub fn ancestors( + tcx: TyCtxt<'tcx>, + trait_def_id: DefId, + start_from_impl: DefId, +) -> Ancestors<'tcx> { + let specialization_graph = tcx.specialization_graph_of(trait_def_id); + Ancestors { + trait_def_id, + specialization_graph, + current_source: Some(Node::Impl(start_from_impl)), + } +} + +impl<'a> HashStable<StableHashingContext<'a>> for Children { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { + let Children { ref nonblanket_impls, ref blanket_impls } = *self; + + ich::hash_stable_trait_impls(hcx, hasher, blanket_impls, nonblanket_impls); + } +} diff --git a/src/librustc/traits/types/structural_impls.rs b/src/librustc/traits/types/structural_impls.rs new file mode 100644 index 00000000000..48ed29f2bb3 --- /dev/null +++ b/src/librustc/traits/types/structural_impls.rs @@ -0,0 +1,712 @@ +use crate::traits; +use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; +use crate::ty::{self, Lift, Ty, TyCtxt}; +use rustc_span::symbol::Symbol; +use smallvec::SmallVec; + +use std::collections::{BTreeMap, BTreeSet}; +use std::fmt; +use std::rc::Rc; + +// Structural impls for the structs in `traits`. + +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::Vtable<'tcx, N> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + super::VtableImpl(ref v) => write!(f, "{:?}", v), + + super::VtableAutoImpl(ref t) => write!(f, "{:?}", t), + + super::VtableClosure(ref d) => write!(f, "{:?}", d), + + super::VtableGenerator(ref d) => write!(f, "{:?}", d), + + super::VtableFnPointer(ref d) => write!(f, "VtableFnPointer({:?})", d), + + super::VtableObject(ref d) => write!(f, "{:?}", d), + + super::VtableParam(ref n) => write!(f, "VtableParam({:?})", n), + + super::VtableBuiltin(ref d) => write!(f, "{:?}", d), + + super::VtableTraitAlias(ref d) => write!(f, "{:?}", d), + } + } +} + +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableImplData<'tcx, N> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "VtableImplData(impl_def_id={:?}, substs={:?}, nested={:?})", + self.impl_def_id, self.substs, self.nested + ) + } +} + +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableGeneratorData<'tcx, N> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "VtableGeneratorData(generator_def_id={:?}, substs={:?}, nested={:?})", + self.generator_def_id, self.substs, self.nested + ) + } +} + +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableClosureData<'tcx, N> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "VtableClosureData(closure_def_id={:?}, substs={:?}, nested={:?})", + self.closure_def_id, self.substs, self.nested + ) + } +} + +impl<N: fmt::Debug> fmt::Debug for traits::VtableBuiltinData<N> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "VtableBuiltinData(nested={:?})", self.nested) + } +} + +impl<N: fmt::Debug> fmt::Debug for traits::VtableAutoImplData<N> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "VtableAutoImplData(trait_def_id={:?}, nested={:?})", + self.trait_def_id, self.nested + ) + } +} + +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableObjectData<'tcx, N> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "VtableObjectData(upcast={:?}, vtable_base={}, nested={:?})", + self.upcast_trait_ref, self.vtable_base, self.nested + ) + } +} + +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableFnPointerData<'tcx, N> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "VtableFnPointerData(fn_ty={:?}, nested={:?})", self.fn_ty, self.nested) + } +} + +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableTraitAliasData<'tcx, N> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "VtableTraitAlias(alias_def_id={:?}, substs={:?}, nested={:?})", + self.alias_def_id, self.substs, self.nested + ) + } +} + +impl<'tcx> fmt::Display for traits::WhereClause<'tcx> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + use crate::traits::WhereClause::*; + + // Bypass `ty::print` because it does not print out anonymous regions. + // FIXME(eddyb) implement a custom `PrettyPrinter`, or move this to `ty::print`. + fn write_region_name<'tcx>( + r: ty::Region<'tcx>, + fmt: &mut fmt::Formatter<'_>, + ) -> fmt::Result { + match r { + ty::ReLateBound(index, br) => match br { + ty::BoundRegion::BrNamed(_, name) => write!(fmt, "{}", name), + ty::BoundRegion::BrAnon(var) => { + if *index == ty::INNERMOST { + write!(fmt, "'^{}", var) + } else { + write!(fmt, "'^{}_{}", index.index(), var) + } + } + _ => write!(fmt, "'_"), + }, + + _ => write!(fmt, "{}", r), + } + } + + match self { + Implemented(trait_ref) => write!(fmt, "Implemented({})", trait_ref), + ProjectionEq(projection) => write!(fmt, "ProjectionEq({})", projection), + RegionOutlives(predicate) => { + write!(fmt, "RegionOutlives({}: ", predicate.0)?; + write_region_name(predicate.1, fmt)?; + write!(fmt, ")") + } + TypeOutlives(predicate) => { + write!(fmt, "TypeOutlives({}: ", predicate.0)?; + write_region_name(predicate.1, fmt)?; + write!(fmt, ")") + } + } + } +} + +impl<'tcx> fmt::Display for traits::WellFormed<'tcx> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + use crate::traits::WellFormed::*; + + match self { + Trait(trait_ref) => write!(fmt, "WellFormed({})", trait_ref), + Ty(ty) => write!(fmt, "WellFormed({})", ty), + } + } +} + +impl<'tcx> fmt::Display for traits::FromEnv<'tcx> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + use crate::traits::FromEnv::*; + + match self { + Trait(trait_ref) => write!(fmt, "FromEnv({})", trait_ref), + Ty(ty) => write!(fmt, "FromEnv({})", ty), + } + } +} + +impl<'tcx> fmt::Display for traits::DomainGoal<'tcx> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + use crate::traits::DomainGoal::*; + + match self { + Holds(wc) => write!(fmt, "{}", wc), + WellFormed(wf) => write!(fmt, "{}", wf), + FromEnv(from_env) => write!(fmt, "{}", from_env), + Normalize(projection) => { + write!(fmt, "Normalize({} -> {})", projection.projection_ty, projection.ty) + } + } + } +} + +impl fmt::Display for traits::QuantifierKind { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + use crate::traits::QuantifierKind::*; + + match self { + Universal => write!(fmt, "forall"), + Existential => write!(fmt, "exists"), + } + } +} + +/// Collect names for regions / types bound by a quantified goal / clause. +/// This collector does not try to do anything clever like in `ty::print`, it's just used +/// for debug output in tests anyway. +struct BoundNamesCollector { + // Just sort by name because `BoundRegion::BrNamed` does not have a `BoundVar` index anyway. + regions: BTreeSet<Symbol>, + + // Sort by `BoundVar` index, so usually this should be equivalent to the order given + // by the list of type parameters. + types: BTreeMap<u32, Symbol>, + + binder_index: ty::DebruijnIndex, +} + +impl BoundNamesCollector { + fn new() -> Self { + BoundNamesCollector { + regions: BTreeSet::new(), + types: BTreeMap::new(), + binder_index: ty::INNERMOST, + } + } + + fn is_empty(&self) -> bool { + self.regions.is_empty() && self.types.is_empty() + } + + fn write_names(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut start = true; + for r in &self.regions { + if !start { + write!(fmt, ", ")?; + } + start = false; + write!(fmt, "{}", r)?; + } + for (_, t) in &self.types { + if !start { + write!(fmt, ", ")?; + } + start = false; + write!(fmt, "{}", t)?; + } + Ok(()) + } +} + +impl<'tcx> TypeVisitor<'tcx> for BoundNamesCollector { + fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool { + self.binder_index.shift_in(1); + let result = t.super_visit_with(self); + self.binder_index.shift_out(1); + result + } + + fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + match t.kind { + ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { + self.types.insert( + bound_ty.var.as_u32(), + match bound_ty.kind { + ty::BoundTyKind::Param(name) => name, + ty::BoundTyKind::Anon => { + Symbol::intern(&format!("^{}", bound_ty.var.as_u32())) + } + }, + ); + } + + _ => (), + }; + + t.super_visit_with(self) + } + + fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { + match r { + ty::ReLateBound(index, br) if *index == self.binder_index => match br { + ty::BoundRegion::BrNamed(_, name) => { + self.regions.insert(*name); + } + + ty::BoundRegion::BrAnon(var) => { + self.regions.insert(Symbol::intern(&format!("'^{}", var))); + } + + _ => (), + }, + + _ => (), + }; + + r.super_visit_with(self) + } +} + +impl<'tcx> fmt::Display for traits::Goal<'tcx> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + use crate::traits::GoalKind::*; + + match self { + Implies(hypotheses, goal) => { + write!(fmt, "if (")?; + for (index, hyp) in hypotheses.iter().enumerate() { + if index > 0 { + write!(fmt, ", ")?; + } + write!(fmt, "{}", hyp)?; + } + write!(fmt, ") {{ {} }}", goal) + } + And(goal1, goal2) => write!(fmt, "({} && {})", goal1, goal2), + Not(goal) => write!(fmt, "not {{ {} }}", goal), + DomainGoal(goal) => write!(fmt, "{}", goal), + Quantified(qkind, goal) => { + let mut collector = BoundNamesCollector::new(); + goal.skip_binder().visit_with(&mut collector); + + if !collector.is_empty() { + write!(fmt, "{}<", qkind)?; + collector.write_names(fmt)?; + write!(fmt, "> {{ ")?; + } + + write!(fmt, "{}", goal.skip_binder())?; + + if !collector.is_empty() { + write!(fmt, " }}")?; + } + + Ok(()) + } + Subtype(a, b) => write!(fmt, "{} <: {}", a, b), + CannotProve => write!(fmt, "CannotProve"), + } + } +} + +impl<'tcx> fmt::Display for traits::ProgramClause<'tcx> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let traits::ProgramClause { goal, hypotheses, .. } = self; + write!(fmt, "{}", goal)?; + if !hypotheses.is_empty() { + write!(fmt, " :- ")?; + for (index, condition) in hypotheses.iter().enumerate() { + if index > 0 { + write!(fmt, ", ")?; + } + write!(fmt, "{}", condition)?; + } + } + write!(fmt, ".") + } +} + +impl<'tcx> fmt::Display for traits::Clause<'tcx> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + use crate::traits::Clause::*; + + match self { + Implies(clause) => write!(fmt, "{}", clause), + ForAll(clause) => { + let mut collector = BoundNamesCollector::new(); + clause.skip_binder().visit_with(&mut collector); + + if !collector.is_empty() { + write!(fmt, "forall<")?; + collector.write_names(fmt)?; + write!(fmt, "> {{ ")?; + } + + write!(fmt, "{}", clause.skip_binder())?; + + if !collector.is_empty() { + write!(fmt, " }}")?; + } + + Ok(()) + } + } + } +} + +/////////////////////////////////////////////////////////////////////////// +// Lift implementations + +impl<'a, 'tcx> Lift<'tcx> for traits::SelectionError<'a> { + type Lifted = traits::SelectionError<'tcx>; + fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { + match *self { + super::Unimplemented => Some(super::Unimplemented), + super::OutputTypeParameterMismatch(a, b, ref err) => { + tcx.lift(&(a, b)).and_then(|(a, b)| { + tcx.lift(err).map(|err| super::OutputTypeParameterMismatch(a, b, err)) + }) + } + super::TraitNotObjectSafe(def_id) => Some(super::TraitNotObjectSafe(def_id)), + super::ConstEvalFailure(err) => Some(super::ConstEvalFailure(err)), + super::Overflow => Some(super::Overflow), + } + } +} + +impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { + type Lifted = traits::ObligationCauseCode<'tcx>; + fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { + match *self { + super::ReturnNoExpression => Some(super::ReturnNoExpression), + super::MiscObligation => Some(super::MiscObligation), + super::SliceOrArrayElem => Some(super::SliceOrArrayElem), + super::TupleElem => Some(super::TupleElem), + super::ProjectionWf(proj) => tcx.lift(&proj).map(super::ProjectionWf), + super::ItemObligation(def_id) => Some(super::ItemObligation(def_id)), + super::BindingObligation(def_id, span) => Some(super::BindingObligation(def_id, span)), + super::ReferenceOutlivesReferent(ty) => { + tcx.lift(&ty).map(super::ReferenceOutlivesReferent) + } + super::ObjectTypeBound(ty, r) => tcx + .lift(&ty) + .and_then(|ty| tcx.lift(&r).and_then(|r| Some(super::ObjectTypeBound(ty, r)))), + super::ObjectCastObligation(ty) => tcx.lift(&ty).map(super::ObjectCastObligation), + super::Coercion { source, target } => { + Some(super::Coercion { source: tcx.lift(&source)?, target: tcx.lift(&target)? }) + } + super::AssignmentLhsSized => Some(super::AssignmentLhsSized), + super::TupleInitializerSized => Some(super::TupleInitializerSized), + super::StructInitializerSized => Some(super::StructInitializerSized), + super::VariableType(id) => Some(super::VariableType(id)), + super::ReturnValue(id) => Some(super::ReturnValue(id)), + super::ReturnType => Some(super::ReturnType), + super::SizedArgumentType => Some(super::SizedArgumentType), + super::SizedReturnType => Some(super::SizedReturnType), + super::SizedYieldType => Some(super::SizedYieldType), + super::RepeatVec(suggest_flag) => Some(super::RepeatVec(suggest_flag)), + super::FieldSized { adt_kind, last } => Some(super::FieldSized { adt_kind, last }), + super::ConstSized => Some(super::ConstSized), + super::ConstPatternStructural => Some(super::ConstPatternStructural), + super::SharedStatic => Some(super::SharedStatic), + super::BuiltinDerivedObligation(ref cause) => { + tcx.lift(cause).map(super::BuiltinDerivedObligation) + } + super::ImplDerivedObligation(ref cause) => { + tcx.lift(cause).map(super::ImplDerivedObligation) + } + super::CompareImplMethodObligation { + item_name, + impl_item_def_id, + trait_item_def_id, + } => Some(super::CompareImplMethodObligation { + item_name, + impl_item_def_id, + trait_item_def_id, + }), + super::CompareImplTypeObligation { item_name, impl_item_def_id, trait_item_def_id } => { + Some(super::CompareImplTypeObligation { + item_name, + impl_item_def_id, + trait_item_def_id, + }) + } + super::ExprAssignable => Some(super::ExprAssignable), + super::MatchExpressionArm(box super::MatchExpressionArmCause { + arm_span, + source, + ref prior_arms, + last_ty, + scrut_hir_id, + }) => tcx.lift(&last_ty).map(|last_ty| { + super::MatchExpressionArm(box super::MatchExpressionArmCause { + arm_span, + source, + prior_arms: prior_arms.clone(), + last_ty, + scrut_hir_id, + }) + }), + super::Pattern { span, root_ty, origin_expr } => { + tcx.lift(&root_ty).map(|root_ty| super::Pattern { span, root_ty, origin_expr }) + } + super::IfExpression(box super::IfExpressionCause { then, outer, semicolon }) => { + Some(super::IfExpression(box super::IfExpressionCause { then, outer, semicolon })) + } + super::IfExpressionWithNoElse => Some(super::IfExpressionWithNoElse), + super::MainFunctionType => Some(super::MainFunctionType), + super::StartFunctionType => Some(super::StartFunctionType), + super::IntrinsicType => Some(super::IntrinsicType), + super::MethodReceiver => Some(super::MethodReceiver), + super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)), + super::TrivialBound => Some(super::TrivialBound), + super::AssocTypeBound(ref data) => Some(super::AssocTypeBound(data.clone())), + } + } +} + +impl<'a, 'tcx> Lift<'tcx> for traits::DerivedObligationCause<'a> { + type Lifted = traits::DerivedObligationCause<'tcx>; + fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { + tcx.lift(&self.parent_trait_ref).and_then(|trait_ref| { + tcx.lift(&*self.parent_code).map(|code| traits::DerivedObligationCause { + parent_trait_ref: trait_ref, + parent_code: Rc::new(code), + }) + }) + } +} + +impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCause<'a> { + type Lifted = traits::ObligationCause<'tcx>; + fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { + tcx.lift(&self.code).map(|code| traits::ObligationCause { + span: self.span, + body_id: self.body_id, + code, + }) + } +} + +// For codegen only. +impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> { + type Lifted = traits::Vtable<'tcx, ()>; + fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { + match self.clone() { + traits::VtableImpl(traits::VtableImplData { impl_def_id, substs, nested }) => { + tcx.lift(&substs).map(|substs| { + traits::VtableImpl(traits::VtableImplData { impl_def_id, substs, nested }) + }) + } + traits::VtableAutoImpl(t) => Some(traits::VtableAutoImpl(t)), + traits::VtableGenerator(traits::VtableGeneratorData { + generator_def_id, + substs, + nested, + }) => tcx.lift(&substs).map(|substs| { + traits::VtableGenerator(traits::VtableGeneratorData { + generator_def_id: generator_def_id, + substs: substs, + nested: nested, + }) + }), + traits::VtableClosure(traits::VtableClosureData { closure_def_id, substs, nested }) => { + tcx.lift(&substs).map(|substs| { + traits::VtableClosure(traits::VtableClosureData { + closure_def_id, + substs, + nested, + }) + }) + } + traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested }) => { + tcx.lift(&fn_ty).map(|fn_ty| { + traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested }) + }) + } + traits::VtableParam(n) => Some(traits::VtableParam(n)), + traits::VtableBuiltin(n) => Some(traits::VtableBuiltin(n)), + traits::VtableObject(traits::VtableObjectData { + upcast_trait_ref, + vtable_base, + nested, + }) => tcx.lift(&upcast_trait_ref).map(|trait_ref| { + traits::VtableObject(traits::VtableObjectData { + upcast_trait_ref: trait_ref, + vtable_base, + nested, + }) + }), + traits::VtableTraitAlias(traits::VtableTraitAliasData { + alias_def_id, + substs, + nested, + }) => tcx.lift(&substs).map(|substs| { + traits::VtableTraitAlias(traits::VtableTraitAliasData { + alias_def_id, + substs, + nested, + }) + }), + } + } +} + +impl<'a, 'tcx> Lift<'tcx> for traits::Environment<'a> { + type Lifted = traits::Environment<'tcx>; + fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { + tcx.lift(&self.clauses).map(|clauses| traits::Environment { clauses }) + } +} + +impl<'a, 'tcx, G: Lift<'tcx>> Lift<'tcx> for traits::InEnvironment<'a, G> { + type Lifted = traits::InEnvironment<'tcx, G::Lifted>; + fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { + tcx.lift(&self.environment).and_then(|environment| { + tcx.lift(&self.goal).map(|goal| traits::InEnvironment { environment, goal }) + }) + } +} + +impl<'tcx, C> Lift<'tcx> for chalk_engine::ExClause<C> +where + C: chalk_engine::context::Context + Clone, + C: traits::ChalkContextLift<'tcx>, +{ + type Lifted = C::LiftedExClause; + + fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { + <C as traits::ChalkContextLift>::lift_ex_clause_to_tcx(self, tcx) + } +} + +impl<'tcx, C> Lift<'tcx> for chalk_engine::DelayedLiteral<C> +where + C: chalk_engine::context::Context + Clone, + C: traits::ChalkContextLift<'tcx>, +{ + type Lifted = C::LiftedDelayedLiteral; + + fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { + <C as traits::ChalkContextLift>::lift_delayed_literal_to_tcx(self, tcx) + } +} + +impl<'tcx, C> Lift<'tcx> for chalk_engine::Literal<C> +where + C: chalk_engine::context::Context + Clone, + C: traits::ChalkContextLift<'tcx>, +{ + type Lifted = C::LiftedLiteral; + + fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { + <C as traits::ChalkContextLift>::lift_literal_to_tcx(self, tcx) + } +} + +/////////////////////////////////////////////////////////////////////////// +// TypeFoldable implementations. + +CloneTypeFoldableAndLiftImpls! { + traits::QuantifierKind, +} + +impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<traits::Goal<'tcx>> { + fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { + let v = self.iter().map(|t| t.fold_with(folder)).collect::<SmallVec<[_; 8]>>(); + folder.tcx().intern_goals(&v) + } + + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + self.iter().any(|t| t.visit_with(visitor)) + } +} + +impl<'tcx> TypeFoldable<'tcx> for traits::Goal<'tcx> { + fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { + let v = (**self).fold_with(folder); + folder.tcx().mk_goal(v) + } + + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + (**self).visit_with(visitor) + } +} + +CloneTypeFoldableAndLiftImpls! { + traits::ProgramClauseCategory, +} + +impl<'tcx> TypeFoldable<'tcx> for traits::Clauses<'tcx> { + fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { + let v = self.iter().map(|t| t.fold_with(folder)).collect::<SmallVec<[_; 8]>>(); + folder.tcx().intern_clauses(&v) + } + + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + self.iter().any(|t| t.visit_with(visitor)) + } +} + +impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::ExClause<C> +where + C: traits::ExClauseFold<'tcx>, + C::Substitution: Clone, + C::RegionConstraint: Clone, +{ + fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { + <C as traits::ExClauseFold>::fold_ex_clause_with(self, folder) + } + + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + <C as traits::ExClauseFold>::visit_ex_clause_with(self, visitor) + } +} + +EnumTypeFoldableImpl! { + impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::DelayedLiteral<C> { + (chalk_engine::DelayedLiteral::CannotProve)(a), + (chalk_engine::DelayedLiteral::Negative)(a), + (chalk_engine::DelayedLiteral::Positive)(a, b), + } where + C: chalk_engine::context::Context<CanonicalConstrainedSubst: TypeFoldable<'tcx>> + Clone, +} + +EnumTypeFoldableImpl! { + impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::Literal<C> { + (chalk_engine::Literal::Negative)(a), + (chalk_engine::Literal::Positive)(a), + } where + C: chalk_engine::context::Context<GoalInEnvironment: Clone + TypeFoldable<'tcx>> + Clone, +} + +CloneTypeFoldableAndLiftImpls! { + chalk_engine::TableIndex, +} diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 217ca0ca3f6..0282f409b32 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -15,6 +15,16 @@ pub struct ExpectedFound<T> { pub found: T, } +impl<T> ExpectedFound<T> { + pub fn new(a_is_expected: bool, a: T, b: T) -> Self { + if a_is_expected { + ExpectedFound { expected: a, found: b } + } else { + ExpectedFound { expected: b, found: a } + } + } +} + // Data structures used in type unification #[derive(Clone, Debug, TypeFoldable)] pub enum TypeError<'tcx> { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 0781feee845..2538322431e 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -46,7 +46,6 @@ use rustc_target::abi::Align; use syntax::ast::{self, Constness, Ident, Name}; use syntax::node_id::{NodeId, NodeMap, NodeSet}; -use smallvec; use std::cell::RefCell; use std::cmp::{self, Ordering}; use std::fmt; @@ -1348,7 +1347,7 @@ pub trait ToPredicate<'tcx> { impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<TraitRef<'tcx>> { fn to_predicate(&self) -> Predicate<'tcx> { ty::Predicate::Trait( - ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.value.clone() }), + ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.value }), self.constness, ) } @@ -2647,9 +2646,7 @@ impl<'tcx> ::std::ops::Deref for Attributes<'tcx> { pub enum ImplOverlapKind { /// These impls are always allowed to overlap. Permitted { - /// Whether or not the impl is permitted due to the trait being - /// a marker trait (a trait with #[marker], or a trait with - /// no associated items and #![feature(overlapping_marker_traits)] enabled) + /// Whether or not the impl is permitted due to the trait being a `#[marker]` trait marker: bool, }, /// These impls are allowed to overlap, but that raises @@ -2746,19 +2743,6 @@ impl<'tcx> TyCtxt<'tcx> { variant.fields.iter().position(|field| self.hygienic_eq(ident, field.ident, variant.def_id)) } - pub fn associated_items(self, def_id: DefId) -> AssocItemsIterator<'tcx> { - // Ideally, we would use `-> impl Iterator` here, but it falls - // afoul of the conservative "capture [restrictions]" we put - // in place, so we use a hand-written iterator. - // - // [restrictions]: https://github.com/rust-lang/rust/issues/34511#issuecomment-373423999 - AssocItemsIterator { - tcx: self, - def_ids: self.associated_item_def_ids(def_id), - next_index: 0, - } - } - /// Returns `true` if the impls are the same polarity and the trait either /// has no items or is annotated #[marker] and prevents item overrides. pub fn impls_are_allowed_to_overlap( @@ -2796,15 +2780,7 @@ impl<'tcx> TyCtxt<'tcx> { | (ImplPolarity::Negative, ImplPolarity::Negative) => {} }; - let is_marker_overlap = if self.features().overlapping_marker_traits { - let trait1_is_empty = self.impl_trait_ref(def_id1).map_or(false, |trait_ref| { - self.associated_item_def_ids(trait_ref.def_id).is_empty() - }); - let trait2_is_empty = self.impl_trait_ref(def_id2).map_or(false, |trait_ref| { - self.associated_item_def_ids(trait_ref.def_id).is_empty() - }); - trait1_is_empty && trait2_is_empty - } else { + let is_marker_overlap = { let is_marker_impl = |def_id: DefId| -> bool { let trait_ref = self.impl_trait_ref(def_id); trait_ref.map_or(false, |tr| self.trait_def(tr.def_id).is_marker) @@ -2998,20 +2974,22 @@ impl<'tcx> TyCtxt<'tcx> { } } -#[derive(Clone)] +#[derive(Copy, Clone, HashStable)] pub struct AssocItemsIterator<'tcx> { - tcx: TyCtxt<'tcx>, - def_ids: &'tcx [DefId], - next_index: usize, + pub items: &'tcx [AssocItem], } -impl Iterator for AssocItemsIterator<'_> { +impl<'tcx> Iterator for AssocItemsIterator<'tcx> { type Item = AssocItem; + #[inline] fn next(&mut self) -> Option<AssocItem> { - let def_id = self.def_ids.get(self.next_index)?; - self.next_index += 1; - Some(self.tcx.associated_item(*def_id)) + if let Some((first, rest)) = self.items.split_first() { + self.items = rest; + Some(*first) + } else { + None + } } } diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index e27f2bdb8d2..dab950e23f6 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -14,7 +14,7 @@ use rustc_target::spec::abi; use syntax::ast::*; use syntax::attr; use syntax::node_id::NodeMap; -use syntax::visit::{self, Visitor}; +use syntax::visit::{self, AssocCtxt, Visitor}; use log::debug; use smallvec::{smallvec, SmallVec}; @@ -81,25 +81,23 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> { } } - fn visit_trait_item(&mut self, item: &'a AssocItem) { - self.lctx.with_hir_id_owner(item.id, |lctx| { - let hir_item = lctx.lower_trait_item(item); - let id = hir::TraitItemId { hir_id: hir_item.hir_id }; - lctx.trait_items.insert(id, hir_item); - lctx.modules.get_mut(&lctx.current_module).unwrap().trait_items.insert(id); + fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { + self.lctx.with_hir_id_owner(item.id, |lctx| match ctxt { + AssocCtxt::Trait => { + let hir_item = lctx.lower_trait_item(item); + let id = hir::TraitItemId { hir_id: hir_item.hir_id }; + lctx.trait_items.insert(id, hir_item); + lctx.modules.get_mut(&lctx.current_module).unwrap().trait_items.insert(id); + } + AssocCtxt::Impl => { + let hir_item = lctx.lower_impl_item(item); + let id = hir::ImplItemId { hir_id: hir_item.hir_id }; + lctx.impl_items.insert(id, hir_item); + lctx.modules.get_mut(&lctx.current_module).unwrap().impl_items.insert(id); + } }); - visit::walk_trait_item(self, item); - } - - fn visit_impl_item(&mut self, item: &'a AssocItem) { - self.lctx.with_hir_id_owner(item.id, |lctx| { - let hir_item = lctx.lower_impl_item(item); - let id = hir::ImplItemId { hir_id: hir_item.hir_id }; - lctx.impl_items.insert(id, hir_item); - lctx.modules.get_mut(&lctx.current_module).unwrap().impl_items.insert(id); - }); - visit::walk_impl_item(self, item); + visit::walk_assoc_item(self, item, ctxt); } } @@ -299,20 +297,17 @@ impl<'hir> LoweringContext<'_, 'hir> { // `impl Future<Output = T>` here because lower_body // only cares about the input argument patterns in the function // declaration (decl), not the return types. + let asyncness = header.asyncness.node; let body_id = - this.lower_maybe_async_body(span, &decl, header.asyncness.node, Some(body)); + this.lower_maybe_async_body(span, &decl, asyncness, body.as_deref()); let (generics, decl) = this.add_in_band_defs( generics, fn_def_id, AnonymousLifetimeMode::PassThrough, |this, idty| { - this.lower_fn_decl( - &decl, - Some((fn_def_id, idty)), - true, - header.asyncness.node.opt_return_id(), - ) + let ret_id = asyncness.opt_return_id(); + this.lower_fn_decl(&decl, Some((fn_def_id, idty)), true, ret_id) }, ); let sig = hir::FnSig { decl, header: this.lower_fn_header(header) }; @@ -658,7 +653,8 @@ impl<'hir> LoweringContext<'_, 'hir> { ident: i.ident, attrs: self.lower_attrs(&i.attrs), kind: match i.kind { - ForeignItemKind::Fn(ref fdec, ref generics) => { + ForeignItemKind::Fn(ref sig, ref generics, _) => { + let fdec = &sig.decl; let (generics, (fn_dec, fn_args)) = self.add_in_band_defs( generics, def_id, diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index c3e96a31e40..5816a64fca5 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -32,6 +32,7 @@ #![feature(array_value_iter)] #![feature(crate_visibility_modifier)] +#![recursion_limit = "256"] use rustc::arena::Arena; use rustc::dep_graph::DepGraph; @@ -63,7 +64,7 @@ use syntax::attr; use syntax::node_id::NodeMap; use syntax::token::{self, Nonterminal, Token}; use syntax::tokenstream::{TokenStream, TokenTree}; -use syntax::visit::{self, Visitor}; +use syntax::visit::{self, AssocCtxt, Visitor}; use syntax::walk_list; use log::{debug, trace}; @@ -485,25 +486,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }); } - fn visit_trait_item(&mut self, item: &'tcx AssocItem) { + fn visit_assoc_item(&mut self, item: &'tcx AssocItem, ctxt: AssocCtxt) { self.lctx.allocate_hir_id_counter(item.id); - - match item.kind { - AssocItemKind::Fn(_, None) => { - // Ignore patterns in trait methods without bodies - self.with_hir_id_owner(None, |this| visit::walk_trait_item(this, item)); - } - _ => self.with_hir_id_owner(Some(item.id), |this| { - visit::walk_trait_item(this, item); - }), - } - } - - fn visit_impl_item(&mut self, item: &'tcx AssocItem) { - self.lctx.allocate_hir_id_counter(item.id); - self.with_hir_id_owner(Some(item.id), |this| { - visit::walk_impl_item(this, item); - }); + let owner = match (&item.kind, ctxt) { + // Ignore patterns in trait methods without bodies. + (AssocItemKind::Fn(_, None), AssocCtxt::Trait) => None, + _ => Some(item.id), + }; + self.with_hir_id_owner(owner, |this| visit::walk_assoc_item(this, item, ctxt)); } fn visit_foreign_item(&mut self, i: &'tcx ForeignItem) { diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index cb64e2e95bf..79ed7f234f7 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -8,7 +8,7 @@ use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{struct_span_err, Applicability, FatalError}; +use rustc_errors::{error_code, struct_span_err, Applicability, FatalError}; use rustc_parse::validate_attr; use rustc_session::lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY; use rustc_session::lint::LintBuffer; @@ -20,7 +20,7 @@ use std::mem; use syntax::ast::*; use syntax::attr; use syntax::expand::is_proc_macro_attr; -use syntax::visit::{self, Visitor}; +use syntax::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use syntax::walk_list; /// Is `self` allowed semantically as the first parameter in an `FnDecl`? @@ -49,6 +49,13 @@ impl BoundContext { struct AstValidator<'a> { session: &'a Session, + + /// The span of the `extern` in an `extern { ... }` block, if any. + extern_mod: Option<&'a Item>, + + /// Are we inside a trait impl? + in_trait_impl: bool, + has_proc_macro_decls: bool, /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`. @@ -74,6 +81,12 @@ struct AstValidator<'a> { } impl<'a> AstValidator<'a> { + fn with_in_trait_impl(&mut self, is_in: bool, f: impl FnOnce(&mut Self)) { + let old = mem::replace(&mut self.in_trait_impl, is_in); + f(self); + self.in_trait_impl = old; + } + fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) { let old = mem::replace(&mut self.is_impl_trait_banned, true); f(self); @@ -389,13 +402,9 @@ impl<'a> AstValidator<'a> { } } - fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) { - if body.is_some() { - return; - } - + fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) { self.err_handler() - .struct_span_err(sp, &format!("associated {} in `impl` without body", ctx)) + .struct_span_err(sp, msg) .span_suggestion( self.session.source_map().end_point(sp), &format!("provide a definition for the {}", ctx), @@ -405,6 +414,13 @@ impl<'a> AstValidator<'a> { .emit(); } + fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) { + if body.is_none() { + let msg = format!("associated {} in `impl` without body", ctx); + self.error_item_without_body(sp, ctx, &msg, sugg); + } + } + fn check_impl_assoc_type_no_bounds(&self, bounds: &[GenericBound]) { let span = match bounds { [] => return, @@ -416,8 +432,71 @@ impl<'a> AstValidator<'a> { .emit(); } - fn check_c_varadic_type(&self, decl: &FnDecl) { - for Param { ty, span, .. } in &decl.inputs { + /// An `fn` in `extern { ... }` cannot have a body `{ ... }`. + fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) { + let body = match body { + None => return, + Some(body) => body, + }; + self.err_handler() + .struct_span_err(ident.span, "incorrect function inside `extern` block") + .span_label(ident.span, "cannot have a body") + .span_suggestion( + body.span, + "remove the invalid body", + ";".to_string(), + Applicability::MaybeIncorrect, + ) + .help( + "you might have meant to write a function accessible through FFI, \ + which can be done by writing `extern fn` outside of the `extern` block", + ) + .span_label( + self.current_extern_span(), + "`extern` blocks define existing foreign functions and functions \ + inside of them cannot have a body", + ) + .note("for more information, visit https://doc.rust-lang.org/std/keyword.extern.html") + .emit(); + } + + fn current_extern_span(&self) -> Span { + self.session.source_map().def_span(self.extern_mod.unwrap().span) + } + + /// An `fn` in `extern { ... }` cannot have qualfiers, e.g. `async fn`. + fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) { + if header.has_qualifiers() { + self.err_handler() + .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers") + .span_label(self.current_extern_span(), "in this `extern` block") + .span_suggestion( + span.until(ident.span.shrink_to_lo()), + "remove the qualifiers", + "fn ".to_string(), + Applicability::MaybeIncorrect, + ) + .emit(); + } + } + + /// Reject C-varadic type unless the function is foreign, + /// or free and `unsafe extern "C"` semantically. + fn check_c_varadic_type(&self, fk: FnKind<'a>) { + match (fk.ctxt(), fk.header()) { + (Some(FnCtxt::Foreign), _) => return, + (Some(FnCtxt::Free), Some(header)) => match header.ext { + Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) | Extern::Implicit + if header.unsafety == Unsafety::Unsafe => + { + return; + } + _ => {} + }, + _ => {} + }; + + for Param { ty, span, .. } in &fk.decl().inputs { if let TyKind::CVarArgs = ty.kind { self.err_handler() .struct_span_err( @@ -428,6 +507,24 @@ impl<'a> AstValidator<'a> { } } } + + /// We currently do not permit const generics in `const fn`, + /// as this is tantamount to allowing compile-time dependent typing. + /// + /// FIXME(const_generics): Is this really true / necessary? Discuss with @varkor. + /// At any rate, the restriction feels too syntactic. Consider moving it to e.g. typeck. + fn check_const_fn_const_generic(&self, span: Span, sig: &FnSig, generics: &Generics) { + if sig.header.constness.node == Constness::Const { + // Look for const generics and error if we find any. + for param in &generics.params { + if let GenericParamKind::Const { .. } = param.kind { + self.err_handler() + .struct_span_err(span, "const parameters are not permitted in `const fn`") + .emit(); + } + } + } + } } enum GenericPosition { @@ -532,9 +629,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_expr(&mut self, expr: &'a Expr) { match &expr.kind { - ExprKind::Closure(_, _, _, fn_decl, _, _) => { - self.check_fn_decl(fn_decl, SelfSemantic::No); - } ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => { struct_span_err!( self.session, @@ -647,31 +741,32 @@ impl<'a> Visitor<'a> for AstValidator<'a> { generics: _, of_trait: Some(_), ref self_ty, - ref items, + items: _, } => { - self.invalid_visibility(&item.vis, None); - if let TyKind::Err = self_ty.kind { - self.err_handler() - .struct_span_err(item.span, "`impl Trait for .. {}` is an obsolete syntax") - .help("use `auto trait Trait {}` instead") + self.with_in_trait_impl(true, |this| { + this.invalid_visibility(&item.vis, None); + if let TyKind::Err = self_ty.kind { + this.err_handler() + .struct_span_err( + item.span, + "`impl Trait for .. {}` is an obsolete syntax", + ) + .help("use `auto trait Trait {}` instead") + .emit(); + } + if unsafety == Unsafety::Unsafe && polarity == ImplPolarity::Negative { + struct_span_err!( + this.session, + item.span, + E0198, + "negative impls cannot be unsafe" + ) .emit(); - } - if unsafety == Unsafety::Unsafe && polarity == ImplPolarity::Negative { - struct_span_err!( - self.session, - item.span, - E0198, - "negative impls cannot be unsafe" - ) - .emit(); - } - for impl_item in items { - self.invalid_visibility(&impl_item.vis, None); - if let AssocItemKind::Fn(ref sig, _) = impl_item.kind { - self.check_trait_fn_not_const(sig.header.constness); - self.check_trait_fn_not_async(impl_item.span, sig.header.asyncness.node); } - } + + visit::walk_item(this, item); + }); + return; // Avoid visiting again. } ItemKind::Impl { unsafety, @@ -712,40 +807,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> { .emit(); } } - ItemKind::Fn(ref sig, ref generics, _) => { - self.visit_fn_header(&sig.header); - self.check_fn_decl(&sig.decl, SelfSemantic::No); - // We currently do not permit const generics in `const fn`, as - // this is tantamount to allowing compile-time dependent typing. - if sig.header.constness.node == Constness::Const { - // Look for const generics and error if we find any. - for param in &generics.params { - match param.kind { - GenericParamKind::Const { .. } => { - self.err_handler() - .struct_span_err( - item.span, - "const parameters are not permitted in `const fn`", - ) - .emit(); - } - _ => {} - } - } - } - // Reject C-varadic type unless the function is `unsafe extern "C"` semantically. - match sig.header.ext { - Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) - | Extern::Implicit - if sig.header.unsafety == Unsafety::Unsafe => {} - _ => self.check_c_varadic_type(&sig.decl), + ItemKind::Fn(ref sig, ref generics, ref body) => { + self.check_const_fn_const_generic(item.span, sig, generics); + + if body.is_none() { + let msg = "free function without a body"; + self.error_item_without_body(item.span, "function", msg, " { <body> }"); } } - ItemKind::ForeignMod(..) => { + ItemKind::ForeignMod(_) => { + let old_item = mem::replace(&mut self.extern_mod, Some(item)); self.invalid_visibility( &item.vis, Some("place qualifiers on individual foreign items instead"), ); + visit::walk_item(self, item); + self.extern_mod = old_item; + return; // Avoid visiting again. } ItemKind::Enum(ref def, _) => { for variant in &def.variants { @@ -796,7 +874,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.with_bound_context(BoundContext::TraitBounds, |this| { walk_list!(this, visit_param_bound, bounds); }); - walk_list!(self, visit_trait_item, trait_items); + walk_list!(self, visit_assoc_item, trait_items, AssocCtxt::Trait); walk_list!(self, visit_attribute, &item.attrs); return; } @@ -820,19 +898,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { - match fi.kind { - ForeignItemKind::Fn(ref decl, _) => { - self.check_fn_decl(decl, SelfSemantic::No); - Self::check_decl_no_pat(decl, |span, _| { - struct_span_err!( - self.session, - span, - E0130, - "patterns aren't allowed in foreign function declarations" - ) - .span_label(span, "pattern not allowed in foreign function") - .emit(); - }); + match &fi.kind { + ForeignItemKind::Fn(sig, _, body) => { + self.check_foreign_fn_bodyless(fi.ident, body.as_deref()); + self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header); } ForeignItemKind::Static(..) | ForeignItemKind::Ty | ForeignItemKind::Macro(..) => {} } @@ -1011,67 +1080,84 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }) } - fn visit_impl_item(&mut self, ii: &'a AssocItem) { - match &ii.kind { - AssocItemKind::Const(_, body) => { - self.check_impl_item_provided(ii.span, body, "constant", " = <expr>;"); - } - AssocItemKind::Fn(_, body) => { - self.check_impl_item_provided(ii.span, body, "function", " { <body> }"); - } - AssocItemKind::TyAlias(bounds, body) => { - self.check_impl_item_provided(ii.span, body, "type", " = <type>;"); - self.check_impl_assoc_type_no_bounds(bounds); - } - _ => {} + fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) { + // Only associated `fn`s can have `self` parameters. + let self_semantic = match fk.ctxt() { + Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes, + _ => SelfSemantic::No, + }; + self.check_fn_decl(fk.decl(), self_semantic); + + self.check_c_varadic_type(fk); + + // Functions without bodies cannot have patterns. + if let FnKind::Fn(ctxt, _, sig, _, None) = fk { + Self::check_decl_no_pat(&sig.decl, |span, mut_ident| { + let (code, msg, label) = match ctxt { + FnCtxt::Foreign => ( + error_code!(E0130), + "patterns aren't allowed in foreign function declarations", + "pattern not allowed in foreign function", + ), + _ => ( + error_code!(E0642), + "patterns aren't allowed in functions without bodies", + "pattern not allowed in function without body", + ), + }; + if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) { + self.lint_buffer.buffer_lint(PATTERNS_IN_FNS_WITHOUT_BODY, id, span, msg); + } else { + self.err_handler() + .struct_span_err(span, msg) + .span_label(span, label) + .code(code) + .emit(); + } + }); } - visit::walk_impl_item(self, ii); + + visit::walk_fn(self, fk, span); } - fn visit_trait_item(&mut self, ti: &'a AssocItem) { - self.invalid_visibility(&ti.vis, None); - self.check_defaultness(ti.span, ti.defaultness); - - if let AssocItemKind::Fn(sig, block) = &ti.kind { - self.check_trait_fn_not_async(ti.span, sig.header.asyncness.node); - self.check_trait_fn_not_const(sig.header.constness); - if block.is_none() { - Self::check_decl_no_pat(&sig.decl, |span, mut_ident| { - if mut_ident { - self.lint_buffer.buffer_lint( - PATTERNS_IN_FNS_WITHOUT_BODY, - ti.id, - span, - "patterns aren't allowed in methods without bodies", - ); - } else { - struct_span_err!( - self.session, - span, - E0642, - "patterns aren't allowed in methods without bodies" - ) - .emit(); - } - }); - } + fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { + if ctxt == AssocCtxt::Trait { + self.check_defaultness(item.span, item.defaultness); } - visit::walk_trait_item(self, ti); - } + if ctxt == AssocCtxt::Impl { + match &item.kind { + AssocItemKind::Const(_, body) => { + self.check_impl_item_provided(item.span, body, "constant", " = <expr>;"); + } + AssocItemKind::Fn(_, body) => { + self.check_impl_item_provided(item.span, body, "function", " { <body> }"); + } + AssocItemKind::TyAlias(bounds, body) => { + self.check_impl_item_provided(item.span, body, "type", " = <type>;"); + self.check_impl_assoc_type_no_bounds(bounds); + } + _ => {} + } + } - fn visit_assoc_item(&mut self, item: &'a AssocItem) { - if let AssocItemKind::Fn(sig, _) = &item.kind { - self.check_fn_decl(&sig.decl, SelfSemantic::Yes); - self.check_c_varadic_type(&sig.decl); + if ctxt == AssocCtxt::Trait || self.in_trait_impl { + self.invalid_visibility(&item.vis, None); + if let AssocItemKind::Fn(sig, _) = &item.kind { + self.check_trait_fn_not_const(sig.header.constness); + self.check_trait_fn_not_async(item.span, sig.header.asyncness.node); + } } - visit::walk_assoc_item(self, item); + + self.with_in_trait_impl(false, |this| visit::walk_assoc_item(this, item, ctxt)); } } pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool { let mut validator = AstValidator { session, + extern_mod: None, + in_trait_impl: false, has_proc_macro_decls: false, outer_impl_trait: None, bound_context: None, diff --git a/src/librustc_ast_passes/feature_gate.rs b/src/librustc_ast_passes/feature_gate.rs index 3b13ab354fd..a10ac94d894 100644 --- a/src/librustc_ast_passes/feature_gate.rs +++ b/src/librustc_ast_passes/feature_gate.rs @@ -8,7 +8,7 @@ use rustc_span::Span; use syntax::ast::{self, AssocTyConstraint, AssocTyConstraintKind, NodeId}; use syntax::ast::{GenericParam, GenericParamKind, PatKind, RangeEnd, VariantData}; use syntax::attr; -use syntax::visit::{self, FnKind, Visitor}; +use syntax::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use log::debug; @@ -492,25 +492,17 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { visit::walk_pat(self, pattern) } - fn visit_fn( - &mut self, - fn_kind: FnKind<'a>, - fn_decl: &'a ast::FnDecl, - span: Span, - _node_id: NodeId, - ) { + fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) { if let Some(header) = fn_kind.header() { - // Stability of const fn methods are covered in - // `visit_trait_item` and `visit_impl_item` below; this is - // because default methods don't pass through this point. + // Stability of const fn methods are covered in `visit_assoc_item` below. self.check_extern(header.ext); } - if fn_decl.c_variadic() { + if fn_kind.ctxt() != Some(FnCtxt::Foreign) && fn_kind.decl().c_variadic() { gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable"); } - visit::walk_fn(self, fn_kind, fn_decl, span) + visit::walk_fn(self, fn_kind, span) } fn visit_generic_param(&mut self, param: &'a GenericParam) { @@ -539,56 +531,35 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { visit::walk_assoc_ty_constraint(self, constraint) } - fn visit_trait_item(&mut self, ti: &'a ast::AssocItem) { - match ti.kind { - ast::AssocItemKind::Fn(ref sig, ref block) => { - if block.is_none() { - self.check_extern(sig.header.ext); - } - if sig.header.constness.node == ast::Constness::Const { - gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable"); + fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) { + if i.defaultness == ast::Defaultness::Default { + gate_feature_post!(&self, specialization, i.span, "specialization is unstable"); + } + + match i.kind { + ast::AssocItemKind::Fn(ref sig, _) => { + let constness = sig.header.constness.node; + if let (ast::Constness::Const, AssocCtxt::Trait) = (constness, ctxt) { + gate_feature_post!(&self, const_fn, i.span, "const fn is unstable"); } } - ast::AssocItemKind::TyAlias(_, ref default) => { - if let Some(_) = default { + ast::AssocItemKind::TyAlias(_, ref ty) => { + if let (Some(_), AssocCtxt::Trait) = (ty, ctxt) { gate_feature_post!( &self, associated_type_defaults, - ti.span, + i.span, "associated type defaults are unstable" ); } - } - _ => {} - } - visit::walk_trait_item(self, ti) - } - - fn visit_assoc_item(&mut self, ii: &'a ast::AssocItem) { - if ii.defaultness == ast::Defaultness::Default { - gate_feature_post!(&self, specialization, ii.span, "specialization is unstable"); - } - - match ii.kind { - ast::AssocItemKind::Fn(ref sig, _) => { - if sig.decl.c_variadic() { - gate_feature_post!( - &self, - c_variadic, - ii.span, - "C-variadic functions are unstable" - ); - } - } - ast::AssocItemKind::TyAlias(_, ref ty) => { if let Some(ty) = ty { self.check_impl_trait(ty); } - self.check_gat(&ii.generics, ii.span); + self.check_gat(&i.generics, i.span); } _ => {} } - visit::walk_assoc_item(self, ii) + visit::walk_assoc_item(self, i, ctxt) } fn visit_vis(&mut self, vis: &'a ast::Visibility) { diff --git a/src/librustc_ast_passes/node_count.rs b/src/librustc_ast_passes/node_count.rs index 9fe7238fcfc..ed1ccdf6a76 100644 --- a/src/librustc_ast_passes/node_count.rs +++ b/src/librustc_ast_passes/node_count.rs @@ -67,13 +67,13 @@ impl<'ast> Visitor<'ast> for NodeCounter { self.count += 1; walk_generics(self, g) } - fn visit_fn(&mut self, fk: FnKind<'_>, fd: &FnDecl, s: Span, _: NodeId) { + fn visit_fn(&mut self, fk: FnKind<'_>, s: Span, _: NodeId) { self.count += 1; - walk_fn(self, fk, fd, s) + walk_fn(self, fk, s) } - fn visit_assoc_item(&mut self, ti: &AssocItem) { + fn visit_assoc_item(&mut self, ti: &AssocItem, ctxt: AssocCtxt) { self.count += 1; - walk_assoc_item(self, ti) + walk_assoc_item(self, ti, ctxt); } fn visit_trait_ref(&mut self, t: &TraitRef) { self.count += 1; diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index 3cc67a7c821..d9077d1606f 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -1020,18 +1020,8 @@ impl<'a> State<'a> { self.maybe_print_comment(item.span.lo()); self.print_outer_attributes(&item.attrs); match item.kind { - ast::ForeignItemKind::Fn(ref decl, ref generics) => { - self.head(""); - self.print_fn( - decl, - ast::FnHeader::default(), - Some(item.ident), - generics, - &item.vis, - ); - self.end(); // end head-ibox - self.s.word(";"); - self.end(); // end the outer fn box + ast::ForeignItemKind::Fn(ref sig, ref gen, ref body) => { + self.print_fn_full(sig, item.ident, gen, &item.vis, body.as_deref(), &item.attrs); } ast::ForeignItemKind::Static(ref t, m) => { self.head(visibility_qualified(&item.vis, "static")); @@ -1154,11 +1144,8 @@ impl<'a> State<'a> { self.s.word(";"); self.end(); // end the outer cbox } - ast::ItemKind::Fn(ref sig, ref param_names, ref body) => { - self.head(""); - self.print_fn(&sig.decl, sig.header, Some(item.ident), param_names, &item.vis); - self.s.word(" "); - self.print_block_with_attrs(body, &item.attrs); + ast::ItemKind::Fn(ref sig, ref gen, ref body) => { + self.print_fn_full(sig, item.ident, gen, &item.vis, body.as_deref(), &item.attrs); } ast::ItemKind::Mod(ref _mod) => { self.head(visibility_qualified(&item.vis, "mod")); @@ -1483,16 +1470,8 @@ impl<'a> State<'a> { self.print_associated_const(item.ident, ty, expr.as_deref(), &item.vis); } ast::AssocItemKind::Fn(sig, body) => { - if body.is_some() { - self.head(""); - } - self.print_fn(&sig.decl, sig.header, Some(item.ident), &item.generics, &item.vis); - if let Some(body) = body { - self.nbsp(); - self.print_block_with_attrs(body, &item.attrs); - } else { - self.s.word(";"); - } + let body = body.as_deref(); + self.print_fn_full(sig, item.ident, &item.generics, &item.vis, body, &item.attrs); } ast::AssocItemKind::TyAlias(bounds, ty) => { self.print_associated_type(item.ident, bounds, ty.as_deref()); @@ -2412,6 +2391,27 @@ impl<'a> State<'a> { } } + fn print_fn_full( + &mut self, + sig: &ast::FnSig, + name: ast::Ident, + generics: &ast::Generics, + vis: &ast::Visibility, + body: Option<&ast::Block>, + attrs: &[ast::Attribute], + ) { + if body.is_some() { + self.head(""); + } + self.print_fn(&sig.decl, sig.header, Some(name), generics, vis); + if let Some(body) = body { + self.nbsp(); + self.print_block_with_attrs(body, attrs); + } else { + self.s.word(";"); + } + } + crate fn print_fn( &mut self, decl: &ast::FnDecl, @@ -2698,13 +2698,9 @@ impl<'a> State<'a> { where_clause: ast::WhereClause { predicates: Vec::new(), span: rustc_span::DUMMY_SP }, span: rustc_span::DUMMY_SP, }; - self.print_fn( - decl, - ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() }, - name, - &generics, - &dummy_spanned(ast::VisibilityKind::Inherited), - ); + let header = ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() }; + let vis = dummy_spanned(ast::VisibilityKind::Inherited); + self.print_fn(decl, header, name, &generics, &vis); self.end(); } diff --git a/src/librustc_builtin_macros/global_allocator.rs b/src/librustc_builtin_macros/global_allocator.rs index 957d34b7d89..ec0d55b38a7 100644 --- a/src/librustc_builtin_macros/global_allocator.rs +++ b/src/librustc_builtin_macros/global_allocator.rs @@ -66,7 +66,7 @@ impl AllocFnFactory<'_, '_> { let decl = self.cx.fn_decl(abi_args, ast::FunctionRetTy::Ty(output_ty)); let header = FnHeader { unsafety: Unsafety::Unsafe, ..FnHeader::default() }; let sig = FnSig { decl, header }; - let kind = ItemKind::Fn(sig, Generics::default(), self.cx.block_expr(output_expr)); + let kind = ItemKind::Fn(sig, Generics::default(), Some(self.cx.block_expr(output_expr))); let item = self.cx.item( self.span, self.cx.ident_of(&self.kind.fn_name(method.name), self.span), diff --git a/src/librustc_builtin_macros/log_syntax.rs b/src/librustc_builtin_macros/log_syntax.rs index 6d9bfbfd05f..ac7ba49ba18 100644 --- a/src/librustc_builtin_macros/log_syntax.rs +++ b/src/librustc_builtin_macros/log_syntax.rs @@ -1,6 +1,5 @@ use rustc_ast_pretty::pprust; use rustc_expand::base; -use rustc_span; use syntax::tokenstream::TokenStream; pub fn expand_log_syntax<'cx>( diff --git a/src/librustc_builtin_macros/test_harness.rs b/src/librustc_builtin_macros/test_harness.rs index 6a73f121c99..70f1c0e4e2d 100644 --- a/src/librustc_builtin_macros/test_harness.rs +++ b/src/librustc_builtin_macros/test_harness.rs @@ -307,7 +307,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> { let decl = ecx.fn_decl(vec![], ast::FunctionRetTy::Ty(main_ret_ty)); let sig = ast::FnSig { decl, header: ast::FnHeader::default() }; - let main = ast::ItemKind::Fn(sig, ast::Generics::default(), main_body); + let main = ast::ItemKind::Fn(sig, ast::Generics::default(), Some(main_body)); // Honor the reexport_test_harness_main attribute let main_id = match cx.reexport_test_harness_main { diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index 3a14fa5ae31..4f05aac0898 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -968,7 +968,78 @@ pub fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLibrary } } +// Because windows-gnu target is meant to be self-contained for pure Rust code it bundles +// own mingw-w64 libraries. These libraries are usually not compatible with mingw-w64 +// installed in the system. This breaks many cases where Rust is mixed with other languages +// (e.g. *-sys crates). +// We prefer system mingw-w64 libraries if they are available to avoid this issue. +fn get_crt_libs_path(sess: &Session) -> Option<PathBuf> { + fn find_exe_in_path<P>(exe_name: P) -> Option<PathBuf> + where + P: AsRef<Path>, + { + for dir in env::split_paths(&env::var_os("PATH")?) { + let full_path = dir.join(&exe_name); + if full_path.is_file() { + return Some(fix_windows_verbatim_for_gcc(&full_path)); + } + } + None + } + + fn probe(sess: &Session) -> Option<PathBuf> { + if let (linker, LinkerFlavor::Gcc) = linker_and_flavor(&sess) { + let linker_path = if cfg!(windows) && linker.extension().is_none() { + linker.with_extension("exe") + } else { + linker + }; + if let Some(linker_path) = find_exe_in_path(linker_path) { + let mingw_arch = match &sess.target.target.arch { + x if x == "x86" => "i686", + x => x, + }; + let mingw_dir = format!("{}-w64-mingw32", mingw_arch); + // Here we have path/bin/gcc but we need path/ + let mut path = linker_path; + path.pop(); + path.pop(); + // Based on Clang MinGW driver + let probe_path = path.join(&mingw_dir).join("lib"); + if probe_path.exists() { + return Some(probe_path); + }; + let probe_path = path.join(&mingw_dir).join("sys-root/mingw/lib"); + if probe_path.exists() { + return Some(probe_path); + }; + }; + }; + None + } + + let mut system_library_path = sess.system_library_path.borrow_mut(); + match &*system_library_path { + Some(Some(compiler_libs_path)) => Some(compiler_libs_path.clone()), + Some(None) => None, + None => { + let path = probe(sess); + *system_library_path = Some(path.clone()); + path + } + } +} + pub fn get_file_path(sess: &Session, name: &str) -> PathBuf { + // prefer system {,dll}crt2.o libs, see get_crt_libs_path comment for more details + if sess.target.target.llvm_target.contains("windows-gnu") { + if let Some(compiler_libs_path) = get_crt_libs_path(sess) { + let file_path = compiler_libs_path.join(name); + if file_path.exists() { + return file_path; + } + } + } let fs = sess.target_filesearch(PathKind::Native); let file_path = fs.get_lib_path().join(name); if file_path.exists() { @@ -1150,6 +1221,13 @@ fn link_args<'a, B: ArchiveBuilder<'a>>( // target descriptor let t = &sess.target.target; + // prefer system mingw-w64 libs, see get_crt_libs_path comment for more details + if cfg!(windows) && sess.target.target.llvm_target.contains("windows-gnu") { + if let Some(compiler_libs_path) = get_crt_libs_path(sess) { + cmd.include_path(&compiler_libs_path); + } + } + cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path)); for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) { diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index 974d9dcfae4..0384776e9fb 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -74,7 +74,7 @@ use crate::fx::{FxHashMap, FxHashSet}; -use std::cell::{Cell, RefCell}; +use std::cell::Cell; use std::collections::hash_map::Entry; use std::fmt::Debug; use std::hash; @@ -146,7 +146,7 @@ pub struct ObligationForest<O: ForestObligation> { active_cache: FxHashMap<O::Predicate, usize>, /// A vector reused in compress(), to avoid allocating new vectors. - node_rewrites: RefCell<Vec<usize>>, + node_rewrites: Vec<usize>, obligation_tree_id_generator: ObligationTreeIdGenerator, @@ -285,7 +285,7 @@ impl<O: ForestObligation> ObligationForest<O> { nodes: vec![], done_cache: Default::default(), active_cache: Default::default(), - node_rewrites: RefCell::new(vec![]), + node_rewrites: vec![], obligation_tree_id_generator: (0..).map(ObligationTreeId), error_cache: Default::default(), } @@ -590,7 +590,7 @@ impl<O: ForestObligation> ObligationForest<O> { #[inline(never)] fn compress(&mut self, do_completed: DoCompleted) -> Option<Vec<O>> { let orig_nodes_len = self.nodes.len(); - let mut node_rewrites: Vec<_> = self.node_rewrites.replace(vec![]); + let mut node_rewrites: Vec<_> = std::mem::take(&mut self.node_rewrites); debug_assert!(node_rewrites.is_empty()); node_rewrites.extend(0..orig_nodes_len); let mut dead_nodes = 0; @@ -651,7 +651,7 @@ impl<O: ForestObligation> ObligationForest<O> { } node_rewrites.truncate(0); - self.node_rewrites.replace(node_rewrites); + self.node_rewrites = node_rewrites; if do_completed == DoCompleted::Yes { Some(removed_done_obligations) } else { None } } diff --git a/src/librustc_error_codes/error_codes/E0264.md b/src/librustc_error_codes/error_codes/E0264.md index e1e7516cec2..708eac8837a 100644 --- a/src/librustc_error_codes/error_codes/E0264.md +++ b/src/librustc_error_codes/error_codes/E0264.md @@ -1,4 +1,6 @@ -An unknown external lang item was used. Erroneous code example: +An unknown external lang item was used. + +Erroneous code example: ```compile_fail,E0264 #![feature(lang_items)] diff --git a/src/librustc_error_codes/error_codes/E0267.md b/src/librustc_error_codes/error_codes/E0267.md index 066ebee0ffb..951490df874 100644 --- a/src/librustc_error_codes/error_codes/E0267.md +++ b/src/librustc_error_codes/error_codes/E0267.md @@ -1,5 +1,7 @@ -This error indicates the use of a loop keyword (`break` or `continue`) inside a -closure but outside of any loop. Erroneous code example: +A loop keyword (`break` or `continue`) was used inside a closure but outside of +any loop. + +Erroneous code example: ```compile_fail,E0267 let w = || { break; }; // error: `break` inside of a closure diff --git a/src/librustc_error_codes/error_codes/E0268.md b/src/librustc_error_codes/error_codes/E0268.md index 7f3ac118601..436aef79fe0 100644 --- a/src/librustc_error_codes/error_codes/E0268.md +++ b/src/librustc_error_codes/error_codes/E0268.md @@ -1,6 +1,6 @@ -This error indicates the use of a loop keyword (`break` or `continue`) outside -of a loop. Without a loop to break out of or continue in, no sensible action can -be taken. Erroneous code example: +A loop keyword (`break` or `continue`) was used outside of a loop. + +Erroneous code example: ```compile_fail,E0268 fn some_func() { @@ -8,6 +8,7 @@ fn some_func() { } ``` +Without a loop to break out of or continue in, no sensible action can be taken. Please verify that you are using `break` and `continue` only in loops. Example: ``` diff --git a/src/librustc_error_codes/error_codes/E0454.md b/src/librustc_error_codes/error_codes/E0454.md index d3314885081..80eb91e43d1 100644 --- a/src/librustc_error_codes/error_codes/E0454.md +++ b/src/librustc_error_codes/error_codes/E0454.md @@ -1,6 +1,6 @@ A link name was given with an empty name. Erroneous code example: -```ignore (cannot-test-this-because-rustdoc-stops-compile-fail-before-codegen) +```compile_fail,E0454 #[link(name = "")] extern {} // error: `#[link(name = "")]` given with empty name ``` diff --git a/src/librustc_error_codes/error_codes/E0458.md b/src/librustc_error_codes/error_codes/E0458.md index 385079d403d..5996f190b34 100644 --- a/src/librustc_error_codes/error_codes/E0458.md +++ b/src/librustc_error_codes/error_codes/E0458.md @@ -1,6 +1,6 @@ An unknown "kind" was specified for a link attribute. Erroneous code example: -```ignore (cannot-test-this-because-rustdoc-stops-compile-fail-before-codegen) +```compile_fail,E0458 #[link(kind = "wonderful_unicorn")] extern {} // error: unknown kind: `wonderful_unicorn` ``` diff --git a/src/librustc_error_codes/error_codes/E0459.md b/src/librustc_error_codes/error_codes/E0459.md index 663bc322ee6..580cbf1e1c6 100644 --- a/src/librustc_error_codes/error_codes/E0459.md +++ b/src/librustc_error_codes/error_codes/E0459.md @@ -1,6 +1,6 @@ A link was used without a name parameter. Erroneous code example: -```ignore (cannot-test-this-because-rustdoc-stops-compile-fail-before-codegen) +```compile_fail,E0459 #[link(kind = "dylib")] extern {} // error: `#[link(...)]` specified without `name = "foo"` ``` diff --git a/src/librustc_expand/base.rs b/src/librustc_expand/base.rs index 536259e0547..e167089b93a 100644 --- a/src/librustc_expand/base.rs +++ b/src/librustc_expand/base.rs @@ -17,7 +17,7 @@ use syntax::mut_visit::{self, MutVisitor}; use syntax::ptr::P; use syntax::token; use syntax::tokenstream::{self, TokenStream}; -use syntax::visit::Visitor; +use syntax::visit::{AssocCtxt, Visitor}; use std::default::Default; use std::iter; @@ -103,8 +103,8 @@ impl Annotatable { pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) { match self { Annotatable::Item(item) => visitor.visit_item(item), - Annotatable::TraitItem(trait_item) => visitor.visit_trait_item(trait_item), - Annotatable::ImplItem(impl_item) => visitor.visit_impl_item(impl_item), + Annotatable::TraitItem(item) => visitor.visit_assoc_item(item, AssocCtxt::Trait), + Annotatable::ImplItem(item) => visitor.visit_assoc_item(item, AssocCtxt::Impl), Annotatable::ForeignItem(foreign_item) => visitor.visit_foreign_item(foreign_item), Annotatable::Stmt(stmt) => visitor.visit_stmt(stmt), Annotatable::Expr(expr) => visitor.visit_expr(expr), diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index f08bed57315..90692fe1ec9 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -25,7 +25,7 @@ use syntax::ptr::P; use syntax::token; use syntax::tokenstream::{TokenStream, TokenTree}; use syntax::util::map_in_place::MapInPlace; -use syntax::visit::{self, Visitor}; +use syntax::visit::{self, AssocCtxt, Visitor}; use smallvec::{smallvec, SmallVec}; use std::io::ErrorKind; @@ -39,7 +39,7 @@ macro_rules! ast_fragments { $($Kind:ident($AstTy:ty) { $kind_name:expr; $(one fn $mut_visit_ast:ident; fn $visit_ast:ident;)? - $(many fn $flat_map_ast_elt:ident; fn $visit_ast_elt:ident;)? + $(many fn $flat_map_ast_elt:ident; fn $visit_ast_elt:ident($($args:tt)*);)? fn $make_ast:ident; })* ) => { @@ -127,7 +127,7 @@ macro_rules! ast_fragments { AstFragment::OptExpr(None) => {} $($(AstFragment::$Kind(ref ast) => visitor.$visit_ast(ast),)?)* $($(AstFragment::$Kind(ref ast) => for ast_elt in &ast[..] { - visitor.$visit_ast_elt(ast_elt); + visitor.$visit_ast_elt(ast_elt, $($args)*); })?)* } } @@ -147,52 +147,58 @@ ast_fragments! { Pat(P<ast::Pat>) { "pattern"; one fn visit_pat; fn visit_pat; fn make_pat; } Ty(P<ast::Ty>) { "type"; one fn visit_ty; fn visit_ty; fn make_ty; } Stmts(SmallVec<[ast::Stmt; 1]>) { - "statement"; many fn flat_map_stmt; fn visit_stmt; fn make_stmts; + "statement"; many fn flat_map_stmt; fn visit_stmt(); fn make_stmts; } Items(SmallVec<[P<ast::Item>; 1]>) { - "item"; many fn flat_map_item; fn visit_item; fn make_items; + "item"; many fn flat_map_item; fn visit_item(); fn make_items; } TraitItems(SmallVec<[P<ast::AssocItem>; 1]>) { - "trait item"; many fn flat_map_trait_item; fn visit_trait_item; fn make_trait_items; + "trait item"; + many fn flat_map_trait_item; + fn visit_assoc_item(AssocCtxt::Trait); + fn make_trait_items; } ImplItems(SmallVec<[P<ast::AssocItem>; 1]>) { - "impl item"; many fn flat_map_impl_item; fn visit_impl_item; fn make_impl_items; + "impl item"; + many fn flat_map_impl_item; + fn visit_assoc_item(AssocCtxt::Impl); + fn make_impl_items; } ForeignItems(SmallVec<[P<ast::ForeignItem>; 1]>) { "foreign item"; many fn flat_map_foreign_item; - fn visit_foreign_item; + fn visit_foreign_item(); fn make_foreign_items; } Arms(SmallVec<[ast::Arm; 1]>) { - "match arm"; many fn flat_map_arm; fn visit_arm; fn make_arms; + "match arm"; many fn flat_map_arm; fn visit_arm(); fn make_arms; } Fields(SmallVec<[ast::Field; 1]>) { - "field expression"; many fn flat_map_field; fn visit_field; fn make_fields; + "field expression"; many fn flat_map_field; fn visit_field(); fn make_fields; } FieldPats(SmallVec<[ast::FieldPat; 1]>) { "field pattern"; many fn flat_map_field_pattern; - fn visit_field_pattern; + fn visit_field_pattern(); fn make_field_patterns; } GenericParams(SmallVec<[ast::GenericParam; 1]>) { "generic parameter"; many fn flat_map_generic_param; - fn visit_generic_param; + fn visit_generic_param(); fn make_generic_params; } Params(SmallVec<[ast::Param; 1]>) { - "function parameter"; many fn flat_map_param; fn visit_param; fn make_params; + "function parameter"; many fn flat_map_param; fn visit_param(); fn make_params; } StructFields(SmallVec<[ast::StructField; 1]>) { "field"; many fn flat_map_struct_field; - fn visit_struct_field; + fn visit_struct_field(); fn make_struct_fields; } Variants(SmallVec<[ast::Variant; 1]>) { - "variant"; many fn flat_map_variant; fn visit_variant; fn make_variants; + "variant"; many fn flat_map_variant; fn visit_variant(); fn make_variants; } } @@ -363,7 +369,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> { krate.attrs = vec![]; krate.module = ast::Mod { inner: orig_mod_span, items: vec![], inline: true }; } - _ => unreachable!(), + Some(ast::Item { span, kind, .. }) => { + krate.attrs = vec![]; + krate.module = ast::Mod { inner: orig_mod_span, items: vec![], inline: true }; + self.cx.span_err( + span, + &format!( + "expected crate top-level item to be a module after macro expansion, found a {}", + kind.descriptive_variant() + ), + ); + } }; self.cx.trace_macros_diag(); krate @@ -599,8 +615,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { &format!("recursion limit reached while expanding `{}`", expn_data.kind.descr()), ); err.help(&format!( - "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", - suggested_limit + "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)", + suggested_limit, self.cx.ecfg.crate_name, )); err.emit(); self.cx.trace_macros_diag(); @@ -851,7 +867,7 @@ pub fn parse_ast_fragment<'a>( AstFragmentKind::ForeignItems => { let mut items = SmallVec::new(); while this.token != token::Eof { - items.push(this.parse_foreign_item(DUMMY_SP)?); + items.push(this.parse_foreign_item()?); } AstFragment::ForeignItems(items) } diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index 0252d88e738..4ae79f9ccaa 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -344,9 +344,6 @@ declare_features! ( /// Allows `extern "x86-interrupt" fn()`. (active, abi_x86_interrupt, "1.17.0", Some(40180), None), - /// Allows overlapping impls of marker traits. - (active, overlapping_marker_traits, "1.18.0", Some(29864), None), - /// Allows a test to fail without failing the whole suite. (active, allow_fail, "1.19.0", Some(46488), None), diff --git a/src/librustc_feature/removed.rs b/src/librustc_feature/removed.rs index d5b6fe81c7b..e6ea093fe89 100644 --- a/src/librustc_feature/removed.rs +++ b/src/librustc_feature/removed.rs @@ -108,7 +108,9 @@ declare_features! ( /// Allows using `#[on_unimplemented(..)]` on traits. /// (Moved to `rustc_attrs`.) (removed, on_unimplemented, "1.40.0", None, None, None), - + /// Allows overlapping impls of marker traits. + (removed, overlapping_marker_traits, "1.42.0", Some(29864), None, + Some("removed in favor of `#![feature(marker_trait_attr)]`")), // ------------------------------------------------------------------------- // feature-group-end: removed features // ------------------------------------------------------------------------- diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index 3ed0ad16eeb..0c93a192667 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -2260,10 +2260,10 @@ impl TraitRef<'_> { #[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] pub struct PolyTraitRef<'hir> { - /// The `'a` in `<'a> Foo<&'a T>`. + /// The `'a` in `for<'a> Foo<&'a T>`. pub bound_generic_params: &'hir [GenericParam<'hir>], - /// The `Foo<&'a T>` in `<'a> Foo<&'a T>`. + /// The `Foo<&'a T>` in `for<'a> Foo<&'a T>`. pub trait_ref: TraitRef<'hir>, pub span: Span, diff --git a/src/librustc_hir/stable_hash_impls.rs b/src/librustc_hir/stable_hash_impls.rs index 696a350ebdd..294074cd3e5 100644 --- a/src/librustc_hir/stable_hash_impls.rs +++ b/src/librustc_hir/stable_hash_impls.rs @@ -11,9 +11,7 @@ pub trait HashStableContext: syntax::HashStableContext + rustc_target::HashStabl fn hash_def_id(&mut self, _: DefId, hasher: &mut StableHasher); fn hash_hir_id(&mut self, _: HirId, hasher: &mut StableHasher); fn hash_body_id(&mut self, _: BodyId, hasher: &mut StableHasher); - fn hash_item_id(&mut self, _: ItemId, hasher: &mut StableHasher); - fn hash_impl_item_id(&mut self, _: ImplItemId, hasher: &mut StableHasher); - fn hash_trait_item_id(&mut self, _: TraitItemId, hasher: &mut StableHasher); + fn hash_reference_to_item(&mut self, _: HirId, hasher: &mut StableHasher); fn hash_hir_mod(&mut self, _: &Mod<'_>, hasher: &mut StableHasher); fn hash_hir_expr(&mut self, _: &Expr<'_>, hasher: &mut StableHasher); fn hash_hir_ty(&mut self, _: &Ty<'_>, hasher: &mut StableHasher); @@ -38,21 +36,28 @@ impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for BodyId { } } +// The following implementations of HashStable for `ItemId`, `TraitItemId`, and +// `ImplItemId` deserve special attention. Normally we do not hash `NodeId`s within +// the HIR, since they just signify a HIR nodes own path. But `ItemId` et al +// are used when another item in the HIR is *referenced* and we certainly +// want to pick up on a reference changing its target, so we hash the NodeIds +// in "DefPath Mode". + impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for ItemId { fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { - hcx.hash_item_id(*self, hasher) + hcx.hash_reference_to_item(self.id, hasher) } } impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for ImplItemId { fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { - hcx.hash_impl_item_id(*self, hasher) + hcx.hash_reference_to_item(self.hir_id, hasher) } } impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for TraitItemId { fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { - hcx.hash_trait_item_id(*self, hasher) + hcx.hash_reference_to_item(self.hir_id, hasher) } } diff --git a/src/librustc_incremental/persist/file_format.rs b/src/librustc_incremental/persist/file_format.rs index 7534b7e9ef4..5c72b049d97 100644 --- a/src/librustc_incremental/persist/file_format.rs +++ b/src/librustc_incremental/persist/file_format.rs @@ -90,8 +90,7 @@ pub fn read_file( let mut rustc_version_str_len = [0u8; 1]; file.read_exact(&mut rustc_version_str_len)?; let rustc_version_str_len = rustc_version_str_len[0] as usize; - let mut buffer = Vec::with_capacity(rustc_version_str_len); - buffer.resize(rustc_version_str_len, 0); + let mut buffer = vec![0; rustc_version_str_len]; file.read_exact(&mut buffer)?; if buffer != rustc_version().as_bytes() { diff --git a/src/librustc_interface/callbacks.rs b/src/librustc_interface/callbacks.rs index eb9c118bb01..803e8958572 100644 --- a/src/librustc_interface/callbacks.rs +++ b/src/librustc_interface/callbacks.rs @@ -11,7 +11,6 @@ use rustc::ty::tls; use rustc_errors::{Diagnostic, TRACK_DIAGNOSTICS}; -use rustc_span; use std::fmt; /// This is a callback from libsyntax as it cannot access the implicit state diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 0be73e55e9c..bf8bcd71efa 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -17,7 +17,6 @@ use rustc::traits; use rustc::ty::steal::Steal; use rustc::ty::{self, GlobalCtxt, ResolverOutputs, TyCtxt}; use rustc::util::common::ErrorReported; -use rustc_builtin_macros; use rustc_codegen_ssa::back::link::emit_metadata; use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc_codegen_utils::link::filename_for_metadata; @@ -26,18 +25,15 @@ use rustc_data_structures::{box_region_allow_access, declare_box_region_type, pa use rustc_errors::PResult; use rustc_expand::base::ExtCtxt; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; -use rustc_incremental; use rustc_lint::LintStore; use rustc_mir as mir; use rustc_mir_build as mir_build; use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str}; use rustc_passes::{self, hir_stats, layout_test}; use rustc_plugin_impl as plugin; -use rustc_privacy; use rustc_resolve::{Resolver, ResolverArenas}; use rustc_span::symbol::Symbol; use rustc_span::FileName; -use rustc_traits; use rustc_typeck as typeck; use syntax::mut_visit::MutVisitor; use syntax::{self, ast, visit}; diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 154b1608dcc..ca66717ac5e 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -43,7 +43,7 @@ use rustc_span::{BytePos, Span}; use syntax::ast::{self, Expr}; use syntax::attr::{self, HasAttrs}; use syntax::tokenstream::{TokenStream, TokenTree}; -use syntax::visit::FnKind; +use syntax::visit::{FnCtxt, FnKind}; use crate::nonstandard_style::{method_context, MethodLateContext}; @@ -259,34 +259,22 @@ impl EarlyLintPass for UnsafeCode { } } - fn check_fn( - &mut self, - cx: &EarlyContext<'_>, - fk: FnKind<'_>, - _: &ast::FnDecl, - span: Span, - _: ast::NodeId, - ) { - match fk { - FnKind::ItemFn(_, ast::FnHeader { unsafety: ast::Unsafety::Unsafe, .. }, ..) => { - self.report_unsafe(cx, span, "declaration of an `unsafe` function") - } - - FnKind::Method(_, sig, ..) => { - if sig.header.unsafety == ast::Unsafety::Unsafe { - self.report_unsafe(cx, span, "implementation of an `unsafe` method") - } - } - - _ => (), - } - } - - fn check_trait_item(&mut self, cx: &EarlyContext<'_>, item: &ast::AssocItem) { - if let ast::AssocItemKind::Fn(ref sig, None) = item.kind { - if sig.header.unsafety == ast::Unsafety::Unsafe { - self.report_unsafe(cx, item.span, "declaration of an `unsafe` method") - } + fn check_fn(&mut self, cx: &EarlyContext<'_>, fk: FnKind<'_>, span: Span, _: ast::NodeId) { + if let FnKind::Fn( + ctxt, + _, + ast::FnSig { header: ast::FnHeader { unsafety: ast::Unsafety::Unsafe, .. }, .. }, + _, + body, + ) = fk + { + let msg = match ctxt { + FnCtxt::Foreign => return, + FnCtxt::Free => "declaration of an `unsafe` function", + FnCtxt::Assoc(_) if body.is_none() => "declaration of an `unsafe` method", + FnCtxt::Assoc(_) => "implementation of an `unsafe` method", + }; + self.report_unsafe(cx, span, msg); } } } diff --git a/src/librustc_lint/early.rs b/src/librustc_lint/early.rs index 490114b2d4d..542cbea0c95 100644 --- a/src/librustc_lint/early.rs +++ b/src/librustc_lint/early.rs @@ -116,17 +116,11 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> ast_visit::walk_stmt(self, s); } - fn visit_fn( - &mut self, - fk: ast_visit::FnKind<'a>, - decl: &'a ast::FnDecl, - span: Span, - id: ast::NodeId, - ) { - run_early_pass!(self, check_fn, fk, decl, span, id); + fn visit_fn(&mut self, fk: ast_visit::FnKind<'a>, span: Span, id: ast::NodeId) { + run_early_pass!(self, check_fn, fk, span, id); self.check_id(id); - ast_visit::walk_fn(self, fk, decl, span); - run_early_pass!(self, check_fn_post, fk, decl, span, id); + ast_visit::walk_fn(self, fk, span); + run_early_pass!(self, check_fn_post, fk, span, id); } fn visit_variant_data(&mut self, s: &'a ast::VariantData) { @@ -213,19 +207,18 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> ast_visit::walk_poly_trait_ref(self, t, m); } - fn visit_trait_item(&mut self, trait_item: &'a ast::AssocItem) { - self.with_lint_attrs(trait_item.id, &trait_item.attrs, |cx| { - run_early_pass!(cx, check_trait_item, trait_item); - ast_visit::walk_trait_item(cx, trait_item); - run_early_pass!(cx, check_trait_item_post, trait_item); - }); - } - - fn visit_impl_item(&mut self, impl_item: &'a ast::AssocItem) { - self.with_lint_attrs(impl_item.id, &impl_item.attrs, |cx| { - run_early_pass!(cx, check_impl_item, impl_item); - ast_visit::walk_impl_item(cx, impl_item); - run_early_pass!(cx, check_impl_item_post, impl_item); + fn visit_assoc_item(&mut self, item: &'a ast::AssocItem, ctxt: ast_visit::AssocCtxt) { + self.with_lint_attrs(item.id, &item.attrs, |cx| match ctxt { + ast_visit::AssocCtxt::Trait => { + run_early_pass!(cx, check_trait_item, item); + ast_visit::walk_assoc_item(cx, item, ctxt); + run_early_pass!(cx, check_trait_item_post, item); + } + ast_visit::AssocCtxt::Impl => { + run_early_pass!(cx, check_impl_item, item); + ast_visit::walk_assoc_item(cx, item, ctxt); + run_early_pass!(cx, check_impl_item_post, item); + } }); } diff --git a/src/librustc_lint/passes.rs b/src/librustc_lint/passes.rs index 7e5d670767a..36de625cafa 100644 --- a/src/librustc_lint/passes.rs +++ b/src/librustc_lint/passes.rs @@ -179,10 +179,9 @@ macro_rules! early_lint_methods { fn check_where_predicate(a: &ast::WherePredicate); fn check_poly_trait_ref(a: &ast::PolyTraitRef, b: &ast::TraitBoundModifier); - fn check_fn(a: syntax::visit::FnKind<'_>, b: &ast::FnDecl, c: Span, d_: ast::NodeId); + fn check_fn(a: syntax::visit::FnKind<'_>, c: Span, d_: ast::NodeId); fn check_fn_post( a: syntax::visit::FnKind<'_>, - b: &ast::FnDecl, c: Span, d: ast::NodeId ); diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 272c4f29203..5490e5e2b4d 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -587,6 +587,14 @@ impl EarlyLintPass for UnusedParens { } } } + + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { + use ast::ItemKind::*; + + if let Const(.., ref expr) | Static(.., ref expr) = item.kind { + self.check_unused_parens_expr(cx, expr, "assigned value", false, None, None); + } + } } declare_lint! { diff --git a/src/librustc_macros/src/lift.rs b/src/librustc_macros/src/lift.rs index 1b91fc5018a..a246b34b2c2 100644 --- a/src/librustc_macros/src/lift.rs +++ b/src/librustc_macros/src/lift.rs @@ -1,7 +1,5 @@ -use proc_macro2; use quote::quote; use syn::{self, parse_quote}; -use synstructure; pub fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { s.add_bounds(synstructure::AddBounds::Generics); diff --git a/src/librustc_macros/src/query.rs b/src/librustc_macros/src/query.rs index f680b0d64cd..6dc4f7f2515 100644 --- a/src/librustc_macros/src/query.rs +++ b/src/librustc_macros/src/query.rs @@ -2,7 +2,6 @@ use itertools::Itertools; use proc_macro::TokenStream; use proc_macro2::{Delimiter, TokenTree}; use quote::quote; -use syn; use syn::parse::{Parse, ParseStream, Result}; use syn::punctuated::Punctuated; use syn::spanned::Spanned; diff --git a/src/librustc_macros/src/symbols.rs b/src/librustc_macros/src/symbols.rs index c692c7f3995..feddcd5f994 100644 --- a/src/librustc_macros/src/symbols.rs +++ b/src/librustc_macros/src/symbols.rs @@ -1,7 +1,6 @@ use proc_macro::TokenStream; use quote::quote; use std::collections::HashSet; -use syn; use syn::parse::{Parse, ParseStream, Result}; use syn::{braced, parse_macro_input, Ident, LitStr, Token}; diff --git a/src/librustc_macros/src/type_foldable.rs b/src/librustc_macros/src/type_foldable.rs index 3d58984a900..687401e3344 100644 --- a/src/librustc_macros/src/type_foldable.rs +++ b/src/librustc_macros/src/type_foldable.rs @@ -1,6 +1,4 @@ use quote::quote; -use syn; -use synstructure; pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { if let syn::Data::Union(_) = s.ast().data { diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs index b0b9790abb1..b49e7b7f0d9 100644 --- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs @@ -397,14 +397,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { (BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => { first_borrow_desc = "first "; - self.cannot_mutably_borrow_multiply( + let mut err = self.cannot_mutably_borrow_multiply( span, &desc_place, &msg_place, issued_span, &msg_borrow, None, - ) + ); + self.suggest_split_at_mut_if_applicable( + &mut err, + &place, + &issued_borrow.borrowed_place, + ); + err } (BorrowKind::Unique, BorrowKind::Unique) => { @@ -549,6 +555,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err } + fn suggest_split_at_mut_if_applicable( + &self, + err: &mut DiagnosticBuilder<'_>, + place: &Place<'tcx>, + borrowed_place: &Place<'tcx>, + ) { + match (&place.projection[..], &borrowed_place.projection[..]) { + ([ProjectionElem::Index(_)], [ProjectionElem::Index(_)]) => { + err.help( + "consider using `.split_at_mut(position)` or similar method to obtain \ + two mutable non-overlapping sub-slices", + ); + } + _ => {} + } + } + /// Returns the description of the root place for a conflicting borrow and the full /// descriptions of the places that caused the conflict. /// diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index cd6d94357e4..f85da760ada 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -218,19 +218,34 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; self.write_scalar(val, dest)?; } - sym::unchecked_shl | sym::unchecked_shr => { + sym::unchecked_shl + | sym::unchecked_shr + | sym::unchecked_add + | sym::unchecked_sub + | sym::unchecked_mul + | sym::unchecked_div + | sym::unchecked_rem => { let l = self.read_immediate(args[0])?; let r = self.read_immediate(args[1])?; let bin_op = match intrinsic_name { sym::unchecked_shl => BinOp::Shl, sym::unchecked_shr => BinOp::Shr, + sym::unchecked_add => BinOp::Add, + sym::unchecked_sub => BinOp::Sub, + sym::unchecked_mul => BinOp::Mul, + sym::unchecked_div => BinOp::Div, + sym::unchecked_rem => BinOp::Rem, _ => bug!("Already checked for int ops"), }; let (val, overflowed, _ty) = self.overflowing_binary_op(bin_op, l, r)?; if overflowed { let layout = self.layout_of(substs.type_at(0))?; let r_val = self.force_bits(r.to_scalar()?, layout.size)?; - throw_ub_format!("Overflowing shift by {} in `{}`", r_val, intrinsic_name); + if let sym::unchecked_shl | sym::unchecked_shr = intrinsic_name { + throw_ub_format!("Overflowing shift by {} in `{}`", r_val, intrinsic_name); + } else { + throw_ub_format!("Overflow executing `{}`", intrinsic_name); + } } self.write_scalar(val, dest)?; } diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs index b1cab591fd9..7c015c7a1d7 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/src/librustc_parse/parser/diagnostics.rs @@ -1,3 +1,4 @@ +use super::ty::AllowPlus; use super::{BlockMode, Parser, PathStyle, SemiColonMode, SeqSep, TokenExpectType, TokenType}; use rustc_ast_pretty::pprust; @@ -693,11 +694,11 @@ impl<'a> Parser<'a> { pub(super) fn maybe_report_ambiguous_plus( &mut self, - allow_plus: bool, + allow_plus: AllowPlus, impl_dyn_multi: bool, ty: &Ty, ) { - if !allow_plus && impl_dyn_multi { + if matches!(allow_plus, AllowPlus::No) && impl_dyn_multi { let sum_with_parens = format!("({})", pprust::ty_to_string(&ty)); self.struct_span_err(ty.span, "ambiguous `+` in a type") .span_suggestion( @@ -712,11 +713,11 @@ impl<'a> Parser<'a> { pub(super) fn maybe_recover_from_bad_type_plus( &mut self, - allow_plus: bool, + allow_plus: AllowPlus, ty: &Ty, ) -> PResult<'a, ()> { // Do not add `+` to expected tokens. - if !allow_plus || !self.token.is_like_plus() { + if matches!(allow_plus, AllowPlus::No) || !self.token.is_like_plus() { return Ok(()); } @@ -937,47 +938,6 @@ impl<'a> Parser<'a> { self.expect(&token::Semi).map(drop) // Error unconditionally } - pub(super) fn parse_semi_or_incorrect_foreign_fn_body( - &mut self, - ident: &Ident, - extern_sp: Span, - ) -> PResult<'a, ()> { - if self.token != token::Semi { - // This might be an incorrect fn definition (#62109). - let parser_snapshot = self.clone(); - match self.parse_inner_attrs_and_block() { - Ok((_, body)) => { - self.struct_span_err(ident.span, "incorrect `fn` inside `extern` block") - .span_label(ident.span, "can't have a body") - .span_label(body.span, "this body is invalid here") - .span_label( - extern_sp, - "`extern` blocks define existing foreign functions and `fn`s \ - inside of them cannot have a body", - ) - .help( - "you might have meant to write a function accessible through ffi, \ - which can be done by writing `extern fn` outside of the \ - `extern` block", - ) - .note( - "for more information, visit \ - https://doc.rust-lang.org/std/keyword.extern.html", - ) - .emit(); - } - Err(mut err) => { - err.cancel(); - mem::replace(self, parser_snapshot); - self.expect_semi()?; - } - } - } else { - self.bump(); - } - Ok(()) - } - /// Consumes alternative await syntaxes like `await!(<expr>)`, `await <expr>`, /// `await? <expr>`, `await(<expr>)`, and `await { <expr> }`. pub(super) fn recover_incorrect_await_syntax( diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 0d12f8cf6c0..d9832141695 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -1,4 +1,5 @@ use super::pat::{GateOr, PARAM_EXPECTED}; +use super::ty::{AllowPlus, RecoverQPath}; use super::{BlockMode, Parser, PathStyle, PrevTokenKind, Restrictions, TokenType}; use super::{SemiColonMode, SeqSep, TokenExpectType}; use crate::maybe_recover_from_interpolated_ty_qpath; @@ -1399,7 +1400,7 @@ impl<'a> Parser<'a> { self.expect_or()?; args }; - let output = self.parse_ret_ty(true, true)?; + let output = self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes)?; Ok(P(FnDecl { inputs, output })) } diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index b7f299e56ae..07d8bae4725 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -1,4 +1,5 @@ use super::diagnostics::{dummy_arg, ConsumeClosingDelim, Error}; +use super::ty::{AllowPlus, RecoverQPath}; use super::{FollowedByType, Parser, PathStyle}; use crate::maybe_whole; @@ -96,7 +97,6 @@ impl<'a> Parser<'a> { } if self.eat_keyword(kw::Extern) { - let extern_sp = self.prev_span; if self.eat_keyword(kw::Crate) { return Ok(Some(self.parse_item_extern_crate(lo, vis, attrs)?)); } @@ -114,7 +114,7 @@ impl<'a> Parser<'a> { }; return self.parse_item_fn(lo, vis, attrs, header); } else if self.check(&token::OpenDelim(token::Brace)) { - return Ok(Some(self.parse_item_foreign_mod(lo, abi, vis, attrs, extern_sp)?)); + return Ok(Some(self.parse_item_foreign_mod(lo, abi, vis, attrs)?)); } self.unexpected()?; @@ -1045,7 +1045,6 @@ impl<'a> Parser<'a> { abi: Option<StrLit>, visibility: Visibility, mut attrs: Vec<Attribute>, - extern_sp: Span, ) -> PResult<'a, P<Item>> { self.expect(&token::OpenDelim(token::Brace))?; @@ -1053,7 +1052,7 @@ impl<'a> Parser<'a> { let mut foreign_items = vec![]; while !self.eat(&token::CloseDelim(token::Brace)) { - foreign_items.push(self.parse_foreign_item(extern_sp)?); + foreign_items.push(self.parse_foreign_item()?); } let prev_span = self.prev_span; @@ -1063,51 +1062,42 @@ impl<'a> Parser<'a> { } /// Parses a foreign item. - pub fn parse_foreign_item(&mut self, extern_sp: Span) -> PResult<'a, P<ForeignItem>> { + pub fn parse_foreign_item(&mut self) -> PResult<'a, P<ForeignItem>> { maybe_whole!(self, NtForeignItem, |ni| ni); let attrs = self.parse_outer_attributes()?; let lo = self.token.span; let visibility = self.parse_visibility(FollowedByType::No)?; + // FOREIGN TYPE ITEM + if self.check_keyword(kw::Type) { + return self.parse_item_foreign_type(visibility, lo, attrs); + } + // FOREIGN STATIC ITEM - // Treat `const` as `static` for error recovery, but don't add it to expected tokens. - if self.check_keyword(kw::Static) || self.token.is_keyword(kw::Const) { - if self.token.is_keyword(kw::Const) { - let mut err = - self.struct_span_err(self.token.span, "extern items cannot be `const`"); + if self.is_static_global() { + self.bump(); // `static` + return self.parse_item_foreign_static(visibility, lo, attrs); + } - // The user wrote 'const fn' - if self.is_keyword_ahead(1, &[kw::Fn, kw::Unsafe]) { - err.emit(); - // Consume `const` - self.bump(); - // Consume `unsafe` if present, since `extern` blocks - // don't allow it. This will leave behind a plain 'fn' - self.eat_keyword(kw::Unsafe); - // Treat 'const fn` as a plain `fn` for error recovery purposes. - // We've already emitted an error, so compilation is guaranteed - // to fail - return Ok(self.parse_item_foreign_fn(visibility, lo, attrs, extern_sp)?); - } - err.span_suggestion( - self.token.span, + // Treat `const` as `static` for error recovery, but don't add it to expected tokens. + if self.is_kw_followed_by_ident(kw::Const) { + self.bump(); // `const` + self.struct_span_err(self.prev_span, "extern items cannot be `const`") + .span_suggestion( + self.prev_span, "try using a static value", "static".to_owned(), Applicability::MachineApplicable, - ); - err.emit(); - } - self.bump(); // `static` or `const` - return Ok(self.parse_item_foreign_static(visibility, lo, attrs)?); + ) + .emit(); + return self.parse_item_foreign_static(visibility, lo, attrs); } + // FOREIGN FUNCTION ITEM - if self.check_keyword(kw::Fn) { - return Ok(self.parse_item_foreign_fn(visibility, lo, attrs, extern_sp)?); - } - // FOREIGN TYPE ITEM - if self.check_keyword(kw::Type) { - return Ok(self.parse_item_foreign_type(visibility, lo, attrs)?); + const MAY_INTRODUCE_FN: &[Symbol] = &[kw::Const, kw::Async, kw::Unsafe, kw::Extern, kw::Fn]; + if MAY_INTRODUCE_FN.iter().any(|&kw| self.check_keyword(kw)) { + return self.parse_item_foreign_fn(visibility, lo, attrs); } match self.parse_assoc_macro_invoc("extern", Some(&visibility), &mut false)? { @@ -1726,14 +1716,14 @@ impl<'a> Parser<'a> { &mut self, lo: Span, vis: Visibility, - attrs: Vec<Attribute>, + mut attrs: Vec<Attribute>, header: FnHeader, ) -> PResult<'a, Option<P<Item>>> { let cfg = ParamCfg { is_name_required: |_| true }; let (ident, decl, generics) = self.parse_fn_sig(&cfg)?; - let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; + let body = self.parse_fn_body(&mut false, &mut attrs)?; let kind = ItemKind::Fn(FnSig { decl, header }, generics, body); - self.mk_item_with_info(attrs, lo, vis, (ident, kind, Some(inner_attrs))) + self.mk_item_with_info(attrs, lo, vis, (ident, kind, None)) } /// Parses a function declaration from a foreign module. @@ -1741,15 +1731,14 @@ impl<'a> Parser<'a> { &mut self, vis: ast::Visibility, lo: Span, - attrs: Vec<Attribute>, - extern_sp: Span, + mut attrs: Vec<Attribute>, ) -> PResult<'a, P<ForeignItem>> { let cfg = ParamCfg { is_name_required: |_| true }; - self.expect_keyword(kw::Fn)?; + let header = self.parse_fn_front_matter()?; let (ident, decl, generics) = self.parse_fn_sig(&cfg)?; - let span = lo.to(self.token.span); - self.parse_semi_or_incorrect_foreign_fn_body(&ident, extern_sp)?; - let kind = ForeignItemKind::Fn(decl, generics); + let body = self.parse_fn_body(&mut false, &mut attrs)?; + let kind = ForeignItemKind::Fn(FnSig { header, decl }, generics, body); + let span = lo.to(self.prev_span); Ok(P(ast::ForeignItem { ident, attrs, kind, id: DUMMY_NODE_ID, span, vis, tokens: None })) } @@ -1760,45 +1749,40 @@ impl<'a> Parser<'a> { is_name_required: fn(&token::Token) -> bool, ) -> PResult<'a, (Ident, AssocItemKind, Generics)> { let header = self.parse_fn_front_matter()?; - let (ident, decl, generics) = self.parse_fn_sig(&ParamCfg { is_name_required })?; - let sig = FnSig { header, decl }; - let body = self.parse_assoc_fn_body(at_end, attrs)?; - Ok((ident, AssocItemKind::Fn(sig, body), generics)) + let (ident, decl, generics) = self.parse_fn_sig(&&ParamCfg { is_name_required })?; + let body = self.parse_fn_body(at_end, attrs)?; + Ok((ident, AssocItemKind::Fn(FnSig { header, decl }, body), generics)) } - /// Parse the "body" of a method in an associated item definition. + /// Parse the "body" of a function. /// This can either be `;` when there's no body, - /// or e.g. a block when the method is a provided one. - fn parse_assoc_fn_body( + /// or e.g. a block when the function is a provided one. + fn parse_fn_body( &mut self, at_end: &mut bool, attrs: &mut Vec<Attribute>, ) -> PResult<'a, Option<P<Block>>> { - Ok(match self.token.kind { + let (inner_attrs, body) = match self.token.kind { token::Semi => { - debug!("parse_assoc_fn_body(): parsing required method"); self.bump(); - *at_end = true; - None + (Vec::new(), None) } token::OpenDelim(token::Brace) => { - debug!("parse_assoc_fn_body(): parsing provided method"); - *at_end = true; - let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - attrs.extend(inner_attrs.iter().cloned()); - Some(body) + let (attrs, body) = self.parse_inner_attrs_and_block()?; + (attrs, Some(body)) } token::Interpolated(ref nt) => match **nt { token::NtBlock(..) => { - *at_end = true; - let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - attrs.extend(inner_attrs.iter().cloned()); - Some(body) + let (attrs, body) = self.parse_inner_attrs_and_block()?; + (attrs, Some(body)) } _ => return self.expected_semi_or_open_brace(), }, _ => return self.expected_semi_or_open_brace(), - }) + }; + attrs.extend(inner_attrs); + *at_end = true; + Ok(body) } /// Parses all the "front matter" for a `fn` declaration, up to @@ -1839,7 +1823,7 @@ impl<'a> Parser<'a> { fn parse_fn_sig(&mut self, cfg: &ParamCfg) -> PResult<'a, (Ident, P<FnDecl>, Generics)> { let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; - let decl = self.parse_fn_decl(cfg, true)?; + let decl = self.parse_fn_decl(cfg, AllowPlus::Yes)?; generics.where_clause = self.parse_where_clause()?; Ok((ident, decl, generics)) } @@ -1848,11 +1832,11 @@ impl<'a> Parser<'a> { pub(super) fn parse_fn_decl( &mut self, cfg: &ParamCfg, - ret_allow_plus: bool, + ret_allow_plus: AllowPlus, ) -> PResult<'a, P<FnDecl>> { Ok(P(FnDecl { inputs: self.parse_fn_params(cfg)?, - output: self.parse_ret_ty(ret_allow_plus, true)?, + output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes)?, })) } diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs index a09eb42dcfe..cb14ffb4bd0 100644 --- a/src/librustc_parse/parser/path.rs +++ b/src/librustc_parse/parser/path.rs @@ -1,3 +1,4 @@ +use super::ty::{AllowPlus, RecoverQPath}; use super::{Parser, TokenType}; use crate::maybe_whole; use rustc_errors::{pluralize, Applicability, PResult}; @@ -224,7 +225,7 @@ impl<'a> Parser<'a> { // `(T, U) -> R` let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?; let span = ident.span.to(self.prev_span); - let output = self.parse_ret_ty(false, false)?; + let output = self.parse_ret_ty(AllowPlus::No, RecoverQPath::No)?; ParenthesizedArgs { inputs, output, span }.into() }; diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs index ae8f1e4db1b..f3a69729399 100644 --- a/src/librustc_parse/parser/stmt.rs +++ b/src/librustc_parse/parser/stmt.rs @@ -199,7 +199,7 @@ impl<'a> Parser<'a> { } } - fn is_kw_followed_by_ident(&self, kw: Symbol) -> bool { + pub(super) fn is_kw_followed_by_ident(&self, kw: Symbol) -> bool { self.token.is_keyword(kw) && self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident()) } diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index c9c2cbb98ca..990661bf6b5 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -36,6 +36,25 @@ impl BoundModifiers { } } +#[derive(Copy, Clone, PartialEq)] +pub(super) enum AllowPlus { + Yes, + No, +} + +#[derive(PartialEq)] +pub(super) enum RecoverQPath { + Yes, + No, +} + +// Is `...` (`CVarArgs`) legal at this level of type parsing? +#[derive(PartialEq)] +enum AllowCVariadic { + Yes, + No, +} + /// Returns `true` if `IDENT t` can start a type -- `IDENT::a::b`, `IDENT<u8, u8>`, /// `IDENT<<u8 as Trait>::AssocTy>`. /// @@ -48,14 +67,14 @@ fn can_continue_type_after_non_fn_ident(t: &Token) -> bool { impl<'a> Parser<'a> { /// Parses a type. pub fn parse_ty(&mut self) -> PResult<'a, P<Ty>> { - self.parse_ty_common(true, true, false) + self.parse_ty_common(AllowPlus::Yes, RecoverQPath::Yes, AllowCVariadic::No) } /// Parse a type suitable for a function or function pointer parameter. /// The difference from `parse_ty` is that this version allows `...` /// (`CVarArgs`) at the top level of the the type. pub(super) fn parse_ty_for_param(&mut self) -> PResult<'a, P<Ty>> { - self.parse_ty_common(true, true, true) + self.parse_ty_common(AllowPlus::Yes, RecoverQPath::Yes, AllowCVariadic::Yes) } /// Parses a type in restricted contexts where `+` is not permitted. @@ -65,18 +84,19 @@ impl<'a> Parser<'a> { /// Example 2: `value1 as TYPE + value2` /// `+` is prohibited to avoid interactions with expression grammar. pub(super) fn parse_ty_no_plus(&mut self) -> PResult<'a, P<Ty>> { - self.parse_ty_common(false, true, false) + self.parse_ty_common(AllowPlus::No, RecoverQPath::Yes, AllowCVariadic::No) } /// Parses an optional return type `[ -> TY ]` in a function declaration. pub(super) fn parse_ret_ty( &mut self, - allow_plus: bool, - allow_qpath_recovery: bool, + allow_plus: AllowPlus, + recover_qpath: RecoverQPath, ) -> PResult<'a, FunctionRetTy> { Ok(if self.eat(&token::RArrow) { // FIXME(Centril): Can we unconditionally `allow_plus`? - FunctionRetTy::Ty(self.parse_ty_common(allow_plus, allow_qpath_recovery, false)?) + let ty = self.parse_ty_common(allow_plus, recover_qpath, AllowCVariadic::No)?; + FunctionRetTy::Ty(ty) } else { FunctionRetTy::Default(self.token.span.shrink_to_lo()) }) @@ -84,11 +104,11 @@ impl<'a> Parser<'a> { fn parse_ty_common( &mut self, - allow_plus: bool, - allow_qpath_recovery: bool, - // Is `...` (`CVarArgs`) legal in the immediate top level call? - allow_c_variadic: bool, + allow_plus: AllowPlus, + recover_qpath: RecoverQPath, + allow_c_variadic: AllowCVariadic, ) -> PResult<'a, P<Ty>> { + let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes; maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery); maybe_whole!(self, NtTy, |x| x); @@ -124,7 +144,7 @@ impl<'a> Parser<'a> { self.parse_ty_bare_fn(lifetime_defs)? } else { let path = self.parse_path(PathStyle::Type)?; - let parse_plus = allow_plus && self.check_plus(); + let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus(); self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)? } } else if self.eat_keyword(kw::Impl) { @@ -144,7 +164,7 @@ impl<'a> Parser<'a> { } else if self.token.is_path_start() { self.parse_path_start_ty(lo, allow_plus)? } else if self.eat(&token::DotDotDot) { - if allow_c_variadic { + if allow_c_variadic == AllowCVariadic::Yes { TyKind::CVarArgs } else { // FIXME(Centril): Should we just allow `...` syntactically @@ -172,7 +192,7 @@ impl<'a> Parser<'a> { /// Parses either: /// - `(TYPE)`, a parenthesized type. /// - `(TYPE,)`, a tuple with a single field of type TYPE. - fn parse_ty_tuple_or_parens(&mut self, lo: Span, allow_plus: bool) -> PResult<'a, TyKind> { + fn parse_ty_tuple_or_parens(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> { let mut trailing_plus = false; let (ts, trailing) = self.parse_paren_comma_seq(|p| { let ty = p.parse_ty()?; @@ -182,7 +202,7 @@ impl<'a> Parser<'a> { if ts.len() == 1 && !trailing { let ty = ts.into_iter().nth(0).unwrap().into_inner(); - let maybe_bounds = allow_plus && self.token.is_like_plus(); + let maybe_bounds = allow_plus == AllowPlus::Yes && self.token.is_like_plus(); match ty.kind { // `(TY_BOUND_NOPAREN) + BOUND + ...`. TyKind::Path(None, path) if maybe_bounds => { @@ -288,7 +308,8 @@ impl<'a> Parser<'a> { let unsafety = self.parse_unsafety(); let ext = self.parse_extern()?; self.expect_keyword(kw::Fn)?; - let decl = self.parse_fn_decl(&ParamCfg { is_name_required: |_| false }, false)?; + let cfg = ParamCfg { is_name_required: |_| false }; + let decl = self.parse_fn_decl(&cfg, AllowPlus::No)?; Ok(TyKind::BareFn(P(BareFnTy { ext, unsafety, generic_params, decl }))) } @@ -326,7 +347,7 @@ impl<'a> Parser<'a> { /// 1. a type macro, `mac!(...)`, /// 2. a bare trait object, `B0 + ... + Bn`, /// 3. or a path, `path::to::MyType`. - fn parse_path_start_ty(&mut self, lo: Span, allow_plus: bool) -> PResult<'a, TyKind> { + fn parse_path_start_ty(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> { // Simple path let path = self.parse_path(PathStyle::Type)?; if self.eat(&token::Not) { @@ -336,7 +357,7 @@ impl<'a> Parser<'a> { args: self.parse_mac_args()?, prior_type_ascription: self.last_type_ascription, })) - } else if allow_plus && self.check_plus() { + } else if allow_plus == AllowPlus::Yes && self.check_plus() { // `Trait1 + Trait2 + 'a` self.parse_remaining_bounds(Vec::new(), path, lo, true) } else { @@ -359,7 +380,7 @@ impl<'a> Parser<'a> { &mut self, colon_span: Option<Span>, ) -> PResult<'a, GenericBounds> { - self.parse_generic_bounds_common(true, colon_span) + self.parse_generic_bounds_common(AllowPlus::Yes, colon_span) } /// Parses bounds of a type parameter `BOUND + BOUND + ...`, possibly with trailing `+`. @@ -367,7 +388,7 @@ impl<'a> Parser<'a> { /// See `parse_generic_bound` for the `BOUND` grammar. fn parse_generic_bounds_common( &mut self, - allow_plus: bool, + allow_plus: AllowPlus, colon_span: Option<Span>, ) -> PResult<'a, GenericBounds> { let mut bounds = Vec::new(); @@ -377,7 +398,7 @@ impl<'a> Parser<'a> { Ok(bound) => bounds.push(bound), Err(neg_sp) => negative_bounds.push(neg_sp), } - if !allow_plus || !self.eat_plus() { + if allow_plus == AllowPlus::No || !self.eat_plus() { break; } } diff --git a/src/librustc_passes/dead.rs b/src/librustc_passes/dead.rs index 2ff9d744f2c..9367909d10c 100644 --- a/src/librustc_passes/dead.rs +++ b/src/librustc_passes/dead.rs @@ -15,7 +15,6 @@ use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::{Node, PatKind, TyKind}; use rustc_session::lint; -use rustc_span; use rustc_span::symbol::sym; use syntax::{ast, attr}; diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs index b6ca2b3a595..c6c201fa38e 100644 --- a/src/librustc_passes/hir_stats.rs +++ b/src/librustc_passes/hir_stats.rs @@ -302,19 +302,18 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { ast_visit::walk_ty(self, t) } - fn visit_fn(&mut self, fk: ast_visit::FnKind<'v>, fd: &'v ast::FnDecl, s: Span, _: NodeId) { - self.record("FnDecl", Id::None, fd); - ast_visit::walk_fn(self, fk, fd, s) - } - - fn visit_trait_item(&mut self, ti: &'v ast::AssocItem) { - self.record("TraitItem", Id::None, ti); - ast_visit::walk_trait_item(self, ti) - } - - fn visit_impl_item(&mut self, ii: &'v ast::AssocItem) { - self.record("ImplItem", Id::None, ii); - ast_visit::walk_impl_item(self, ii) + fn visit_fn(&mut self, fk: ast_visit::FnKind<'v>, s: Span, _: NodeId) { + self.record("FnDecl", Id::None, fk.decl()); + ast_visit::walk_fn(self, fk, s) + } + + fn visit_assoc_item(&mut self, item: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) { + let label = match ctxt { + ast_visit::AssocCtxt::Trait => "TraitItem", + ast_visit::AssocCtxt::Impl => "ImplItem", + }; + self.record(label, Id::None, item); + ast_visit::walk_assoc_item(self, item, ctxt); } fn visit_param_bound(&mut self, bounds: &'v ast::GenericBound) { diff --git a/src/librustc_passes/liveness.rs b/src/librustc_passes/liveness.rs index 7718139f6e9..b355a47c394 100644 --- a/src/librustc_passes/liveness.rs +++ b/src/librustc_passes/liveness.rs @@ -822,8 +822,15 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { return false; } - let mut changed = false; + let mut any_changed = false; self.indices2(ln, succ_ln, |this, idx, succ_idx| { + // This is a special case, pulled out from the code below, where we + // don't have to do anything. It occurs about 60-70% of the time. + if this.rwu_table.packed_rwus[succ_idx] == INV_INV_FALSE { + return; + } + + let mut changed = false; let mut rwu = this.rwu_table.get(idx); let succ_rwu = this.rwu_table.get(succ_idx); if succ_rwu.reader.is_valid() && !rwu.reader.is_valid() { @@ -843,6 +850,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { if changed { this.rwu_table.assign_unpacked(idx, rwu); + any_changed = true; } }); @@ -851,9 +859,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { ln, self.ln_str(succ_ln), first_merge, - changed + any_changed ); - return changed; + return any_changed; } // Indicates that a local variable was *defined*; we know that no diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index c77b588d7fb..d6ea737385c 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -36,7 +36,7 @@ use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, Nod use syntax::ast::{AssocItem, AssocItemKind, MetaItemKind, StmtKind}; use syntax::ast::{Ident, Name}; use syntax::token::{self, Token}; -use syntax::visit::{self, Visitor}; +use syntax::visit::{self, AssocCtxt, Visitor}; use log::debug; use std::cell::Cell; @@ -1234,7 +1234,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { self.parent_scope.legacy = orig_current_legacy_scope; } - fn visit_trait_item(&mut self, item: &'b AssocItem) { + fn visit_assoc_item(&mut self, item: &'b AssocItem, ctxt: AssocCtxt) { let parent = self.parent_scope.module; if let AssocItemKind::Macro(_) = item.kind { @@ -1242,6 +1242,12 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { return; } + if let AssocCtxt::Impl = ctxt { + self.resolve_visibility(&item.vis); + visit::walk_assoc_item(self, item, ctxt); + return; + } + // Add the item to the trait info. let item_def_id = self.r.definitions.local_def_id(item.id); let (res, ns) = match item.kind { @@ -1260,16 +1266,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { let expansion = self.parent_scope.expansion; self.r.define(parent, item.ident, ns, (res, vis, item.span, expansion)); - visit::walk_trait_item(self, item); - } - - fn visit_impl_item(&mut self, item: &'b ast::AssocItem) { - if let ast::AssocItemKind::Macro(..) = item.kind { - self.visit_invoc(item.id); - } else { - self.resolve_visibility(&item.vis); - visit::walk_impl_item(self, item); - } + visit::walk_assoc_item(self, item, ctxt); } fn visit_token(&mut self, t: Token) { diff --git a/src/librustc_resolve/def_collector.rs b/src/librustc_resolve/def_collector.rs index 696ba0e994c..3a26197c160 100644 --- a/src/librustc_resolve/def_collector.rs +++ b/src/librustc_resolve/def_collector.rs @@ -125,7 +125,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { &sig.header, generics, &sig.decl, - Some(body), + body.as_deref(), ); } ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) => { @@ -213,39 +213,26 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { visit::walk_generic_param(self, param); } - fn visit_trait_item(&mut self, ti: &'a AssocItem) { - let def_data = match ti.kind { - AssocItemKind::Fn(..) | AssocItemKind::Const(..) => DefPathData::ValueNs(ti.ident.name), - AssocItemKind::TyAlias(..) => DefPathData::TypeNs(ti.ident.name), - AssocItemKind::Macro(..) => return self.visit_macro_invoc(ti.id), - }; - - let def = self.create_def(ti.id, def_data, ti.span); - self.with_parent(def, |this| visit::walk_trait_item(this, ti)); - } - - fn visit_impl_item(&mut self, ii: &'a AssocItem) { - let def_data = match ii.kind { - AssocItemKind::Fn(FnSig { ref header, ref decl }, ref body) - if header.asyncness.node.is_async() => - { + fn visit_assoc_item(&mut self, i: &'a AssocItem, ctxt: visit::AssocCtxt) { + let def_data = match &i.kind { + AssocItemKind::Fn(FnSig { header, decl }, body) if header.asyncness.node.is_async() => { return self.visit_async_fn( - ii.id, - ii.ident.name, - ii.span, + i.id, + i.ident.name, + i.span, header, - &ii.generics, + &i.generics, decl, body.as_deref(), ); } - AssocItemKind::Fn(..) | AssocItemKind::Const(..) => DefPathData::ValueNs(ii.ident.name), - AssocItemKind::TyAlias(..) => DefPathData::TypeNs(ii.ident.name), - AssocItemKind::Macro(..) => return self.visit_macro_invoc(ii.id), + AssocItemKind::Fn(..) | AssocItemKind::Const(..) => DefPathData::ValueNs(i.ident.name), + AssocItemKind::TyAlias(..) => DefPathData::TypeNs(i.ident.name), + AssocItemKind::Macro(..) => return self.visit_macro_invoc(i.id), }; - let def = self.create_def(ii.id, def_data, ii.span); - self.with_parent(def, |this| visit::walk_impl_item(this, ii)); + let def = self.create_def(i.id, def_data, i.span); + self.with_parent(def, |this| visit::walk_assoc_item(this, i, ctxt)); } fn visit_pat(&mut self, pat: &'a Pat) { diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index a612ad9e783..075dca8f01d 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -20,6 +20,7 @@ use syntax::ast::{self, Ident, Path}; use syntax::util::lev_distance::find_best_match_for_name; use crate::imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver}; +use crate::lifetimes::{ElisionFailureInfo, LifetimeContext}; use crate::path_names_to_string; use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind}; use crate::{BindingError, CrateLint, HasGenericParams, LegacyScope, Module, ModuleOrUniformRoot}; @@ -48,6 +49,40 @@ crate struct ImportSuggestion { pub path: Path, } +crate enum MissingLifetimeSpot<'tcx> { + Generics(&'tcx hir::Generics<'tcx>), + HigherRanked { span: Span, span_type: ForLifetimeSpanType }, +} + +crate enum ForLifetimeSpanType { + BoundEmpty, + BoundTail, + TypeEmpty, + TypeTail, +} + +impl ForLifetimeSpanType { + crate fn descr(&self) -> &'static str { + match self { + Self::BoundEmpty | Self::BoundTail => "bound", + Self::TypeEmpty | Self::TypeTail => "type", + } + } + + crate fn suggestion(&self, sugg: &str) -> String { + match self { + Self::BoundEmpty | Self::TypeEmpty => format!("for<{}> ", sugg), + Self::BoundTail | Self::TypeTail => format!(", {}", sugg), + } + } +} + +impl<'tcx> Into<MissingLifetimeSpot<'tcx>> for &'tcx hir::Generics<'tcx> { + fn into(self) -> MissingLifetimeSpot<'tcx> { + MissingLifetimeSpot::Generics(self) + } +} + /// Adjust the impl span so that just the `impl` keyword is taken by removing /// everything after `<` (`"impl<T> Iterator for A<T> {}" -> "impl"`) and /// everything after the first whitespace (`"impl Iterator for A" -> "impl"`). @@ -1457,72 +1492,206 @@ crate fn show_candidates( } } -crate fn report_missing_lifetime_specifiers( - sess: &Session, - span: Span, - count: usize, -) -> DiagnosticBuilder<'_> { - struct_span_err!(sess, span, E0106, "missing lifetime specifier{}", pluralize!(count)) -} +impl<'tcx> LifetimeContext<'_, 'tcx> { + crate fn report_missing_lifetime_specifiers( + &self, + span: Span, + count: usize, + ) -> DiagnosticBuilder<'tcx> { + struct_span_err!( + self.tcx.sess, + span, + E0106, + "missing lifetime specifier{}", + pluralize!(count) + ) + } -crate fn add_missing_lifetime_specifiers_label( - err: &mut DiagnosticBuilder<'_>, - span: Span, - count: usize, - lifetime_names: &FxHashSet<ast::Ident>, - snippet: Option<&str>, - missing_named_lifetime_spots: &[&hir::Generics<'_>], -) { - if count > 1 { - err.span_label(span, format!("expected {} lifetime parameters", count)); - } else { - let suggest_existing = |err: &mut DiagnosticBuilder<'_>, sugg| { - err.span_suggestion( - span, - "consider using the named lifetime", - sugg, - Applicability::MaybeIncorrect, - ); - }; - let suggest_new = |err: &mut DiagnosticBuilder<'_>, sugg| { - err.span_label(span, "expected named lifetime parameter"); - - if let Some(generics) = missing_named_lifetime_spots.iter().last() { - let mut introduce_suggestion = vec![]; - introduce_suggestion.push(match &generics.params { - [] => (generics.span, "<'lifetime>".to_string()), - [param, ..] => (param.span.shrink_to_lo(), "'lifetime, ".to_string()), - }); - introduce_suggestion.push((span, sugg)); - err.multipart_suggestion( - "consider introducing a named lifetime parameter", - introduce_suggestion, - Applicability::MaybeIncorrect, - ); + crate fn emit_undeclared_lifetime_error(&self, lifetime_ref: &hir::Lifetime) { + let mut err = struct_span_err!( + self.tcx.sess, + lifetime_ref.span, + E0261, + "use of undeclared lifetime name `{}`", + lifetime_ref + ); + err.span_label(lifetime_ref.span, "undeclared lifetime"); + for missing in &self.missing_named_lifetime_spots { + match missing { + MissingLifetimeSpot::Generics(generics) => { + let (span, sugg) = if let Some(param) = generics + .params + .iter() + .filter(|p| match p.kind { + hir::GenericParamKind::Type { + synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), + .. + } => false, + _ => true, + }) + .next() + { + (param.span.shrink_to_lo(), format!("{}, ", lifetime_ref)) + } else { + (generics.span, format!("<{}>", lifetime_ref)) + }; + err.span_suggestion( + span, + &format!("consider introducing lifetime `{}` here", lifetime_ref), + sugg, + Applicability::MaybeIncorrect, + ); + } + MissingLifetimeSpot::HigherRanked { span, span_type } => { + err.span_suggestion( + *span, + &format!( + "consider making the {} lifetime-generic with a new `{}` lifetime", + span_type.descr(), + lifetime_ref + ), + span_type.suggestion(&lifetime_ref.to_string()), + Applicability::MaybeIncorrect, + ); + err.note( + "for more information on higher-ranked polymorphism, visit \ + https://doc.rust-lang.org/nomicon/hrtb.html", + ); + } } - }; + } + err.emit(); + } - match (lifetime_names.len(), lifetime_names.iter().next(), snippet) { - (1, Some(name), Some("&")) => { - suggest_existing(err, format!("&{} ", name)); - } - (1, Some(name), Some("'_")) => { - suggest_existing(err, name.to_string()); - } - (1, Some(name), Some(snippet)) if !snippet.ends_with(">") => { - suggest_existing(err, format!("{}<{}>", snippet, name)); - } - (0, _, Some("&")) => { - suggest_new(err, "&'lifetime ".to_string()); - } - (0, _, Some("'_")) => { - suggest_new(err, "'lifetime".to_string()); - } - (0, _, Some(snippet)) if !snippet.ends_with(">") => { - suggest_new(err, format!("{}<'lifetime>", snippet)); + crate fn is_trait_ref_fn_scope(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) -> bool { + if let def::Res::Def(_, did) = trait_ref.trait_ref.path.res { + if [ + self.tcx.lang_items().fn_once_trait(), + self.tcx.lang_items().fn_trait(), + self.tcx.lang_items().fn_mut_trait(), + ] + .contains(&Some(did)) + { + let (span, span_type) = match &trait_ref.bound_generic_params { + [] => (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty), + [.., bound] => (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail), + }; + self.missing_named_lifetime_spots + .push(MissingLifetimeSpot::HigherRanked { span, span_type }); + return true; } - _ => { - err.span_label(span, "expected lifetime parameter"); + }; + false + } + + crate fn add_missing_lifetime_specifiers_label( + &self, + err: &mut DiagnosticBuilder<'_>, + span: Span, + count: usize, + lifetime_names: &FxHashSet<ast::Ident>, + params: &[ElisionFailureInfo], + ) { + if count > 1 { + err.span_label(span, format!("expected {} lifetime parameters", count)); + } else { + let snippet = self.tcx.sess.source_map().span_to_snippet(span).ok(); + let suggest_existing = |err: &mut DiagnosticBuilder<'_>, sugg| { + err.span_suggestion( + span, + "consider using the named lifetime", + sugg, + Applicability::MaybeIncorrect, + ); + }; + let suggest_new = + |err: &mut DiagnosticBuilder<'_>, sugg: &str| { + err.span_label(span, "expected named lifetime parameter"); + + for missing in self.missing_named_lifetime_spots.iter().rev() { + let mut introduce_suggestion = vec![]; + let msg; + let should_break; + introduce_suggestion.push(match missing { + MissingLifetimeSpot::Generics(generics) => { + msg = "consider introducing a named lifetime parameter".to_string(); + should_break = true; + if let Some(param) = generics.params.iter().filter(|p| match p.kind { + hir::GenericParamKind::Type { + synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), + .. + } => false, + _ => true, + }).next() { + (param.span.shrink_to_lo(), "'a, ".to_string()) + } else { + (generics.span, "<'a>".to_string()) + } + } + MissingLifetimeSpot::HigherRanked { span, span_type } => { + msg = format!( + "consider making the {} lifetime-generic with a new `'a` lifetime", + span_type.descr(), + ); + should_break = false; + err.note( + "for more information on higher-ranked polymorphism, visit \ + https://doc.rust-lang.org/nomicon/hrtb.html", + ); + (*span, span_type.suggestion("'a")) + } + }); + for param in params { + if let Ok(snippet) = + self.tcx.sess.source_map().span_to_snippet(param.span) + { + if snippet.starts_with("&") && !snippet.starts_with("&'") { + introduce_suggestion + .push((param.span, format!("&'a {}", &snippet[1..]))); + } else if snippet.starts_with("&'_ ") { + introduce_suggestion + .push((param.span, format!("&'a {}", &snippet[4..]))); + } + } + } + introduce_suggestion.push((span, sugg.to_string())); + err.multipart_suggestion( + &msg, + introduce_suggestion, + Applicability::MaybeIncorrect, + ); + if should_break { + break; + } + } + }; + + match ( + lifetime_names.len(), + lifetime_names.iter().next(), + snippet.as_ref().map(|s| s.as_str()), + ) { + (1, Some(name), Some("&")) => { + suggest_existing(err, format!("&{} ", name)); + } + (1, Some(name), Some("'_")) => { + suggest_existing(err, name.to_string()); + } + (1, Some(name), Some(snippet)) if !snippet.ends_with(">") => { + suggest_existing(err, format!("{}<{}>", snippet, name)); + } + (0, _, Some("&")) => { + suggest_new(err, "&'a "); + } + (0, _, Some("'_")) => { + suggest_new(err, "'a"); + } + (0, _, Some(snippet)) if !snippet.ends_with(">") => { + suggest_new(err, &format!("{}<'a>", snippet)); + } + _ => { + err.span_label(span, "expected lifetime parameter"); + } } } } diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index f1622af130e..01a0e568137 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -24,7 +24,7 @@ use smallvec::{smallvec, SmallVec}; use syntax::ast::*; use syntax::ptr::P; use syntax::util::lev_distance::find_best_match_for_name; -use syntax::visit::{self, FnKind, Visitor}; +use syntax::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use syntax::{unwrap_or, walk_list}; use log::debug; @@ -437,7 +437,7 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { } fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) { match foreign_item.kind { - ForeignItemKind::Fn(_, ref generics) => { + ForeignItemKind::Fn(_, ref generics, _) => { self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { visit::walk_foreign_item(this, foreign_item); }); @@ -452,13 +452,15 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { } } } - fn visit_fn(&mut self, fn_kind: FnKind<'ast>, declaration: &'ast FnDecl, sp: Span, _: NodeId) { - let previous_value = replace(&mut self.diagnostic_metadata.current_function, Some(sp)); - debug!("(resolving function) entering function"); + fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, _: NodeId) { let rib_kind = match fn_kind { - FnKind::ItemFn(..) => FnItemRibKind, - FnKind::Method(..) | FnKind::Closure(_) => NormalRibKind, + FnKind::Fn(FnCtxt::Foreign, ..) => return visit::walk_fn(self, fn_kind, sp), + FnKind::Fn(FnCtxt::Free, ..) => FnItemRibKind, + FnKind::Fn(FnCtxt::Assoc(_), ..) | FnKind::Closure(..) => NormalRibKind, }; + let previous_value = replace(&mut self.diagnostic_metadata.current_function, Some(sp)); + debug!("(resolving function) entering function"); + let declaration = fn_kind.decl(); // Create a value rib for the function. self.with_rib(ValueNS, rib_kind, |this| { @@ -471,8 +473,8 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { // Resolve the function body, potentially inside the body of an async closure match fn_kind { - FnKind::ItemFn(.., body) | FnKind::Method(.., body) => this.visit_block(body), - FnKind::Closure(body) => this.visit_expr(body), + FnKind::Fn(.., body) => walk_list!(this, visit_block, body), + FnKind::Closure(_, body) => this.visit_expr(body), }; debug!("(resolving function) leaving function"); @@ -843,12 +845,16 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { }); } } - AssocItemKind::Fn(_, _) => { - visit::walk_trait_item(this, trait_item) - } - AssocItemKind::TyAlias(..) => { - visit::walk_trait_item(this, trait_item) - } + AssocItemKind::Fn(_, _) => visit::walk_assoc_item( + this, + trait_item, + AssocCtxt::Trait, + ), + AssocItemKind::TyAlias(..) => visit::walk_assoc_item( + this, + trait_item, + AssocCtxt::Trait, + ), AssocItemKind::Macro(_) => { panic!("unexpanded macro in resolve!") } @@ -1128,7 +1134,11 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ); this.with_constant_rib(|this| { - visit::walk_impl_item(this, impl_item) + visit::walk_assoc_item( + this, + impl_item, + AssocCtxt::Impl, + ) }); } AssocItemKind::Fn(..) => { @@ -1139,7 +1149,11 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { impl_item.span, |n, s| MethodNotMemberOfTrait(n, s)); - visit::walk_impl_item(this, impl_item); + visit::walk_assoc_item( + this, + impl_item, + AssocCtxt::Impl, + ) } AssocItemKind::TyAlias(_, _) => { // If this is a trait impl, ensure the type @@ -1149,7 +1163,11 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { impl_item.span, |n, s| TypeNotMemberOfTrait(n, s)); - visit::walk_impl_item(this, impl_item); + visit::walk_assoc_item( + this, + impl_item, + AssocCtxt::Impl, + ) } AssocItemKind::Macro(_) => panic!("unexpanded macro in resolve!"), diff --git a/src/librustc_resolve/lifetimes.rs b/src/librustc_resolve/lifetimes.rs index 6e9ed5fdc17..0ba9b4f1706 100644 --- a/src/librustc_resolve/lifetimes.rs +++ b/src/librustc_resolve/lifetimes.rs @@ -5,9 +5,7 @@ //! used between functions, and they operate in a purely top-down //! way. Therefore, we break lifetime name resolution into a separate pass. -use crate::diagnostics::{ - add_missing_lifetime_specifiers_label, report_missing_lifetime_specifiers, -}; +use crate::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot}; use rustc::hir::map::Map; use rustc::lint; use rustc::middle::resolve_lifetime::*; @@ -153,8 +151,8 @@ struct NamedRegionMap { object_lifetime_defaults: HirIdMap<Vec<ObjectLifetimeDefault>>, } -struct LifetimeContext<'a, 'tcx> { - tcx: TyCtxt<'tcx>, +crate struct LifetimeContext<'a, 'tcx> { + crate tcx: TyCtxt<'tcx>, map: &'a mut NamedRegionMap, scope: ScopeRef<'a>, @@ -186,7 +184,7 @@ struct LifetimeContext<'a, 'tcx> { /// When encountering an undefined named lifetime, we will suggest introducing it in these /// places. - missing_named_lifetime_spots: Vec<&'tcx hir::Generics<'tcx>>, + crate missing_named_lifetime_spots: Vec<MissingLifetimeSpot<'tcx>>, } #[derive(Debug)] @@ -264,13 +262,14 @@ enum Elide { } #[derive(Clone, Debug)] -struct ElisionFailureInfo { +crate struct ElisionFailureInfo { /// Where we can find the argument pattern. parent: Option<hir::BodyId>, /// The index of the argument in the original definition. index: usize, lifetime_count: usize, have_bound_regions: bool, + crate span: Span, } type ScopeRef<'a> = &'a Scope<'a>; @@ -389,7 +388,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { match item.kind { hir::ItemKind::Fn(ref sig, ref generics, _) => { - self.missing_named_lifetime_spots.push(generics); + self.missing_named_lifetime_spots.push(generics.into()); self.visit_early_late(None, &sig.decl, generics, |this| { intravisit::walk_item(this, item); }); @@ -424,7 +423,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { | hir::ItemKind::Trait(_, _, ref generics, ..) | hir::ItemKind::TraitAlias(ref generics, ..) | hir::ItemKind::Impl { ref generics, .. } => { - self.missing_named_lifetime_spots.push(generics); + self.missing_named_lifetime_spots.push(generics.into()); // Impls permit `'_` to be used and it is equivalent to "some fresh lifetime name". // This is not true for other kinds of items.x @@ -492,6 +491,21 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let next_early_index = self.next_early_index(); let was_in_fn_syntax = self.is_in_fn_syntax; self.is_in_fn_syntax = true; + let lifetime_span: Option<Span> = c + .generic_params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => Some(param.span), + _ => None, + }) + .last(); + let (span, span_type) = if let Some(span) = lifetime_span { + (span.shrink_to_hi(), ForLifetimeSpanType::TypeTail) + } else { + (ty.span.shrink_to_lo(), ForLifetimeSpanType::TypeEmpty) + }; + self.missing_named_lifetime_spots + .push(MissingLifetimeSpot::HigherRanked { span, span_type }); let scope = Scope::Binder { lifetimes: c .generic_params @@ -514,6 +528,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { this.check_lifetime_params(old_scope, &c.generic_params); intravisit::walk_ty(this, ty); }); + self.missing_named_lifetime_spots.pop(); self.is_in_fn_syntax = was_in_fn_syntax; } hir::TyKind::TraitObject(bounds, ref lifetime) => { @@ -696,7 +711,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { use self::hir::TraitItemKind::*; - self.missing_named_lifetime_spots.push(&trait_item.generics); + self.missing_named_lifetime_spots.push((&trait_item.generics).into()); match trait_item.kind { Method(ref sig, _) => { let tcx = self.tcx; @@ -753,7 +768,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { use self::hir::ImplItemKind::*; - self.missing_named_lifetime_spots.push(&impl_item.generics); + self.missing_named_lifetime_spots.push((&impl_item.generics).into()); match impl_item.kind { Method(ref sig, _) => { let tcx = self.tcx; @@ -953,6 +968,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { ) { debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref); + let should_pop_missing_lt = self.is_trait_ref_fn_scope(trait_ref); if !self.trait_ref_hack || trait_ref.bound_generic_params.iter().any(|param| match param.kind { GenericParamKind::Lifetime { .. } => true, @@ -988,10 +1004,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { self.with(scope, |old_scope, this| { this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params); walk_list!(this, visit_generic_param, trait_ref.bound_generic_params); - this.visit_trait_ref(&trait_ref.trait_ref) + this.visit_trait_ref(&trait_ref.trait_ref); }) } else { - self.visit_trait_ref(&trait_ref.trait_ref) + self.visit_trait_ref(&trait_ref.trait_ref); + } + if should_pop_missing_lt { + self.missing_named_lifetime_spots.pop(); } } } @@ -1824,29 +1843,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { self.insert_lifetime(lifetime_ref, def); } else { - let mut err = struct_span_err!( - self.tcx.sess, - lifetime_ref.span, - E0261, - "use of undeclared lifetime name `{}`", - lifetime_ref - ); - err.span_label(lifetime_ref.span, "undeclared lifetime"); - if !self.is_in_fn_syntax { - for generics in &self.missing_named_lifetime_spots { - let (span, sugg) = match &generics.params { - [] => (generics.span, format!("<{}>", lifetime_ref)), - [param, ..] => (param.span.shrink_to_lo(), format!("{}, ", lifetime_ref)), - }; - err.span_suggestion( - span, - &format!("consider introducing lifetime `{}` here", lifetime_ref), - sugg, - Applicability::MaybeIncorrect, - ); - } - } - err.emit(); + self.emit_undeclared_lifetime_error(lifetime_ref); } } @@ -2230,6 +2227,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { index: i, lifetime_count: gather.lifetimes.len(), have_bound_regions: gather.have_bound_regions, + span: input.span, } }) .collect(); @@ -2385,7 +2383,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } }; - let mut err = report_missing_lifetime_specifiers(self.tcx.sess, span, lifetime_refs.len()); + let mut err = self.report_missing_lifetime_specifiers(span, lifetime_refs.len()); let mut add_label = true; if let Some(params) = error { @@ -2394,13 +2392,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } if add_label { - add_missing_lifetime_specifiers_label( + self.add_missing_lifetime_specifiers_label( &mut err, span, lifetime_refs.len(), &lifetime_names, - self.tcx.sess.source_map().span_to_snippet(span).ok().as_ref().map(|s| s.as_str()), - &self.missing_named_lifetime_spots, + error.map(|p| &p[..]).unwrap_or(&[]), ); } @@ -2442,8 +2439,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let elided_len = elided_params.len(); for (i, info) in elided_params.into_iter().enumerate() { - let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions } = info; + let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions, span } = + info; + db.span_label(span, ""); let help_name = if let Some(ident) = parent.and_then(|body| self.tcx.hir().body(body).params[index].pat.simple_ident()) { @@ -2477,7 +2476,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { if len == 0 { db.help( "this function's return type contains a borrowed value, \ - but there is no value for it to be borrowed from", + but there is no value for it to be borrowed from", ); self.suggest_lifetime(db, span, "consider giving it a 'static lifetime") } else if elided_len == 0 { @@ -2491,14 +2490,14 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } else if elided_len == 1 { db.help(&format!( "this function's return type contains a borrowed value, \ - but the signature does not say which {} it is borrowed from", + but the signature does not say which {} it is borrowed from", m )); true } else { db.help(&format!( "this function's return type contains a borrowed value, \ - but the signature does not say whether it is borrowed from {}", + but the signature does not say whether it is borrowed from {}", m )); true diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 3f436a1e27c..5ce81c104e1 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -358,7 +358,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { decl: &'l ast::FnDecl, header: &'l ast::FnHeader, ty_params: &'l ast::Generics, - body: &'l ast::Block, + body: Option<&'l ast::Block>, ) { let hir_id = self.tcx.hir().node_to_hir_id(item.id); self.nest_tables(item.id, |v| { @@ -392,7 +392,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { } } - v.visit_block(&body); + walk_list!(v, visit_block, body); }); } @@ -1291,7 +1291,7 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> { } } Fn(ref sig, ref ty_params, ref body) => { - self.process_fn(item, &sig.decl, &sig.header, ty_params, &body) + self.process_fn(item, &sig.decl, &sig.header, ty_params, body.as_deref()) } Static(ref typ, _, ref expr) => self.process_static_or_const_item(item, typ, expr), Const(ref typ, ref expr) => self.process_static_or_const_item(item, &typ, &expr), @@ -1515,7 +1515,8 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> { let access = access_from!(self.save_ctxt, item, hir_id); match item.kind { - ast::ForeignItemKind::Fn(ref decl, ref generics) => { + ast::ForeignItemKind::Fn(ref sig, ref generics, _) => { + let decl = &sig.decl; if let Some(fn_data) = self.save_ctxt.get_extern_item_data(item) { down_cast_data!(fn_data, DefData, item.span); diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 89054441fa3..e32f4744366 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -133,7 +133,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { self.tcx.def_path_str(self.tcx.hir().local_def_id_from_node_id(item.id)) ); match item.kind { - ast::ForeignItemKind::Fn(ref decl, ref generics) => { + ast::ForeignItemKind::Fn(ref sig, ref generics, _) => { filter!(self.span_utils, item.ident.span); Some(Data::DefData(Def { @@ -142,7 +142,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { span: self.span_from_span(item.ident.span), name: item.ident.to_string(), qualname, - value: make_signature(decl, generics), + value: make_signature(&sig.decl, generics), parent: None, children: vec![], decl_id: None, diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index dbf29b6531d..6401cabdcd5 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -723,7 +723,8 @@ impl Sig for ast::ForeignItem { fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext<'_, '_>) -> Result { let id = Some(self.id); match self.kind { - ast::ForeignItemKind::Fn(ref decl, ref generics) => { + ast::ForeignItemKind::Fn(ref sig, ref generics, _) => { + let decl = &sig.decl; let mut text = String::new(); text.push_str("fn "); diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs index 813d14d616d..ad1a6c4906e 100644 --- a/src/librustc_session/config.rs +++ b/src/librustc_session/config.rs @@ -22,8 +22,6 @@ use rustc_span::symbol::{sym, Symbol}; use rustc_errors::emitter::HumanReadableErrorType; use rustc_errors::{ColorConfig, FatalError, Handler, HandlerFlags}; -use getopts; - use std::collections::btree_map::{ Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter, }; @@ -816,7 +814,6 @@ mod opt { #![allow(dead_code)] use super::RustcOptGroup; - use getopts; pub type R = RustcOptGroup; pub type S = &'static str; @@ -1862,7 +1859,6 @@ pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateTy pub mod nightly_options { use super::{ErrorOutputType, OptionStability, RustcOptGroup}; use crate::early_error; - use getopts; use rustc_feature::UnstableFeatures; pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool { diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs index be0e668a467..d6b71641da5 100644 --- a/src/librustc_session/options.rs +++ b/src/librustc_session/options.rs @@ -11,8 +11,6 @@ use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel use rustc_feature::UnstableFeatures; use rustc_span::edition::Edition; -use getopts; - use std::collections::BTreeMap; use std::collections::hash_map::DefaultHasher; diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs index a40d6451b95..70984917d7c 100644 --- a/src/librustc_session/session.rs +++ b/src/librustc_session/session.rs @@ -33,7 +33,6 @@ use rustc_data_structures::jobserver::{self, Client}; use rustc_data_structures::profiling::{SelfProfiler, SelfProfilerRef}; use rustc_target::spec::{PanicStrategy, RelroLevel, Target, TargetTriple}; -use std; use std::cell::{self, RefCell}; use std::env; use std::fmt; @@ -133,6 +132,10 @@ pub struct Session { /// Mapping from ident span to path span for paths that don't exist as written, but that /// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`. pub confused_type_with_std_module: Lock<FxHashMap<Span, Span>>, + + /// Path for libraries that will take preference over libraries shipped by Rust. + /// Used by windows-gnu targets to priortize system mingw-w64 libraries. + pub system_library_path: OneThread<RefCell<Option<Option<PathBuf>>>>, } pub struct PerfStats { @@ -1069,6 +1072,7 @@ fn build_session_( driver_lint_caps, trait_methods_not_found: Lock::new(Default::default()), confused_type_with_std_module: Lock::new(Default::default()), + system_library_path: OneThread::new(RefCell::new(Default::default())), }; validate_commandline_args_with_session_available(&sess); diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index e4f8b5a0143..c060e8948e3 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -755,8 +755,13 @@ symbols! { u64, u8, unboxed_closures, + unchecked_add, + unchecked_div, + unchecked_mul, + unchecked_rem, unchecked_shl, unchecked_shr, + unchecked_sub, underscore_const_names, underscore_imports, underscore_lifetimes, diff --git a/src/librustc_ty/ty.rs b/src/librustc_ty/ty.rs index 9f867cf8ab4..aa05165e3de 100644 --- a/src/librustc_ty/ty.rs +++ b/src/librustc_ty/ty.rs @@ -206,6 +206,14 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] { } } +fn associated_items<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::AssocItemsIterator<'tcx> { + ty::AssocItemsIterator { + items: tcx.arena.alloc_from_iter( + tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did)), + ), + } +} + fn def_span(tcx: TyCtxt<'_>, def_id: DefId) -> Span { tcx.hir().span_if_local(def_id).unwrap() } @@ -356,6 +364,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { asyncness, associated_item, associated_item_def_ids, + associated_items, adt_sized_constraint, def_span, param_env, diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index c2123876b67..6bd120d818d 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1307,12 +1307,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ); } }; + // FIXME: point at the type params that don't have appropriate lifetimes: + // struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F); + // ---- ---- ^^^^^^^ struct_span_err!( tcx.sess, binding.span, E0582, "binding for associated type `{}` references lifetime `{}`, \ - which does not appear in the trait input types", + which does not appear in the trait input types", binding.item_name, br_name ) @@ -1438,10 +1441,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Expand trait aliases recursively and check that only one regular (non-auto) trait // is used and no 'maybe' bounds are used. - let expanded_traits = traits::expand_trait_aliases( - tcx, - bounds.trait_bounds.iter().map(|&(a, b, _)| (a.clone(), b)), - ); + let expanded_traits = + traits::expand_trait_aliases(tcx, bounds.trait_bounds.iter().map(|&(a, b, _)| (a, b))); let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id())); if regular_traits.len() > 1 { diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index e4dec97183c..d436733d19a 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -250,8 +250,8 @@ pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Spa ) .span_label(span, "deref recursion limit reached") .help(&format!( - "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", - suggested_limit + "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)", + suggested_limit, tcx.crate_name, )) .emit(); } diff --git a/src/librustc_typeck/variance/mod.rs b/src/librustc_typeck/variance/mod.rs index 27dc03bbbe2..32bd7e4c4c1 100644 --- a/src/librustc_typeck/variance/mod.rs +++ b/src/librustc_typeck/variance/mod.rs @@ -3,7 +3,6 @@ //! //! [rustc guide]: https://rust-lang.github.io/rustc-guide/variance.html -use arena; use hir::Node; use rustc::ty::query::Providers; use rustc::ty::{self, CrateVariancesMap, TyCtxt}; diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index e110545c6f2..356660763a7 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -16,7 +16,6 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; -use rustc_span; use rustc_span::symbol::{kw, sym, Symbol}; use std::mem; diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 22f5d0dc2c0..1b776930d7a 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -3,7 +3,6 @@ use std::ffi::OsStr; use std::fmt; use std::path::PathBuf; -use getopts; use rustc::lint::Level; use rustc::session; use rustc::session::config::{ @@ -13,7 +12,6 @@ use rustc::session::config::{ use rustc::session::config::{parse_crate_types_from_list, parse_externs, CrateType}; use rustc::session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs}; use rustc::session::search_paths::SearchPath; -use rustc_driver; use rustc_span::edition::{Edition, DEFAULT_EDITION}; use rustc_target::spec::TargetTriple; diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index a8baa89c6f1..429988db9d8 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -11,7 +11,6 @@ use rustc_hir::def::Namespace::TypeNS; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; use rustc_hir::HirId; use rustc_interface::interface; -use rustc_lint; use rustc_resolve as resolve; use rustc_session::lint; diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index c6706413942..6a23b230e12 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -73,8 +73,6 @@ use crate::html::markdown::{self, ErrorCodes, IdMap, Markdown, MarkdownHtml, Mar use crate::html::sources; use crate::html::{highlight, layout, static_files}; -use minifier; - #[cfg(test)] mod tests; @@ -3629,14 +3627,7 @@ fn render_impl( for it in &i.inner_impl().items { if let clean::TypedefItem(ref tydef, _) = it.inner { write!(w, "<span class=\"where fmt-newline\"> "); - assoc_type( - w, - it, - &vec![], - Some(&tydef.type_), - AssocItemLink::Anchor(None), - "", - ); + assoc_type(w, it, &[], Some(&tydef.type_), AssocItemLink::Anchor(None), ""); write!(w, ";</span>"); } } diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 912a40722b8..a37efc22c93 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -5,7 +5,6 @@ use std::path::PathBuf; use rustc_feature::UnstableFeatures; use rustc_span::edition::Edition; use rustc_span::source_map::DUMMY_SP; -use testing; use crate::config::{Options, RenderOptions}; use crate::externalfiles::{load_string, LoadStringError}; diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 50d5f70f488..332d19fbfae 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -13,7 +13,6 @@ use rustc_hir::def_id::DefId; use rustc_resolve::ParentScope; use rustc_span::symbol::Symbol; use rustc_span::DUMMY_SP; -use syntax; use syntax::ast::{self, Ident}; use std::ops::Range; diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 936f63975a5..556dab302b8 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -20,7 +20,6 @@ use std::str; use syntax::ast; use syntax::with_globals; use tempfile::Builder as TempFileBuilder; -use testing; use crate::clean::Attributes; use crate::config::Options; @@ -282,7 +281,7 @@ fn run_test( for debugging_option_str in &options.debugging_options_strs { compiler.arg("-Z").arg(&debugging_option_str); } - if no_run { + if no_run && !compile_fail { compiler.arg("--emit=metadata"); } compiler.arg("--target").arg(target.to_string()); diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 6739d4498a6..8862226adbb 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -198,7 +198,7 @@ impl<R> BufReader<R> { /// Ok(()) /// } /// ``` - #[unstable(feature = "buffered_io_capacity", issue = "68558")] + #[unstable(feature = "buffered_io_capacity", issue = "68833")] pub fn capacity(&self) -> usize { self.buf.len() } @@ -616,7 +616,7 @@ impl<W: Write> BufWriter<W> { /// // Calculate how many bytes can be written without flushing /// let without_flush = capacity - buf_writer.buffer().len(); /// ``` - #[unstable(feature = "buffered_io_capacity", issue = "68558")] + #[unstable(feature = "buffered_io_capacity", issue = "68833")] pub fn capacity(&self) -> usize { self.buf.capacity() } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 806f868ff24..f9c9f224730 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -334,12 +334,6 @@ extern crate libc; #[allow(unused_extern_crates)] extern crate unwind; -// Only needed for now for the `std_detect` module until that crate changes to -// use `cfg_if::cfg_if!` -#[macro_use] -#[cfg(not(test))] -extern crate cfg_if; - // During testing, this crate is not actually the "real" std library, but rather // it links to the real std library, which was compiled from this same source // code. So any lang items std defines are conditionally excluded (or else they diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs index 23104419978..6707f790cab 100644 --- a/src/libstd/sys/unix/time.rs +++ b/src/libstd/sys/unix/time.rs @@ -282,7 +282,6 @@ mod inner { (cfg!(target_os = "linux") && cfg!(target_arch = "x86_64")) || (cfg!(target_os = "linux") && cfg!(target_arch = "x86")) || cfg!(target_os = "fuchsia") - || false // last clause, used so `||` is always trailing above } pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> { diff --git a/src/libstd/tests/run-time-detect.rs b/src/libstd/tests/run-time-detect.rs index e39cc1eed5e..2e6d1bc8efd 100644 --- a/src/libstd/tests/run-time-detect.rs +++ b/src/libstd/tests/run-time-detect.rs @@ -6,6 +6,7 @@ all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")), all(target_arch = "powerpc", target_os = "linux"), all(target_arch = "powerpc64", target_os = "linux"), + any(target_arch = "x86", target_arch = "x86_64"), ), feature(stdsimd) )] diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 5a8c9f76ea9..b22406124e0 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2533,6 +2533,17 @@ pub struct FnHeader { pub ext: Extern, } +impl FnHeader { + /// Does this function header have any qualifiers or is it empty? + pub fn has_qualifiers(&self) -> bool { + let Self { unsafety, asyncness, constness, ext } = self; + matches!(unsafety, Unsafety::Unsafe) + || asyncness.node.is_async() + || matches!(constness.node, Constness::Const) + || !matches!(ext, Extern::None) + } +} + impl Default for FnHeader { fn default() -> FnHeader { FnHeader { @@ -2565,7 +2576,7 @@ pub enum ItemKind { /// A function declaration (`fn`). /// /// E.g., `fn foo(bar: usize) -> usize { .. }`. - Fn(FnSig, Generics, P<Block>), + Fn(FnSig, Generics, Option<P<Block>>), /// A module declaration (`mod`). /// /// E.g., `mod foo;` or `mod foo { .. }`. @@ -2667,7 +2678,7 @@ pub type ForeignItem = Item<ForeignItemKind>; #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub enum ForeignItemKind { /// A foreign function. - Fn(P<FnDecl>, Generics), + Fn(FnSig, Generics, Option<P<Block>>), /// A foreign static item (`static ext: u8`). Static(P<Ty>, Mutability), /// A foreign type. diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 3bcdf8fe286..8517f223f92 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -901,7 +901,7 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) { ItemKind::Fn(sig, generics, body) => { visit_fn_sig(sig, vis); vis.visit_generics(generics); - vis.visit_block(body); + visit_opt(body, |body| vis.visit_block(body)); } ItemKind::Mod(m) => vis.visit_mod(m), ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm), @@ -1044,9 +1044,10 @@ pub fn noop_flat_map_foreign_item<T: MutVisitor>( visitor.visit_ident(ident); visit_attrs(attrs, visitor); match kind { - ForeignItemKind::Fn(fdec, generics) => { - visitor.visit_fn_decl(fdec); + ForeignItemKind::Fn(sig, generics, body) => { + visit_fn_sig(sig, visitor); visitor.visit_generics(generics); + visit_opt(body, |body| visitor.visit_block(body)); } ForeignItemKind::Static(t, _m) => visitor.visit_ty(t), ForeignItemKind::Ty => {} diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 946a0d29cd3..73e731397c3 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -19,24 +19,47 @@ use crate::tokenstream::{TokenStream, TokenTree}; use rustc_span::Span; +#[derive(Copy, Clone, PartialEq)] +pub enum AssocCtxt { + Trait, + Impl, +} + +#[derive(Copy, Clone, PartialEq)] +pub enum FnCtxt { + Free, + Foreign, + Assoc(AssocCtxt), +} + #[derive(Copy, Clone)] pub enum FnKind<'a> { - /// E.g., `fn foo()` or `extern "Abi" fn foo()`. - ItemFn(Ident, &'a FnHeader, &'a Visibility, &'a Block), - - /// E.g., `fn foo(&self)`. - Method(Ident, &'a FnSig, &'a Visibility, &'a Block), + /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`. + Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, Option<&'a Block>), /// E.g., `|x, y| body`. - Closure(&'a Expr), + Closure(&'a FnDecl, &'a Expr), } impl<'a> FnKind<'a> { pub fn header(&self) -> Option<&'a FnHeader> { match *self { - FnKind::ItemFn(_, header, _, _) => Some(header), - FnKind::Method(_, sig, _, _) => Some(&sig.header), - FnKind::Closure(_) => None, + FnKind::Fn(_, _, sig, _, _) => Some(&sig.header), + FnKind::Closure(_, _) => None, + } + } + + pub fn decl(&self) -> &'a FnDecl { + match self { + FnKind::Fn(_, _, sig, _, _) => &sig.decl, + FnKind::Closure(decl, _) => decl, + } + } + + pub fn ctxt(&self) -> Option<FnCtxt> { + match self { + FnKind::Fn(ctxt, ..) => Some(*ctxt), + FnKind::Closure(..) => None, } } } @@ -106,17 +129,11 @@ pub trait Visitor<'ast>: Sized { fn visit_where_predicate(&mut self, p: &'ast WherePredicate) { walk_where_predicate(self, p) } - fn visit_fn(&mut self, fk: FnKind<'ast>, fd: &'ast FnDecl, s: Span, _: NodeId) { - walk_fn(self, fk, fd, s) - } - fn visit_trait_item(&mut self, i: &'ast AssocItem) { - walk_trait_item(self, i) + fn visit_fn(&mut self, fk: FnKind<'ast>, s: Span, _: NodeId) { + walk_fn(self, fk, s) } - fn visit_impl_item(&mut self, i: &'ast AssocItem) { - walk_impl_item(self, i) - } - fn visit_assoc_item(&mut self, i: &'ast AssocItem) { - walk_assoc_item(self, i) + fn visit_assoc_item(&mut self, i: &'ast AssocItem, ctxt: AssocCtxt) { + walk_assoc_item(self, i, ctxt) } fn visit_trait_ref(&mut self, t: &'ast TraitRef) { walk_trait_ref(self, t) @@ -287,13 +304,8 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { } ItemKind::Fn(ref sig, ref generics, ref body) => { visitor.visit_generics(generics); - visitor.visit_fn_header(&sig.header); - visitor.visit_fn( - FnKind::ItemFn(item.ident, &sig.header, &item.vis, body), - &sig.decl, - item.span, - item.id, - ) + let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref()); + visitor.visit_fn(kind, item.span, item.id) } ItemKind::Mod(ref module) => visitor.visit_mod(module, item.span, &item.attrs, item.id), ItemKind::ForeignMod(ref foreign_module) => { @@ -321,17 +333,17 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { visitor.visit_generics(generics); walk_list!(visitor, visit_trait_ref, of_trait); visitor.visit_ty(self_ty); - walk_list!(visitor, visit_impl_item, items); + walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Impl); } ItemKind::Struct(ref struct_definition, ref generics) | ItemKind::Union(ref struct_definition, ref generics) => { visitor.visit_generics(generics); visitor.visit_variant_data(struct_definition); } - ItemKind::Trait(.., ref generics, ref bounds, ref methods) => { + ItemKind::Trait(.., ref generics, ref bounds, ref items) => { visitor.visit_generics(generics); walk_list!(visitor, visit_param_bound, bounds); - walk_list!(visitor, visit_trait_item, methods); + walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Trait); } ItemKind::TraitAlias(ref generics, ref bounds) => { visitor.visit_generics(generics); @@ -512,21 +524,22 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) { } } -pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, foreign_item: &'a ForeignItem) { - visitor.visit_vis(&foreign_item.vis); - visitor.visit_ident(foreign_item.ident); +pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignItem) { + visitor.visit_vis(&item.vis); + visitor.visit_ident(item.ident); - match foreign_item.kind { - ForeignItemKind::Fn(ref function_declaration, ref generics) => { - walk_fn_decl(visitor, function_declaration); - visitor.visit_generics(generics) + match item.kind { + ForeignItemKind::Fn(ref sig, ref generics, ref body) => { + visitor.visit_generics(generics); + let kind = FnKind::Fn(FnCtxt::Foreign, item.ident, sig, &item.vis, body.as_deref()); + visitor.visit_fn(kind, item.span, item.id); } ForeignItemKind::Static(ref typ, _) => visitor.visit_ty(typ), ForeignItemKind::Ty => (), ForeignItemKind::Macro(ref mac) => visitor.visit_mac(mac), } - walk_list!(visitor, visit_attribute, &foreign_item.attrs); + walk_list!(visitor, visit_attribute, &item.attrs); } pub fn walk_global_asm<'a, V: Visitor<'a>>(_: &mut V, _: &'a GlobalAsm) { @@ -594,37 +607,21 @@ pub fn walk_fn_decl<'a, V: Visitor<'a>>(visitor: &mut V, function_declaration: & visitor.visit_fn_ret_ty(&function_declaration.output); } -pub fn walk_fn<'a, V>(visitor: &mut V, kind: FnKind<'a>, declaration: &'a FnDecl, _span: Span) -where - V: Visitor<'a>, -{ +pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>, _span: Span) { match kind { - FnKind::ItemFn(_, header, _, body) => { - visitor.visit_fn_header(header); - walk_fn_decl(visitor, declaration); - visitor.visit_block(body); - } - FnKind::Method(_, sig, _, body) => { + FnKind::Fn(_, _, sig, _, body) => { visitor.visit_fn_header(&sig.header); - walk_fn_decl(visitor, declaration); - visitor.visit_block(body); + walk_fn_decl(visitor, &sig.decl); + walk_list!(visitor, visit_block, body); } - FnKind::Closure(body) => { - walk_fn_decl(visitor, declaration); + FnKind::Closure(decl, body) => { + walk_fn_decl(visitor, decl); visitor.visit_expr(body); } } } -pub fn walk_impl_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem) { - visitor.visit_assoc_item(item); -} - -pub fn walk_trait_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem) { - visitor.visit_assoc_item(item); -} - -pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem) { +pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem, ctxt: AssocCtxt) { visitor.visit_vis(&item.vis); visitor.visit_ident(item.ident); walk_list!(visitor, visit_attribute, &item.attrs); @@ -634,17 +631,9 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem) visitor.visit_ty(ty); walk_list!(visitor, visit_expr, expr); } - AssocItemKind::Fn(ref sig, None) => { - visitor.visit_fn_header(&sig.header); - walk_fn_decl(visitor, &sig.decl); - } - AssocItemKind::Fn(ref sig, Some(ref body)) => { - visitor.visit_fn( - FnKind::Method(item.ident, sig, &item.vis, body), - &sig.decl, - item.span, - item.id, - ); + AssocItemKind::Fn(ref sig, ref body) => { + let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), item.ident, sig, &item.vis, body.as_deref()); + visitor.visit_fn(kind, item.span, item.id); } AssocItemKind::TyAlias(ref bounds, ref ty) => { walk_list!(visitor, visit_param_bound, bounds); @@ -765,8 +754,9 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { visitor.visit_expr(subexpression); walk_list!(visitor, visit_arm, arms); } - ExprKind::Closure(_, _, _, ref function_declaration, ref body, _decl_span) => visitor - .visit_fn(FnKind::Closure(body), function_declaration, expression.span, expression.id), + ExprKind::Closure(_, _, _, ref decl, ref body, _decl_span) => { + visitor.visit_fn(FnKind::Closure(decl, body), expression.span, expression.id) + } ExprKind::Block(ref block, ref opt_label) => { walk_list!(visitor, visit_label, opt_label); visitor.visit_block(block); diff --git a/src/libtest/cli.rs b/src/libtest/cli.rs index edff8bea0f3..778600b2196 100644 --- a/src/libtest/cli.rs +++ b/src/libtest/cli.rs @@ -1,6 +1,5 @@ //! Module converting command-line arguments into test configuration. -use getopts; use std::env; use std::path::PathBuf; diff --git a/src/libtest/console.rs b/src/libtest/console.rs index ebdfb162947..149c9202e6e 100644 --- a/src/libtest/console.rs +++ b/src/libtest/console.rs @@ -4,8 +4,6 @@ use std::fs::File; use std::io; use std::io::prelude::Write; -use term; - use super::{ bench::fmt_bench_samples, cli::TestOpts, diff --git a/src/stdarch b/src/stdarch -Subproject e0ab2c165ace03a61139b61f1d9b86b07028850 +Subproject dea57529b3695605909e7d327bb6551d7a10c78 diff --git a/src/test/ui/async-await/issues/issue-63388-2.nll.stderr b/src/test/ui/async-await/issues/issue-63388-2.nll.stderr index 7781af89dea..6edb9e63d48 100644 --- a/src/test/ui/async-await/issues/issue-63388-2.nll.stderr +++ b/src/test/ui/async-await/issues/issue-63388-2.nll.stderr @@ -1,6 +1,8 @@ error[E0106]: missing lifetime specifier --> $DIR/issue-63388-2.rs:12:10 | +LL | foo: &dyn Foo, bar: &'a dyn Foo + | -------- ----------- LL | ) -> &dyn Foo | ^ help: consider using the named lifetime: `&'a` | diff --git a/src/test/ui/async-await/issues/issue-63388-2.stderr b/src/test/ui/async-await/issues/issue-63388-2.stderr index 7e45d588c6c..9f51ced9c3f 100644 --- a/src/test/ui/async-await/issues/issue-63388-2.stderr +++ b/src/test/ui/async-await/issues/issue-63388-2.stderr @@ -1,6 +1,8 @@ error[E0106]: missing lifetime specifier --> $DIR/issue-63388-2.rs:12:10 | +LL | foo: &dyn Foo, bar: &'a dyn Foo + | -------- ----------- LL | ) -> &dyn Foo | ^ help: consider using the named lifetime: `&'a` | diff --git a/src/test/ui/coherence/coherence-conflicting-negative-trait-impl.rs b/src/test/ui/coherence/coherence-conflicting-negative-trait-impl.rs index 66d0958e4c9..b4f5f9ef56b 100644 --- a/src/test/ui/coherence/coherence-conflicting-negative-trait-impl.rs +++ b/src/test/ui/coherence/coherence-conflicting-negative-trait-impl.rs @@ -1,6 +1,7 @@ #![feature(optin_builtin_traits)] -#![feature(overlapping_marker_traits)] +#![feature(marker_trait_attr)] +#[marker] trait MyTrait {} struct TestType<T>(::std::marker::PhantomData<T>); @@ -8,11 +9,11 @@ struct TestType<T>(::std::marker::PhantomData<T>); unsafe impl<T: MyTrait+'static> Send for TestType<T> {} impl<T: MyTrait> !Send for TestType<T> {} -//~^ ERROR E0119 +//~^ ERROR conflicting implementations unsafe impl<T:'static> Send for TestType<T> {} +//~^ ERROR conflicting implementations impl !Send for TestType<i32> {} -//~^ ERROR E0119 fn main() {} diff --git a/src/test/ui/coherence/coherence-conflicting-negative-trait-impl.stderr b/src/test/ui/coherence/coherence-conflicting-negative-trait-impl.stderr index 0a8bbc4bc50..25d3d3ee997 100644 --- a/src/test/ui/coherence/coherence-conflicting-negative-trait-impl.stderr +++ b/src/test/ui/coherence/coherence-conflicting-negative-trait-impl.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `std::marker::Send` for type `TestType<_>`: - --> $DIR/coherence-conflicting-negative-trait-impl.rs:10:1 + --> $DIR/coherence-conflicting-negative-trait-impl.rs:11:1 | LL | unsafe impl<T: MyTrait+'static> Send for TestType<T> {} | ---------------------------------------------------- first implementation here @@ -7,14 +7,14 @@ LL | LL | impl<T: MyTrait> !Send for TestType<T> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `TestType<_>` -error[E0119]: conflicting implementations of trait `std::marker::Send` for type `TestType<i32>`: - --> $DIR/coherence-conflicting-negative-trait-impl.rs:15:1 +error[E0119]: conflicting implementations of trait `std::marker::Send` for type `TestType<_>`: + --> $DIR/coherence-conflicting-negative-trait-impl.rs:14:1 | +LL | unsafe impl<T: MyTrait+'static> Send for TestType<T> {} + | ---------------------------------------------------- first implementation here +... LL | unsafe impl<T:'static> Send for TestType<T> {} - | ------------------------------------------- first implementation here -LL | -LL | impl !Send for TestType<i32> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `TestType<i32>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `TestType<_>` error: aborting due to 2 previous errors diff --git a/src/test/ui/coherence/coherence-impls-send.rs b/src/test/ui/coherence/coherence-impls-send.rs index b2a9c5be658..7898dc9831d 100644 --- a/src/test/ui/coherence/coherence-impls-send.rs +++ b/src/test/ui/coherence/coherence-impls-send.rs @@ -1,5 +1,4 @@ #![feature(optin_builtin_traits)] -#![feature(overlapping_marker_traits)] use std::marker::Copy; @@ -24,7 +23,8 @@ unsafe impl Send for [MyType] {} //~^ ERROR E0117 unsafe impl Send for &'static [NotSync] {} -//~^ ERROR E0117 +//~^ ERROR conflicting implementations of trait +//~| ERROR only traits defined in the current crate fn main() { } diff --git a/src/test/ui/coherence/coherence-impls-send.stderr b/src/test/ui/coherence/coherence-impls-send.stderr index a5b3c7657bd..dbfc968332c 100644 --- a/src/test/ui/coherence/coherence-impls-send.stderr +++ b/src/test/ui/coherence/coherence-impls-send.stderr @@ -1,5 +1,16 @@ +error[E0119]: conflicting implementations of trait `std::marker::Send` for type `&[NotSync]`: + --> $DIR/coherence-impls-send.rs:25:1 + | +LL | unsafe impl Send for &'static [NotSync] {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: conflicting implementation in crate `core`: + - impl<T> std::marker::Send for &T + where T: std::marker::Sync, T: ?Sized; + = note: upstream crates may add a new impl of trait `std::marker::Sync` for type `[NotSync]` in future versions + error[E0117]: only traits defined in the current crate can be implemented for arbitrary types - --> $DIR/coherence-impls-send.rs:17:1 + --> $DIR/coherence-impls-send.rs:16:1 | LL | unsafe impl Send for (MyType, MyType) {} | ^^^^^^^^^^^^^^^^^^^^^---------------- @@ -10,13 +21,13 @@ LL | unsafe impl Send for (MyType, MyType) {} = note: define and implement a trait or new type instead error[E0321]: cross-crate traits with a default impl, like `std::marker::Send`, can only be implemented for a struct/enum type, not `&'static NotSync` - --> $DIR/coherence-impls-send.rs:20:1 + --> $DIR/coherence-impls-send.rs:19:1 | LL | unsafe impl Send for &'static NotSync {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type error[E0117]: only traits defined in the current crate can be implemented for arbitrary types - --> $DIR/coherence-impls-send.rs:23:1 + --> $DIR/coherence-impls-send.rs:22:1 | LL | unsafe impl Send for [MyType] {} | ^^^^^^^^^^^^^^^^^^^^^-------- @@ -27,7 +38,7 @@ LL | unsafe impl Send for [MyType] {} = note: define and implement a trait or new type instead error[E0117]: only traits defined in the current crate can be implemented for arbitrary types - --> $DIR/coherence-impls-send.rs:26:1 + --> $DIR/coherence-impls-send.rs:25:1 | LL | unsafe impl Send for &'static [NotSync] {} | ^^^^^^^^^^^^^^^^^^^^^------------------ @@ -37,7 +48,7 @@ LL | unsafe impl Send for &'static [NotSync] {} | = note: define and implement a trait or new type instead -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0117, E0321. +Some errors have detailed explanations: E0117, E0119, E0321. For more information about an error, try `rustc --explain E0117`. diff --git a/src/test/ui/consts/const-int-arithmetic.rs b/src/test/ui/consts/const-int-arithmetic.rs new file mode 100644 index 00000000000..cfa2873c68b --- /dev/null +++ b/src/test/ui/consts/const-int-arithmetic.rs @@ -0,0 +1,130 @@ +// run-pass + +#![feature(saturating_neg)] +#![feature(const_checked_int_methods)] +#![feature(const_euclidean_int_methods)] +#![feature(const_overflowing_int_methods)] +#![feature(const_saturating_int_methods)] +#![feature(const_wrapping_int_methods)] + +use std::i8; + +macro_rules! suite { + ($( + $fn:ident -> $ty:ty { $( $label:ident : $expr:expr, $result:expr; )* } + )*) => { $( + fn $fn() { + $( + const $label: $ty = $expr; + assert_eq!($label, $result); + )* + } + )* } +} + +suite!( + checked -> Option<i8> { + // `const_checked_int_methods` + C1: 5i8.checked_add(2), Some(7); + C2: 127i8.checked_add(2), None; + + C3: 5i8.checked_sub(2), Some(3); + C4: (-127i8).checked_sub(2), None; + + C5: 1i8.checked_mul(3), Some(3); + C6: 5i8.checked_mul(122), None; + C7: (-127i8).checked_mul(-99), None; + + C8: (i8::min_value() + 1).checked_div(-1), Some(127); + C9: i8::min_value().checked_div(-1), None; + C10: 1i8.checked_div(0), None; + + C11: 5i8.checked_rem(2), Some(1); + C12: 5i8.checked_rem(0), None; + C13: i8::MIN.checked_rem(-1), None; + + C14: 5i8.checked_neg(), Some(-5); + C15: i8::MIN.checked_neg(), None; + + C16: 0x1i8.checked_shl(4), Some(0x10); + C17: 0x1i8.checked_shl(129), None; + + C18: 0x10i8.checked_shr(4), Some(0x1); + C19: 0x10i8.checked_shr(128), None; + + + C20: (-5i8).checked_abs(), Some(5); + C21: i8::MIN.checked_abs(), None; + + // `const_euclidean_int_methods` + C22: (i8::min_value() + 1).checked_div_euclid(-1), Some(127); + C23: i8::min_value().checked_div_euclid(-1), None; + C24: (1i8).checked_div_euclid(0), None; + + C25: 5i8.checked_rem_euclid(2), Some(1); + C26: 5i8.checked_rem_euclid(0), None; + C27: i8::MIN.checked_rem_euclid(-1), None; + } + + saturating_and_wrapping -> i8 { + // `const_saturating_int_methods` + C28: 100i8.saturating_add(1), 101; + C29: i8::max_value().saturating_add(100), i8::max_value(); + C30: i8::min_value().saturating_add(-1), i8::min_value(); + + C31: 100i8.saturating_sub(127), -27; + C32: i8::min_value().saturating_sub(100), i8::min_value(); + C33: i8::max_value().saturating_sub(-1), i8::max_value(); + + C34: 10i8.saturating_mul(12), 120; + C35: i8::MAX.saturating_mul(10), i8::MAX; + C36: i8::MIN.saturating_mul(10), i8::MIN; + + C37: 100i8.saturating_neg(), -100; + C38: (-100i8).saturating_neg(), 100; + C39: i8::min_value().saturating_neg(), i8::max_value(); + C40: i8::max_value().saturating_neg(), i8::min_value() + 1; + + C57: 100i8.saturating_abs(), 100; + C58: (-100i8).saturating_abs(), 100; + C59: i8::min_value().saturating_abs(), i8::max_value(); + C60: (i8::min_value() + 1).saturating_abs(), i8::max_value(); + + // `const_wrapping_int_methods` + C41: 100i8.wrapping_div(10), 10; + C42: (-128i8).wrapping_div(-1), -128; + + C43: 100i8.wrapping_rem(10), 0; + C44: (-128i8).wrapping_rem(-1), 0; + + // `const_euclidean_int_methods` + C45: 100i8.wrapping_div_euclid(10), 10; + C46: (-128i8).wrapping_div_euclid(-1), -128; + + C47: 100i8.wrapping_rem_euclid(10), 0; + C48: (-128i8).wrapping_rem_euclid(-1), 0; + } + + overflowing -> (i8, bool) { + // `const_overflowing_int_methods` + C49: 5i8.overflowing_div(2), (2, false); + C50: i8::MIN.overflowing_div(-1), (i8::MIN, true); + + C51: 5i8.overflowing_rem(2), (1, false); + C52: i8::MIN.overflowing_rem(-1), (0, true); + + // `const_euclidean_int_methods` + C53: 5i8.overflowing_div_euclid(2), (2, false); + C54: i8::MIN.overflowing_div_euclid(-1), (i8::MIN, true); + + C55: 5i8.overflowing_rem_euclid(2), (1, false); + C56: i8::MIN.overflowing_rem_euclid(-1), (0, true); + + } +); + +fn main() { + checked(); + saturating_and_wrapping(); + overflowing(); +} diff --git a/src/test/ui/did_you_mean/recursion_limit.stderr b/src/test/ui/did_you_mean/recursion_limit.stderr index b05b92bf1e9..fc14b7fa5b7 100644 --- a/src/test/ui/did_you_mean/recursion_limit.stderr +++ b/src/test/ui/did_you_mean/recursion_limit.stderr @@ -7,7 +7,7 @@ LL | fn is_send<T:Send>() { } LL | is_send::<A>(); | ^^^^^^^^^^^^ | - = help: consider adding a `#![recursion_limit="20"]` attribute to your crate + = help: consider adding a `#![recursion_limit="20"]` attribute to your crate (`recursion_limit`) = note: required because it appears within the type `I` = note: required because it appears within the type `H` = note: required because it appears within the type `G` diff --git a/src/test/ui/did_you_mean/recursion_limit_deref.stderr b/src/test/ui/did_you_mean/recursion_limit_deref.stderr index fdbb5af9b32..e8d11530b08 100644 --- a/src/test/ui/did_you_mean/recursion_limit_deref.stderr +++ b/src/test/ui/did_you_mean/recursion_limit_deref.stderr @@ -4,7 +4,7 @@ error[E0055]: reached the recursion limit while auto-dereferencing `I` LL | let x: &Bottom = &t; | ^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="20"]` attribute to your crate + = help: consider adding a `#![recursion_limit="20"]` attribute to your crate (`recursion_limit_deref`) error[E0308]: mismatched types --> $DIR/recursion_limit_deref.rs:50:22 diff --git a/src/test/ui/did_you_mean/recursion_limit_macro.stderr b/src/test/ui/did_you_mean/recursion_limit_macro.stderr index 1cc59051605..18d321c24d8 100644 --- a/src/test/ui/did_you_mean/recursion_limit_macro.stderr +++ b/src/test/ui/did_you_mean/recursion_limit_macro.stderr @@ -7,7 +7,7 @@ LL | ($t:tt $($tail:tt)*) => { recurse!($($tail)*) }; LL | recurse!(0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9); | -------------------------------------------------- in this macro invocation | - = help: consider adding a `#![recursion_limit="20"]` attribute to your crate + = help: consider adding a `#![recursion_limit="20"]` attribute to your crate (`recursion_limit_macro`) error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0055.stderr b/src/test/ui/error-codes/E0055.stderr index d06566ffbe9..01411e585ab 100644 --- a/src/test/ui/error-codes/E0055.stderr +++ b/src/test/ui/error-codes/E0055.stderr @@ -4,7 +4,7 @@ error[E0055]: reached the recursion limit while auto-dereferencing `Foo` LL | ref_foo.foo(); | ^^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="10"]` attribute to your crate + = help: consider adding a `#![recursion_limit="10"]` attribute to your crate (`E0055`) error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0106.stderr b/src/test/ui/error-codes/E0106.stderr index e01e0a6f54b..a23bcbfd71a 100644 --- a/src/test/ui/error-codes/E0106.stderr +++ b/src/test/ui/error-codes/E0106.stderr @@ -6,8 +6,8 @@ LL | x: &bool, | help: consider introducing a named lifetime parameter | -LL | struct Foo<'lifetime> { -LL | x: &'lifetime bool, +LL | struct Foo<'a> { +LL | x: &'a bool, | error[E0106]: missing lifetime specifier @@ -18,9 +18,9 @@ LL | B(&bool), | help: consider introducing a named lifetime parameter | -LL | enum Bar<'lifetime> { +LL | enum Bar<'a> { LL | A(u8), -LL | B(&'lifetime bool), +LL | B(&'a bool), | error[E0106]: missing lifetime specifier @@ -31,8 +31,8 @@ LL | type MyStr = &str; | help: consider introducing a named lifetime parameter | -LL | type MyStr<'lifetime> = &'lifetime str; - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | type MyStr<'a> = &'a str; + | ^^^^ ^^^ error[E0106]: missing lifetime specifier --> $DIR/E0106.rs:17:10 @@ -42,8 +42,8 @@ LL | baz: Baz, | help: consider introducing a named lifetime parameter | -LL | struct Quux<'lifetime> { -LL | baz: Baz<'lifetime>, +LL | struct Quux<'a> { +LL | baz: Baz<'a>, | error[E0106]: missing lifetime specifiers diff --git a/src/test/ui/error-codes/E0275.stderr b/src/test/ui/error-codes/E0275.stderr index 1d087a46594..c551a00096e 100644 --- a/src/test/ui/error-codes/E0275.stderr +++ b/src/test/ui/error-codes/E0275.stderr @@ -7,7 +7,7 @@ LL | trait Foo {} LL | impl<T> Foo for T where Bar<T>: Foo {} | ^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`E0275`) = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` diff --git a/src/test/ui/extern/extern-ffi-fn-with-body.rs b/src/test/ui/extern/extern-ffi-fn-with-body.rs index 4cf563514ea..ef234e8afd8 100644 --- a/src/test/ui/extern/extern-ffi-fn-with-body.rs +++ b/src/test/ui/extern/extern-ffi-fn-with-body.rs @@ -1,5 +1,5 @@ extern "C" { - fn foo() -> i32 { //~ ERROR incorrect `fn` inside `extern` block + fn foo() -> i32 { //~ ERROR incorrect function inside `extern` block return 0; } } diff --git a/src/test/ui/extern/extern-ffi-fn-with-body.stderr b/src/test/ui/extern/extern-ffi-fn-with-body.stderr index 4ac3ce1f93e..079c9cecd8e 100644 --- a/src/test/ui/extern/extern-ffi-fn-with-body.stderr +++ b/src/test/ui/extern/extern-ffi-fn-with-body.stderr @@ -1,17 +1,17 @@ -error: incorrect `fn` inside `extern` block +error: incorrect function inside `extern` block --> $DIR/extern-ffi-fn-with-body.rs:2:8 | LL | extern "C" { - | ------ `extern` blocks define existing foreign functions and `fn`s inside of them cannot have a body + | ---------- `extern` blocks define existing foreign functions and functions inside of them cannot have a body LL | fn foo() -> i32 { | ________^^^__________- | | | - | | can't have a body + | | cannot have a body LL | | return 0; LL | | } - | |_____- this body is invalid here + | |_____- help: remove the invalid body: `;` | - = help: you might have meant to write a function accessible through ffi, which can be done by writing `extern fn` outside of the `extern` block + = help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html error: aborting due to previous error diff --git a/src/test/ui/generic/generic-extern-lifetime.stderr b/src/test/ui/generic/generic-extern-lifetime.stderr index 39372c93158..72951aea4aa 100644 --- a/src/test/ui/generic/generic-extern-lifetime.stderr +++ b/src/test/ui/generic/generic-extern-lifetime.stderr @@ -9,12 +9,24 @@ error[E0261]: use of undeclared lifetime name `'a` | LL | pub fn life4<'b>(x: for<'c> fn(&'a i32)); | ^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the type lifetime-generic with a new `'a` lifetime + | +LL | pub fn life4<'b>(x: for<'c, 'a> fn(&'a i32)); + | ^^^^ error[E0261]: use of undeclared lifetime name `'a` --> $DIR/generic-extern-lifetime.rs:11:38 | LL | pub fn life7<'b>() -> for<'c> fn(&'a i32); | ^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the type lifetime-generic with a new `'a` lifetime + | +LL | pub fn life7<'b>() -> for<'c, 'a> fn(&'a i32); + | ^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr b/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr index 14c53f90665..211a3286cc3 100644 --- a/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr +++ b/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr @@ -6,8 +6,8 @@ LL | type Output = &i32; | help: consider introducing a named lifetime parameter | -LL | type Output<'lifetime> = &'lifetime i32; - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | type Output<'a> = &'a i32; + | ^^^^ ^^^ error[E0106]: missing lifetime specifier --> $DIR/assoc-type.rs:16:20 @@ -17,8 +17,8 @@ LL | type Output = &'_ i32; | help: consider introducing a named lifetime parameter | -LL | type Output<'lifetime> = &'lifetime i32; - | ^^^^^^^^^^^ ^^^^^^^^^ +LL | type Output<'a> = &'a i32; + | ^^^^ ^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr b/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr index 5f101a24c1d..f2a4150632d 100644 --- a/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr +++ b/src/test/ui/in-band-lifetimes/issue-61124-anon-lifetime-in-struct-declaration.stderr @@ -6,8 +6,8 @@ LL | struct Heartbreak(Betrayal); | help: consider introducing a named lifetime parameter | -LL | struct Heartbreak<'lifetime>(Betrayal<'lifetime>); - | ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ +LL | struct Heartbreak<'a>(Betrayal<'a>); + | ^^^^ ^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr b/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr index bfb20ade035..a43b49041ec 100644 --- a/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr +++ b/src/test/ui/in-band-lifetimes/no_introducing_in_band_in_locals.stderr @@ -11,6 +11,16 @@ error[E0261]: use of undeclared lifetime name `'test` | LL | let y: fn(&'test u32) = foo2; | ^^^^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider introducing lifetime `'test` here + | +LL | fn bar<'test>() { + | ^^^^^^^ +help: consider making the type lifetime-generic with a new `'test` lifetime + | +LL | let y: for<'test> fn(&'test u32) = foo2; + | ^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/infinite/infinite-autoderef.stderr b/src/test/ui/infinite/infinite-autoderef.stderr index 8c59fbd5301..e7d90f00d24 100644 --- a/src/test/ui/infinite/infinite-autoderef.stderr +++ b/src/test/ui/infinite/infinite-autoderef.stderr @@ -13,7 +13,7 @@ error[E0055]: reached the recursion limit while auto-dereferencing `Foo` LL | Foo.foo; | ^^^^^^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`infinite_autoderef`) error[E0055]: reached the recursion limit while auto-dereferencing `Foo` --> $DIR/infinite-autoderef.rs:25:9 @@ -21,7 +21,7 @@ error[E0055]: reached the recursion limit while auto-dereferencing `Foo` LL | Foo.foo; | ^^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`infinite_autoderef`) error[E0609]: no field `foo` on type `Foo` --> $DIR/infinite-autoderef.rs:25:9 @@ -35,7 +35,7 @@ error[E0055]: reached the recursion limit while auto-dereferencing `Foo` LL | Foo.bar(); | ^^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`infinite_autoderef`) error[E0599]: no method named `bar` found for struct `Foo` in the current scope --> $DIR/infinite-autoderef.rs:26:9 diff --git a/src/test/ui/infinite/infinite-macro-expansion.stderr b/src/test/ui/infinite/infinite-macro-expansion.stderr index 159312e5c1b..ff67eea5688 100644 --- a/src/test/ui/infinite/infinite-macro-expansion.stderr +++ b/src/test/ui/infinite/infinite-macro-expansion.stderr @@ -7,7 +7,7 @@ LL | () => (recursive!()) LL | recursive!() | ------------ in this macro invocation | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`infinite_macro_expansion`) error: aborting due to previous error diff --git a/src/test/ui/issues/issue-16098.stderr b/src/test/ui/issues/issue-16098.stderr index 2b9657d4628..a34039a6eec 100644 --- a/src/test/ui/issues/issue-16098.stderr +++ b/src/test/ui/issues/issue-16098.stderr @@ -7,7 +7,7 @@ LL | $n + prob1!($n - 1); LL | println!("Problem 1: {}", prob1!(1000)); | ------------ in this macro invocation | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_16098`) error: aborting due to previous error diff --git a/src/test/ui/issues/issue-18400.stderr b/src/test/ui/issues/issue-18400.stderr index 85cfa5663f1..57067ad5175 100644 --- a/src/test/ui/issues/issue-18400.stderr +++ b/src/test/ui/issues/issue-18400.stderr @@ -4,7 +4,7 @@ error[E0275]: overflow evaluating the requirement `_: std::marker::Sized` LL | 0.contains(bits); | ^^^^^^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_18400`) = note: required because of the requirements on the impl of `Set<&[_]>` for `{integer}` = note: required because of the requirements on the impl of `Set<&[&[_]]>` for `{integer}` = note: required because of the requirements on the impl of `Set<&[&[&[_]]]>` for `{integer}` diff --git a/src/test/ui/issues/issue-19707.stderr b/src/test/ui/issues/issue-19707.stderr index 8a627bc0bd4..337f2f971ed 100644 --- a/src/test/ui/issues/issue-19707.stderr +++ b/src/test/ui/issues/issue-19707.stderr @@ -2,25 +2,35 @@ error[E0106]: missing lifetime specifier --> $DIR/issue-19707.rs:3:28 | LL | type Foo = fn(&u8, &u8) -> &u8; - | ^ expected named lifetime parameter + | --- --- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the type lifetime-generic with a new `'a` lifetime + | +LL | type Foo = for<'a> fn(&'a u8, &'a u8) -> &'a u8; + | ^^^^^^^ ^^^^^^ ^^^^^^ ^^^ help: consider introducing a named lifetime parameter | -LL | type Foo<'lifetime> = fn(&u8, &u8) -> &'lifetime u8; - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | type Foo<'a> = fn(&'a u8, &'a u8) -> &'a u8; + | ^^^^ ^^^^^^ ^^^^^^ ^^^ error[E0106]: missing lifetime specifier --> $DIR/issue-19707.rs:5:27 | LL | fn bar<F: Fn(&u8, &u8) -> &u8>(f: &F) {} - | ^ expected named lifetime parameter + | --- --- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'a` lifetime + | +LL | fn bar<F: for<'a> Fn(&'a u8, &'a u8) -> &'a u8>(f: &F) {} + | ^^^^^^^ ^^^^^^ ^^^^^^ ^^^ help: consider introducing a named lifetime parameter | -LL | fn bar<'lifetime, F: Fn(&u8, &u8) -> &'lifetime u8>(f: &F) {} - | ^^^^^^^^^^ ^^^^^^^^^^ +LL | fn bar<'a, F: Fn(&'a u8, &'a u8) -> &'a u8>(f: &F) {} + | ^^^ ^^^^^^ ^^^^^^ ^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-20413.stderr b/src/test/ui/issues/issue-20413.stderr index e765144ff0b..84e64ff74ae 100644 --- a/src/test/ui/issues/issue-20413.stderr +++ b/src/test/ui/issues/issue-20413.stderr @@ -15,7 +15,7 @@ LL | trait Foo { LL | impl<T> Foo for T where NoData<T>: Foo { | ^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`) = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` @@ -153,7 +153,7 @@ LL | trait Foo { LL | impl<T> Foo for T where NoData<T>: Foo { | ^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`) = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` diff --git a/src/test/ui/issues/issue-23122-2.stderr b/src/test/ui/issues/issue-23122-2.stderr index d2c1421e29e..7625e30498a 100644 --- a/src/test/ui/issues/issue-23122-2.stderr +++ b/src/test/ui/issues/issue-23122-2.stderr @@ -4,7 +4,7 @@ error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<< LL | impl<T: Next> Next for GetNext<T> { | ^^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_23122_2`) = note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>` error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: std::marker::Sized` @@ -13,7 +13,7 @@ error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<< LL | type Next = <GetNext<T::Next> as Next>::Next; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate + = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_23122_2`) = note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-26638.stderr b/src/test/ui/issues/issue-26638.stderr index 85d5d9cc42e..1d8fbdc63c5 100644 --- a/src/test/ui/issues/issue-26638.stderr +++ b/src/test/ui/issues/issue-26638.stderr @@ -2,13 +2,13 @@ error[E0106]: missing lifetime specifier --> $DIR/issue-26638.rs:1:62 | LL | fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.next() } - | ^ expected named lifetime parameter + | ------------------------------------ ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say which one of `iter`'s 2 lifetimes it is borrowed from help: consider introducing a named lifetime parameter | -LL | fn parse_type<'lifetime>(iter: Box<dyn Iterator<Item=&str>+'static>) -> &'lifetime str { iter.next() } - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn parse_type<'a>(iter: Box<dyn Iterator<Item=&str>+'static>) -> &'a str { iter.next() } + | ^^^^ ^^^ error[E0106]: missing lifetime specifier --> $DIR/issue-26638.rs:4:40 diff --git a/src/test/ui/issues/issue-30255.stderr b/src/test/ui/issues/issue-30255.stderr index c9402277640..ab43d4a3c60 100644 --- a/src/test/ui/issues/issue-30255.stderr +++ b/src/test/ui/issues/issue-30255.stderr @@ -2,37 +2,37 @@ error[E0106]: missing lifetime specifier --> $DIR/issue-30255.rs:9:24 | LL | fn f(a: &S, b: i32) -> &i32 { - | ^ expected named lifetime parameter + | -- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say which one of `a`'s 2 lifetimes it is borrowed from help: consider introducing a named lifetime parameter | -LL | fn f<'lifetime>(a: &S, b: i32) -> &'lifetime i32 { - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn f<'a>(a: &'a S, b: i32) -> &'a i32 { + | ^^^^ ^^^^^ ^^^ error[E0106]: missing lifetime specifier --> $DIR/issue-30255.rs:14:34 | LL | fn g(a: &S, b: bool, c: &i32) -> &i32 { - | ^ expected named lifetime parameter + | -- ---- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `a`'s 2 lifetimes or `c` help: consider introducing a named lifetime parameter | -LL | fn g<'lifetime>(a: &S, b: bool, c: &i32) -> &'lifetime i32 { - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn g<'a>(a: &'a S, b: bool, c: &'a i32) -> &'a i32 { + | ^^^^ ^^^^^ ^^^^^^^ ^^^ error[E0106]: missing lifetime specifier --> $DIR/issue-30255.rs:19:44 | LL | fn h(a: &bool, b: bool, c: &S, d: &i32) -> &i32 { - | ^ expected named lifetime parameter + | ----- -- ---- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a`, one of `c`'s 2 lifetimes, or `d` help: consider introducing a named lifetime parameter | -LL | fn h<'lifetime>(a: &bool, b: bool, c: &S, d: &i32) -> &'lifetime i32 { - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn h<'a>(a: &'a bool, b: bool, c: &'a S, d: &'a i32) -> &'a i32 { + | ^^^^ ^^^^^^^^ ^^^^^ ^^^^^^^ ^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-38940.stderr b/src/test/ui/issues/issue-38940.stderr index f60387f841a..36117278fd8 100644 --- a/src/test/ui/issues/issue-38940.stderr +++ b/src/test/ui/issues/issue-38940.stderr @@ -4,7 +4,7 @@ error[E0055]: reached the recursion limit while auto-dereferencing `I` LL | let x: &Bottom = &t; | ^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="20"]` attribute to your crate + = help: consider adding a `#![recursion_limit="20"]` attribute to your crate (`issue_38940`) error[E0308]: mismatched types --> $DIR/issue-38940.rs:43:22 diff --git a/src/test/ui/issues/issue-39616.rs b/src/test/ui/issues/issue-39616.rs index 3d8e28e5c2f..428856a36b4 100644 --- a/src/test/ui/issues/issue-39616.rs +++ b/src/test/ui/issues/issue-39616.rs @@ -1,5 +1,4 @@ fn foo(a: [0; 1]) {} //~ ERROR expected type, found `0` -//~| ERROR expected one of `)`, `,`, `->`, `where`, or `{`, found `]` -// FIXME(jseyfried): avoid emitting the second error (preexisting) +//~| ERROR expected `;` or `{`, found `]` fn main() {} diff --git a/src/test/ui/issues/issue-39616.stderr b/src/test/ui/issues/issue-39616.stderr index 74e94eda51f..ced58274661 100644 --- a/src/test/ui/issues/issue-39616.stderr +++ b/src/test/ui/issues/issue-39616.stderr @@ -4,11 +4,11 @@ error: expected type, found `0` LL | fn foo(a: [0; 1]) {} | ^ expected type -error: expected one of `)`, `,`, `->`, `where`, or `{`, found `]` +error: expected `;` or `{`, found `]` --> $DIR/issue-39616.rs:1:16 | LL | fn foo(a: [0; 1]) {} - | ^ expected one of `)`, `,`, `->`, `where`, or `{` + | ^ expected `;` or `{` error: aborting due to 2 previous errors diff --git a/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr b/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr index 1d5eeac23f9..461c1832e9a 100644 --- a/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr +++ b/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr @@ -10,25 +10,25 @@ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:7:33 | LL | fn g(_x: &isize, _y: &isize) -> &isize { - | ^ expected named lifetime parameter + | ------ ------ ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `_x` or `_y` help: consider introducing a named lifetime parameter | -LL | fn g<'lifetime>(_x: &isize, _y: &isize) -> &'lifetime isize { - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn g<'a>(_x: &'a isize, _y: &'a isize) -> &'a isize { + | ^^^^ ^^^^^^^^^ ^^^^^^^^^ ^^^ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:17:19 | LL | fn h(_x: &Foo) -> &isize { - | ^ expected named lifetime parameter + | ---- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say which one of `_x`'s 2 lifetimes it is borrowed from help: consider introducing a named lifetime parameter | -LL | fn h<'lifetime>(_x: &Foo) -> &'lifetime isize { - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn h<'a>(_x: &'a Foo) -> &'a isize { + | ^^^^ ^^^^^^^ ^^^ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:21:20 diff --git a/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr b/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr index 2990ab86824..c1fcab2409f 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr @@ -2,13 +2,13 @@ error[E0106]: missing lifetime specifier --> $DIR/ex1b-return-no-names-if-else.rs:1:29 | LL | fn foo(x: &i32, y: &i32) -> &i32 { - | ^ expected named lifetime parameter + | ---- ---- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y` help: consider introducing a named lifetime parameter | -LL | fn foo<'lifetime>(x: &i32, y: &i32) -> &'lifetime i32 { - | ^^^^^^^^^^^ ^^^^^^^^^^ +LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 { + | ^^^^ ^^^^^^^ ^^^^^^^ ^^^ error: aborting due to previous error diff --git a/src/test/ui/lint/lint-unnecessary-parens.rs b/src/test/ui/lint/lint-unnecessary-parens.rs index 4e8339a8e6b..5ce1f576081 100644 --- a/src/test/ui/lint/lint-unnecessary-parens.rs +++ b/src/test/ui/lint/lint-unnecessary-parens.rs @@ -38,6 +38,9 @@ macro_rules! baz { } } +const CONST_ITEM: usize = (10); //~ ERROR unnecessary parentheses around assigned value +static STATIC_ITEM: usize = (10); //~ ERROR unnecessary parentheses around assigned value + fn main() { foo(); bar((true)); //~ ERROR unnecessary parentheses around function argument diff --git a/src/test/ui/lint/lint-unnecessary-parens.stderr b/src/test/ui/lint/lint-unnecessary-parens.stderr index 3663f1d98bb..8858c953273 100644 --- a/src/test/ui/lint/lint-unnecessary-parens.stderr +++ b/src/test/ui/lint/lint-unnecessary-parens.stderr @@ -34,26 +34,38 @@ error: unnecessary parentheses around block return value LL | (5) | ^^^ help: remove these parentheses +error: unnecessary parentheses around assigned value + --> $DIR/lint-unnecessary-parens.rs:41:27 + | +LL | const CONST_ITEM: usize = (10); + | ^^^^ help: remove these parentheses + +error: unnecessary parentheses around assigned value + --> $DIR/lint-unnecessary-parens.rs:42:29 + | +LL | static STATIC_ITEM: usize = (10); + | ^^^^ help: remove these parentheses + error: unnecessary parentheses around function argument - --> $DIR/lint-unnecessary-parens.rs:43:9 + --> $DIR/lint-unnecessary-parens.rs:46:9 | LL | bar((true)); | ^^^^^^ help: remove these parentheses error: unnecessary parentheses around `if` condition - --> $DIR/lint-unnecessary-parens.rs:45:8 + --> $DIR/lint-unnecessary-parens.rs:48:8 | LL | if (true) {} | ^^^^^^ help: remove these parentheses error: unnecessary parentheses around `while` condition - --> $DIR/lint-unnecessary-parens.rs:46:11 + --> $DIR/lint-unnecessary-parens.rs:49:11 | LL | while (true) {} | ^^^^^^ help: remove these parentheses warning: denote infinite loops with `loop { ... }` - --> $DIR/lint-unnecessary-parens.rs:46:5 + --> $DIR/lint-unnecessary-parens.rs:49:5 | LL | while (true) {} | ^^^^^^^^^^^^ help: use `loop` @@ -61,46 +73,46 @@ LL | while (true) {} = note: `#[warn(while_true)]` on by default error: unnecessary parentheses around `match` head expression - --> $DIR/lint-unnecessary-parens.rs:48:11 + --> $DIR/lint-unnecessary-parens.rs:51:11 | LL | match (true) { | ^^^^^^ help: remove these parentheses error: unnecessary parentheses around `let` head expression - --> $DIR/lint-unnecessary-parens.rs:51:16 + --> $DIR/lint-unnecessary-parens.rs:54:16 | LL | if let 1 = (1) {} | ^^^ help: remove these parentheses error: unnecessary parentheses around `let` head expression - --> $DIR/lint-unnecessary-parens.rs:52:19 + --> $DIR/lint-unnecessary-parens.rs:55:19 | LL | while let 1 = (2) {} | ^^^ help: remove these parentheses error: unnecessary parentheses around method argument - --> $DIR/lint-unnecessary-parens.rs:66:24 + --> $DIR/lint-unnecessary-parens.rs:69:24 | LL | X { y: false }.foo((true)); | ^^^^^^ help: remove these parentheses error: unnecessary parentheses around assigned value - --> $DIR/lint-unnecessary-parens.rs:68:18 + --> $DIR/lint-unnecessary-parens.rs:71:18 | LL | let mut _a = (0); | ^^^ help: remove these parentheses error: unnecessary parentheses around assigned value - --> $DIR/lint-unnecessary-parens.rs:69:10 + --> $DIR/lint-unnecessary-parens.rs:72:10 | LL | _a = (0); | ^^^ help: remove these parentheses error: unnecessary parentheses around assigned value - --> $DIR/lint-unnecessary-parens.rs:70:11 + --> $DIR/lint-unnecessary-parens.rs:73:11 | LL | _a += (1); | ^^^ help: remove these parentheses -error: aborting due to 15 previous errors +error: aborting due to 17 previous errors diff --git a/src/test/ui/macros/issue-54441.stderr b/src/test/ui/macros/issue-54441.stderr index 1139ef06a12..92d1afe1b64 100644 --- a/src/test/ui/macros/issue-54441.stderr +++ b/src/test/ui/macros/issue-54441.stderr @@ -1,8 +1,8 @@ -error: expected one of `crate`, `fn`, `pub`, `static`, or `type`, found keyword `let` +error: expected one of `async`, `const`, `crate`, `extern`, `fn`, `pub`, `static`, `type`, or `unsafe`, found keyword `let` --> $DIR/issue-54441.rs:3:9 | LL | let - | ^^^ expected one of `crate`, `fn`, `pub`, `static`, or `type` + | ^^^ expected one of 9 possible tokens ... LL | m!(); | ----- in this macro invocation diff --git a/src/test/ui/macros/trace_faulty_macros.stderr b/src/test/ui/macros/trace_faulty_macros.stderr index 4e86daffb61..021c51fd726 100644 --- a/src/test/ui/macros/trace_faulty_macros.stderr +++ b/src/test/ui/macros/trace_faulty_macros.stderr @@ -29,7 +29,7 @@ LL | my_recursive_macro!(); LL | my_recursive_macro!(); | ---------------------- in this macro invocation | - = help: consider adding a `#![recursion_limit="8"]` attribute to your crate + = help: consider adding a `#![recursion_limit="8"]` attribute to your crate (`trace_faulty_macros`) note: trace_macro --> $DIR/trace_faulty_macros.rs:34:5 diff --git a/src/test/ui/no-patterns-in-args-2.rs b/src/test/ui/no-patterns-in-args-2.rs index ccf57478b48..85b7fc5cdba 100644 --- a/src/test/ui/no-patterns-in-args-2.rs +++ b/src/test/ui/no-patterns-in-args-2.rs @@ -1,9 +1,9 @@ #![deny(patterns_in_fns_without_body)] trait Tr { - fn f1(mut arg: u8); //~ ERROR patterns aren't allowed in methods without bodies + fn f1(mut arg: u8); //~ ERROR patterns aren't allowed in functions without bodies //~^ WARN was previously accepted - fn f2(&arg: u8); //~ ERROR patterns aren't allowed in methods without bodies + fn f2(&arg: u8); //~ ERROR patterns aren't allowed in functions without bodies fn g1(arg: u8); // OK fn g2(_: u8); // OK #[allow(anonymous_parameters)] diff --git a/src/test/ui/no-patterns-in-args-2.stderr b/src/test/ui/no-patterns-in-args-2.stderr index 905a89af4e5..21f4439d890 100644 --- a/src/test/ui/no-patterns-in-args-2.stderr +++ b/src/test/ui/no-patterns-in-args-2.stderr @@ -1,10 +1,10 @@ -error[E0642]: patterns aren't allowed in methods without bodies +error[E0642]: patterns aren't allowed in functions without bodies --> $DIR/no-patterns-in-args-2.rs:6:11 | LL | fn f2(&arg: u8); - | ^^^^ + | ^^^^ pattern not allowed in function without body -error: patterns aren't allowed in methods without bodies +error: patterns aren't allowed in functions without bodies --> $DIR/no-patterns-in-args-2.rs:4:11 | LL | fn f1(mut arg: u8); diff --git a/src/test/ui/no-patterns-in-args-macro.rs b/src/test/ui/no-patterns-in-args-macro.rs index 59cb9945398..b5109f9c286 100644 --- a/src/test/ui/no-patterns-in-args-macro.rs +++ b/src/test/ui/no-patterns-in-args-macro.rs @@ -6,10 +6,10 @@ macro_rules! m { type A = fn($pat: u8); - extern { + extern "C" { fn foreign_fn($pat: u8); } - } + }; } mod good_pat { @@ -20,7 +20,7 @@ mod bad_pat { m!((bad, pat)); //~^ ERROR patterns aren't allowed in function pointer types //~| ERROR patterns aren't allowed in foreign function declarations - //~| ERROR patterns aren't allowed in methods without bodies + //~| ERROR patterns aren't allowed in functions without bodies } fn main() {} diff --git a/src/test/ui/no-patterns-in-args-macro.stderr b/src/test/ui/no-patterns-in-args-macro.stderr index f21df68d5a2..0016c7953f3 100644 --- a/src/test/ui/no-patterns-in-args-macro.stderr +++ b/src/test/ui/no-patterns-in-args-macro.stderr @@ -1,8 +1,8 @@ -error[E0642]: patterns aren't allowed in methods without bodies +error[E0642]: patterns aren't allowed in functions without bodies --> $DIR/no-patterns-in-args-macro.rs:20:8 | LL | m!((bad, pat)); - | ^^^^^^^^^^ + | ^^^^^^^^^^ pattern not allowed in function without body error[E0561]: patterns aren't allowed in function pointer types --> $DIR/no-patterns-in-args-macro.rs:20:8 diff --git a/src/test/ui/or-patterns/issue-68785-irrefutable-param-with-at.rs b/src/test/ui/or-patterns/issue-68785-irrefutable-param-with-at.rs new file mode 100644 index 00000000000..1a65a1e544b --- /dev/null +++ b/src/test/ui/or-patterns/issue-68785-irrefutable-param-with-at.rs @@ -0,0 +1,14 @@ +// check-pass + +#![feature(or_patterns)] + +enum MyEnum { + FirstCase(u8), + OtherCase(u16), +} + +fn my_fn(x @ (MyEnum::FirstCase(_) | MyEnum::OtherCase(_)): MyEnum) {} + +fn main() { + my_fn(MyEnum::FirstCase(0)); +} diff --git a/src/test/ui/overlap-doesnt-conflict-with-specialization.rs b/src/test/ui/overlap-doesnt-conflict-with-specialization.rs index 3d4069f368d..dd09d68367e 100644 --- a/src/test/ui/overlap-doesnt-conflict-with-specialization.rs +++ b/src/test/ui/overlap-doesnt-conflict-with-specialization.rs @@ -1,8 +1,9 @@ // run-pass -#![feature(overlapping_marker_traits)] +#![feature(marker_trait_attr)] #![feature(specialization)] +#[marker] trait MyMarker {} impl<T> MyMarker for T {} diff --git a/src/test/ui/overlap-marker-trait.rs b/src/test/ui/overlap-marker-trait.rs deleted file mode 100644 index bf39d9c903f..00000000000 --- a/src/test/ui/overlap-marker-trait.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Test for RFC 1268: we allow overlapping impls of marker traits, -// that is, traits without items. In this case, a type `T` is -// `MyMarker` if it is either `Debug` or `Display`. This test just -// checks that we don't consider **all** types to be `MyMarker`. See -// also the companion test in -// `run-pass/overlap-permitted-for-marker-traits.rs`. - -#![feature(overlapping_marker_traits)] -#![feature(optin_builtin_traits)] - -use std::fmt::{Debug, Display}; - -trait Marker {} - -impl<T: Debug> Marker for T {} -impl<T: Display> Marker for T {} - -fn is_marker<T: Marker>() { } - -struct NotDebugOrDisplay; - -fn main() { - // Debug && Display: - is_marker::<i32>(); - - // Debug && !Display: - is_marker::<Vec<i32>>(); - - // !Debug && !Display - is_marker::<NotDebugOrDisplay>(); //~ ERROR -} diff --git a/src/test/ui/overlap-marker-trait.stderr b/src/test/ui/overlap-marker-trait.stderr deleted file mode 100644 index 15ebcd17b0d..00000000000 --- a/src/test/ui/overlap-marker-trait.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0277]: the trait bound `NotDebugOrDisplay: Marker` is not satisfied - --> $DIR/overlap-marker-trait.rs:30:17 - | -LL | fn is_marker<T: Marker>() { } - | --------- ------ required by this bound in `is_marker` -... -LL | is_marker::<NotDebugOrDisplay>(); - | ^^^^^^^^^^^^^^^^^ the trait `Marker` is not implemented for `NotDebugOrDisplay` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/parser/duplicate-visibility.rs b/src/test/ui/parser/duplicate-visibility.rs index bb17e97e950..a8f0b7d61b9 100644 --- a/src/test/ui/parser/duplicate-visibility.rs +++ b/src/test/ui/parser/duplicate-visibility.rs @@ -1,4 +1,4 @@ -// error-pattern:expected one of `(`, `fn`, `static`, or `type` +// error-pattern: expected one of `(`, `async`, `const`, `extern`, `fn` extern { pub pub fn foo(); } diff --git a/src/test/ui/parser/duplicate-visibility.stderr b/src/test/ui/parser/duplicate-visibility.stderr index 313e88e812b..cba4058e482 100644 --- a/src/test/ui/parser/duplicate-visibility.stderr +++ b/src/test/ui/parser/duplicate-visibility.stderr @@ -1,8 +1,8 @@ -error: expected one of `(`, `fn`, `static`, or `type`, found keyword `pub` +error: expected one of `(`, `async`, `const`, `extern`, `fn`, `static`, `type`, or `unsafe`, found keyword `pub` --> $DIR/duplicate-visibility.rs:3:9 | LL | pub pub fn foo(); - | ^^^ expected one of `(`, `fn`, `static`, or `type` + | ^^^ expected one of 8 possible tokens error: aborting due to previous error diff --git a/src/test/ui/parser/fn-body-optional-semantic-fail.rs b/src/test/ui/parser/fn-body-optional-semantic-fail.rs new file mode 100644 index 00000000000..38def05e8f2 --- /dev/null +++ b/src/test/ui/parser/fn-body-optional-semantic-fail.rs @@ -0,0 +1,27 @@ +// Tests the different rules for `fn` forms requiring the presence or lack of a body. + +fn main() { + fn f1(); //~ ERROR free function without a body + fn f2() {} // OK. + + trait X { + fn f1(); // OK. + fn f2() {} // OK. + } + + struct Y; + impl X for Y { + fn f1(); //~ ERROR associated function in `impl` without body + fn f2() {} // OK. + } + + impl Y { + fn f3(); //~ ERROR associated function in `impl` without body + fn f4() {} // OK. + } + + extern { + fn f5(); // OK. + fn f6() {} //~ ERROR incorrect function inside `extern` block + } +} diff --git a/src/test/ui/parser/fn-body-optional-semantic-fail.stderr b/src/test/ui/parser/fn-body-optional-semantic-fail.stderr new file mode 100644 index 00000000000..23ce98fb5d7 --- /dev/null +++ b/src/test/ui/parser/fn-body-optional-semantic-fail.stderr @@ -0,0 +1,40 @@ +error: free function without a body + --> $DIR/fn-body-optional-semantic-fail.rs:4:5 + | +LL | fn f1(); + | ^^^^^^^- + | | + | help: provide a definition for the function: `{ <body> }` + +error: associated function in `impl` without body + --> $DIR/fn-body-optional-semantic-fail.rs:14:9 + | +LL | fn f1(); + | ^^^^^^^- + | | + | help: provide a definition for the function: `{ <body> }` + +error: associated function in `impl` without body + --> $DIR/fn-body-optional-semantic-fail.rs:19:9 + | +LL | fn f3(); + | ^^^^^^^- + | | + | help: provide a definition for the function: `{ <body> }` + +error: incorrect function inside `extern` block + --> $DIR/fn-body-optional-semantic-fail.rs:25:12 + | +LL | extern { + | ------ `extern` blocks define existing foreign functions and functions inside of them cannot have a body +LL | fn f5(); // OK. +LL | fn f6() {} + | ^^ -- help: remove the invalid body: `;` + | | + | cannot have a body + | + = help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/parser/fn-body-optional-syntactic-pass.rs b/src/test/ui/parser/fn-body-optional-syntactic-pass.rs new file mode 100644 index 00000000000..e7991c73b4b --- /dev/null +++ b/src/test/ui/parser/fn-body-optional-syntactic-pass.rs @@ -0,0 +1,31 @@ +// Ensures that all `fn` forms having or lacking a body are syntactically valid. + +// check-pass + +fn main() {} + +#[cfg(FALSE)] +fn syntax() { + fn f(); + fn f() {} + + trait X { + fn f(); + fn f() {} + } + + impl X for Y { + fn f(); + fn f() {} + } + + impl Y { + fn f(); + fn f() {} + } + + extern { + fn f(); + fn f() {} + } +} diff --git a/src/test/ui/parser/fn-header-semantic-fail.rs b/src/test/ui/parser/fn-header-semantic-fail.rs new file mode 100644 index 00000000000..c2b7e69c80d --- /dev/null +++ b/src/test/ui/parser/fn-header-semantic-fail.rs @@ -0,0 +1,57 @@ +// Ensures that all `fn` forms can have all the function qualifiers syntactically. + +// edition:2018 + +#![feature(const_extern_fn)] +#![feature(const_fn)] + +fn main() { + async fn ff1() {} // OK. + unsafe fn ff2() {} // OK. + const fn ff3() {} // OK. + extern "C" fn ff4() {} // OK. + const /* async */ unsafe extern "C" fn ff5() {} // OK. + //^ FIXME(Centril): `async` should be legal syntactically, ensure it's illegal semantically. + + trait X { + async fn ft1(); //~ ERROR trait fns cannot be declared `async` + unsafe fn ft2(); // OK. + const fn ft3(); //~ ERROR trait fns cannot be declared const + extern "C" fn ft4(); // OK. + /* const */ async unsafe extern "C" fn ft5(); + //~^ ERROR trait fns cannot be declared `async` + //^ FIXME(Centril): `const` should be legal syntactically, ensure it's illegal semantically. + } + + struct Y; + impl X for Y { + async fn ft1() {} //~ ERROR trait fns cannot be declared `async` + //~^ ERROR method `ft1` has an incompatible type for trait + unsafe fn ft2() {} // OK. + const fn ft3() {} //~ ERROR trait fns cannot be declared const + extern "C" fn ft4() {} + /* const */ async unsafe extern "C" fn ft5() {} + //~^ ERROR trait fns cannot be declared `async` + //~| ERROR method `ft5` has an incompatible type for trait + //^ FIXME(Centril): `const` should be legal syntactically, ensure it's illegal semantically. + } + + impl Y { + async fn fi1() {} // OK. + unsafe fn fi2() {} // OK. + const fn fi3() {} // OK. + extern "C" fn fi4() {} // OK. + /* const */ async unsafe extern "C" fn fi5() {} // OK. + //^ FIXME(Centril): `const` should be legal syntactically, ensure it's illegal semantically. + } + + extern { + async fn fe1(); //~ ERROR functions in `extern` blocks cannot have qualifiers + unsafe fn fe2(); //~ ERROR functions in `extern` blocks cannot have qualifiers + const fn fe3(); //~ ERROR functions in `extern` blocks cannot have qualifiers + extern "C" fn fe4(); //~ ERROR functions in `extern` blocks cannot have qualifiers + /* const */ async unsafe extern "C" fn fe5(); + //~^ ERROR functions in `extern` blocks cannot have qualifiers + //^ FIXME(Centril): `const` should be legal syntactically, ensure it's illegal semantically. + } +} diff --git a/src/test/ui/parser/fn-header-semantic-fail.stderr b/src/test/ui/parser/fn-header-semantic-fail.stderr new file mode 100644 index 00000000000..41d2d9b7faa --- /dev/null +++ b/src/test/ui/parser/fn-header-semantic-fail.stderr @@ -0,0 +1,136 @@ +error[E0706]: trait fns cannot be declared `async` + --> $DIR/fn-header-semantic-fail.rs:17:9 + | +LL | async fn ft1(); + | ^^^^^^^^^^^^^^^ + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + +error[E0379]: trait fns cannot be declared const + --> $DIR/fn-header-semantic-fail.rs:19:9 + | +LL | const fn ft3(); + | ^^^^^ trait fns cannot be const + +error[E0706]: trait fns cannot be declared `async` + --> $DIR/fn-header-semantic-fail.rs:21:21 + | +LL | /* const */ async unsafe extern "C" fn ft5(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + +error[E0706]: trait fns cannot be declared `async` + --> $DIR/fn-header-semantic-fail.rs:28:9 + | +LL | async fn ft1() {} + | ^^^^^^^^^^^^^^^^^ + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + +error[E0379]: trait fns cannot be declared const + --> $DIR/fn-header-semantic-fail.rs:31:9 + | +LL | const fn ft3() {} + | ^^^^^ trait fns cannot be const + +error[E0706]: trait fns cannot be declared `async` + --> $DIR/fn-header-semantic-fail.rs:33:21 + | +LL | /* const */ async unsafe extern "C" fn ft5() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + +error: functions in `extern` blocks cannot have qualifiers + --> $DIR/fn-header-semantic-fail.rs:49:18 + | +LL | extern { + | ------ in this `extern` block +LL | async fn fe1(); + | ---------^^^ + | | + | help: remove the qualifiers: `fn` + +error: functions in `extern` blocks cannot have qualifiers + --> $DIR/fn-header-semantic-fail.rs:50:19 + | +LL | extern { + | ------ in this `extern` block +LL | async fn fe1(); +LL | unsafe fn fe2(); + | ----------^^^ + | | + | help: remove the qualifiers: `fn` + +error: functions in `extern` blocks cannot have qualifiers + --> $DIR/fn-header-semantic-fail.rs:51:18 + | +LL | extern { + | ------ in this `extern` block +... +LL | const fn fe3(); + | ---------^^^ + | | + | help: remove the qualifiers: `fn` + +error: functions in `extern` blocks cannot have qualifiers + --> $DIR/fn-header-semantic-fail.rs:52:23 + | +LL | extern { + | ------ in this `extern` block +... +LL | extern "C" fn fe4(); + | --------------^^^ + | | + | help: remove the qualifiers: `fn` + +error: functions in `extern` blocks cannot have qualifiers + --> $DIR/fn-header-semantic-fail.rs:53:48 + | +LL | extern { + | ------ in this `extern` block +... +LL | /* const */ async unsafe extern "C" fn fe5(); + | ---------------------------^^^ + | | + | help: remove the qualifiers: `fn` + +error[E0053]: method `ft1` has an incompatible type for trait + --> $DIR/fn-header-semantic-fail.rs:28:24 + | +LL | async fn ft1(); + | - type in trait +... +LL | async fn ft1() {} + | ^ + | | + | the `Output` of this `async fn`'s found opaque type + | expected `()`, found opaque type + | + = note: expected fn pointer `fn()` + found fn pointer `fn() -> impl std::future::Future` + +error[E0053]: method `ft5` has an incompatible type for trait + --> $DIR/fn-header-semantic-fail.rs:33:54 + | +LL | /* const */ async unsafe extern "C" fn ft5(); + | - type in trait +... +LL | /* const */ async unsafe extern "C" fn ft5() {} + | ^ + | | + | the `Output` of this `async fn`'s found opaque type + | expected `()`, found opaque type + | + = note: expected fn pointer `unsafe extern "C" fn()` + found fn pointer `unsafe extern "C" fn() -> impl std::future::Future` + +error: aborting due to 13 previous errors + +Some errors have detailed explanations: E0053, E0379, E0706. +For more information about an error, try `rustc --explain E0053`. diff --git a/src/test/ui/parser/fn-header-syntactic-pass.rs b/src/test/ui/parser/fn-header-syntactic-pass.rs new file mode 100644 index 00000000000..145a208cb24 --- /dev/null +++ b/src/test/ui/parser/fn-header-syntactic-pass.rs @@ -0,0 +1,55 @@ +// Ensures that all `fn` forms can have all the function qualifiers syntactically. + +// check-pass +// edition:2018 + +#![feature(const_extern_fn)] +//^ FIXME(Centril): move check to ast_validation. + +fn main() {} + +#[cfg(FALSE)] +fn syntax() { + async fn f(); + unsafe fn f(); + const fn f(); + extern "C" fn f(); + const /* async */ unsafe extern "C" fn f(); + //^ FIXME(Centril): `async` should be legal syntactically. + + trait X { + async fn f(); + unsafe fn f(); + const fn f(); + extern "C" fn f(); + /* const */ async unsafe extern "C" fn f(); + //^ FIXME(Centril): `const` should be legal syntactically. + } + + impl X for Y { + async fn f(); + unsafe fn f(); + const fn f(); + extern "C" fn f(); + /* const */ async unsafe extern "C" fn f(); + //^ FIXME(Centril): `const` should be legal syntactically. + } + + impl Y { + async fn f(); + unsafe fn f(); + const fn f(); + extern "C" fn f(); + /* const */ async unsafe extern "C" fn f(); + //^ FIXME(Centril): `const` should be legal syntactically. + } + + extern { + async fn f(); + unsafe fn f(); + const fn f(); + extern "C" fn f(); + /* const */ async unsafe extern "C" fn f(); + //^ FIXME(Centril): `const` should be legal syntactically. + } +} diff --git a/src/test/ui/parser/issue-24780.rs b/src/test/ui/parser/issue-24780.rs index 799cdd80222..8b46aa2bf22 100644 --- a/src/test/ui/parser/issue-24780.rs +++ b/src/test/ui/parser/issue-24780.rs @@ -3,6 +3,6 @@ // expected one of ..., `>`, ... found `>` fn foo() -> Vec<usize>> { - //~^ ERROR expected one of `!`, `+`, `::`, `where`, or `{`, found `>` + //~^ ERROR expected `;` or `{`, found `>` Vec::new() } diff --git a/src/test/ui/parser/issue-24780.stderr b/src/test/ui/parser/issue-24780.stderr index d9470191b25..d65a5f44873 100644 --- a/src/test/ui/parser/issue-24780.stderr +++ b/src/test/ui/parser/issue-24780.stderr @@ -1,8 +1,8 @@ -error: expected one of `!`, `+`, `::`, `where`, or `{`, found `>` +error: expected `;` or `{`, found `>` --> $DIR/issue-24780.rs:5:23 | LL | fn foo() -> Vec<usize>> { - | ^ expected one of `!`, `+`, `::`, `where`, or `{` + | ^ expected `;` or `{` error: aborting due to previous error diff --git a/src/test/ui/parser/issue-63135.rs b/src/test/ui/parser/issue-63135.rs index d5f5f1469f3..7d46b8904f0 100644 --- a/src/test/ui/parser/issue-63135.rs +++ b/src/test/ui/parser/issue-63135.rs @@ -1,3 +1,3 @@ -// error-pattern: aborting due to 6 previous errors +// error-pattern: aborting due to 7 previous errors fn i(n{...,f # diff --git a/src/test/ui/parser/issue-63135.stderr b/src/test/ui/parser/issue-63135.stderr index 462fdf11f40..04afae93be0 100644 --- a/src/test/ui/parser/issue-63135.stderr +++ b/src/test/ui/parser/issue-63135.stderr @@ -43,5 +43,11 @@ error: expected one of `:` or `|`, found `)` LL | fn i(n{...,f # | ^ expected one of `:` or `|` -error: aborting due to 6 previous errors +error: expected `;` or `{`, found `<eof>` + --> $DIR/issue-63135.rs:3:16 + | +LL | fn i(n{...,f # + | ^ expected `;` or `{` + +error: aborting due to 7 previous errors diff --git a/src/test/ui/parser/issue-68788-in-trait-item-propagation.rs b/src/test/ui/parser/issue-68788-in-trait-item-propagation.rs new file mode 100644 index 00000000000..7c3dd1d5a98 --- /dev/null +++ b/src/test/ui/parser/issue-68788-in-trait-item-propagation.rs @@ -0,0 +1,21 @@ +// Make sure we don't propagate restrictions on trait impl items to items inside them. + +// check-pass +// edition:2018 + +fn main() {} + +trait X { + fn foo(); +} + +impl X for () { + fn foo() { + struct S; + impl S { + pub const X: u8 = 0; + pub const fn bar() {} + async fn qux() {} + } + } +} diff --git a/src/test/ui/parser/missing_right_paren.rs b/src/test/ui/parser/missing_right_paren.rs index c35236ce793..810dee9571d 100644 --- a/src/test/ui/parser/missing_right_paren.rs +++ b/src/test/ui/parser/missing_right_paren.rs @@ -1,3 +1,3 @@ // ignore-tidy-trailing-newlines -// error-pattern: aborting due to 3 previous errors +// error-pattern: aborting due to 4 previous errors fn main((ؼ \ No newline at end of file diff --git a/src/test/ui/parser/missing_right_paren.stderr b/src/test/ui/parser/missing_right_paren.stderr index d67e7c88912..c1ceb81a07c 100644 --- a/src/test/ui/parser/missing_right_paren.stderr +++ b/src/test/ui/parser/missing_right_paren.stderr @@ -22,5 +22,11 @@ error: expected one of `:` or `|`, found `)` LL | fn main((ؼ | ^ expected one of `:` or `|` -error: aborting due to 3 previous errors +error: expected `;` or `{`, found `<eof>` + --> $DIR/missing_right_paren.rs:3:11 + | +LL | fn main((ؼ + | ^ expected `;` or `{` + +error: aborting due to 4 previous errors diff --git a/src/test/ui/parser/no-const-fn-in-extern-block.rs b/src/test/ui/parser/no-const-fn-in-extern-block.rs index 29f26389ded..4cae703a163 100644 --- a/src/test/ui/parser/no-const-fn-in-extern-block.rs +++ b/src/test/ui/parser/no-const-fn-in-extern-block.rs @@ -1,8 +1,8 @@ extern { const fn foo(); - //~^ ERROR extern items cannot be `const` + //~^ ERROR functions in `extern` blocks cannot have qualifiers const unsafe fn bar(); - //~^ ERROR extern items cannot be `const` + //~^ ERROR functions in `extern` blocks cannot have qualifiers } fn main() {} diff --git a/src/test/ui/parser/no-const-fn-in-extern-block.stderr b/src/test/ui/parser/no-const-fn-in-extern-block.stderr index 5b4663a702f..de653987e40 100644 --- a/src/test/ui/parser/no-const-fn-in-extern-block.stderr +++ b/src/test/ui/parser/no-const-fn-in-extern-block.stderr @@ -1,14 +1,23 @@ -error: extern items cannot be `const` - --> $DIR/no-const-fn-in-extern-block.rs:2:5 +error: functions in `extern` blocks cannot have qualifiers + --> $DIR/no-const-fn-in-extern-block.rs:2:14 | +LL | extern { + | ------ in this `extern` block LL | const fn foo(); - | ^^^^^ + | ---------^^^ + | | + | help: remove the qualifiers: `fn` -error: extern items cannot be `const` - --> $DIR/no-const-fn-in-extern-block.rs:4:5 +error: functions in `extern` blocks cannot have qualifiers + --> $DIR/no-const-fn-in-extern-block.rs:4:21 | +LL | extern { + | ------ in this `extern` block +... LL | const unsafe fn bar(); - | ^^^^^ + | ----------------^^^ + | | + | help: remove the qualifiers: `fn` error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/not-a-pred.stderr b/src/test/ui/parser/not-a-pred.stderr index 90246b92bf0..dce54655fa0 100644 --- a/src/test/ui/parser/not-a-pred.stderr +++ b/src/test/ui/parser/not-a-pred.stderr @@ -1,8 +1,8 @@ -error: expected one of `->`, `where`, or `{`, found `:` +error: expected `;` or `{`, found `:` --> $DIR/not-a-pred.rs:3:26 | LL | fn f(a: isize, b: isize) : lt(a, b) { } - | ^ expected one of `->`, `where`, or `{` + | ^ expected `;` or `{` error: aborting due to previous error diff --git a/src/test/ui/proc-macro/auxiliary/issue-59191.rs b/src/test/ui/proc-macro/auxiliary/issue-59191.rs new file mode 100644 index 00000000000..d9ee77067ec --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/issue-59191.rs @@ -0,0 +1,16 @@ +// edition:2018 +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn no_main(_attrs: TokenStream, _input: TokenStream) -> TokenStream { + let new_krate = r#" + fn main() {} + "#; + new_krate.parse().unwrap() +} diff --git a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs new file mode 100644 index 00000000000..a59cacb8bde --- /dev/null +++ b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs @@ -0,0 +1,8 @@ +// edition:2018 +// aux-crate:issue_59191=issue-59191.rs +// Test that using a macro to replace the entire crate tree with a non-'mod' item errors out nicely. +// `issue_59191::no_main` replaces whatever's passed in with `fn main() {}`. +#![feature(custom_inner_attributes)] +//~^ ERROR `main` function not found in crate `issue_59191_replace_root_with_fn` [E0601] +#![issue_59191::no_main] +//~^ ERROR expected crate top-level item to be a module after macro expansion, found a function diff --git a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr new file mode 100644 index 00000000000..e0a3caef9db --- /dev/null +++ b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr @@ -0,0 +1,17 @@ +error: expected crate top-level item to be a module after macro expansion, found a function + --> $DIR/issue-59191-replace-root-with-fn.rs:7:1 + | +LL | #![issue_59191::no_main] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0601]: `main` function not found in crate `issue_59191_replace_root_with_fn` + --> $DIR/issue-59191-replace-root-with-fn.rs:5:1 + | +LL | / #![feature(custom_inner_attributes)] +LL | | +LL | | #![issue_59191::no_main] + | |________________________^ consider adding a `main` function to `$DIR/issue-59191-replace-root-with-fn.rs` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0601`. diff --git a/src/test/ui/proc-macro/item-error.stderr b/src/test/ui/proc-macro/item-error.stderr index 01eadbe252e..27f7639d213 100644 --- a/src/test/ui/proc-macro/item-error.stderr +++ b/src/test/ui/proc-macro/item-error.stderr @@ -6,8 +6,8 @@ LL | a: &u64 | help: consider introducing a named lifetime parameter | -LL | struct A<'lifetime> { -LL | a: &'lifetime u64 +LL | struct A<'a> { +LL | a: &'a u64 | error: aborting due to previous error diff --git a/src/test/ui/regions/regions-in-enums-anon.stderr b/src/test/ui/regions/regions-in-enums-anon.stderr index 41655a210b3..b3649c5b485 100644 --- a/src/test/ui/regions/regions-in-enums-anon.stderr +++ b/src/test/ui/regions/regions-in-enums-anon.stderr @@ -6,8 +6,8 @@ LL | Bar(&isize) | help: consider introducing a named lifetime parameter | -LL | enum Foo<'lifetime> { -LL | Bar(&'lifetime isize) +LL | enum Foo<'a> { +LL | Bar(&'a isize) | error: aborting due to previous error diff --git a/src/test/ui/regions/regions-in-structs-anon.stderr b/src/test/ui/regions/regions-in-structs-anon.stderr index fbe8036880f..60a6fb9a0fa 100644 --- a/src/test/ui/regions/regions-in-structs-anon.stderr +++ b/src/test/ui/regions/regions-in-structs-anon.stderr @@ -6,8 +6,8 @@ LL | x: &isize | help: consider introducing a named lifetime parameter | -LL | struct Foo<'lifetime> { -LL | x: &'lifetime isize +LL | struct Foo<'a> { +LL | x: &'a isize | error: aborting due to previous error diff --git a/src/test/ui/regions/regions-name-undeclared.stderr b/src/test/ui/regions/regions-name-undeclared.stderr index 79ebef41dcc..eb19a30c52b 100644 --- a/src/test/ui/regions/regions-name-undeclared.stderr +++ b/src/test/ui/regions/regions-name-undeclared.stderr @@ -88,12 +88,32 @@ error[E0261]: use of undeclared lifetime name `'b` | LL | ... &'b isize, | ^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider introducing lifetime `'b` here + | +LL | fn fn_types<'b>(a: &'a isize, + | ^^^^ +help: consider making the bound lifetime-generic with a new `'b` lifetime + | +LL | b: Box<dyn for<'a, 'b> FnOnce(&'a isize, + | ^^^^ error[E0261]: use of undeclared lifetime name `'b` --> $DIR/regions-name-undeclared.rs:45:36 | LL | ... &'b isize)>, | ^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider introducing lifetime `'b` here + | +LL | fn fn_types<'b>(a: &'a isize, + | ^^^^ +help: consider making the bound lifetime-generic with a new `'b` lifetime + | +LL | b: Box<dyn for<'a, 'b> FnOnce(&'a isize, + | ^^^^ error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-name-undeclared.rs:46:17 diff --git a/src/test/ui/rfc1623-2.rs b/src/test/ui/rfc1623-2.rs new file mode 100644 index 00000000000..35a2ef10c2e --- /dev/null +++ b/src/test/ui/rfc1623-2.rs @@ -0,0 +1,13 @@ +#![allow(dead_code)] + +fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { + a +} + +// the boundaries of elision +static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = +//~^ ERROR missing lifetime specifier [E0106] + &(non_elidable as fn(&u8, &u8) -> &u8); + //~^ ERROR missing lifetime specifier [E0106] + +fn main() {} diff --git a/src/test/ui/rfc1623-2.stderr b/src/test/ui/rfc1623-2.stderr new file mode 100644 index 00000000000..732bb61e6ee --- /dev/null +++ b/src/test/ui/rfc1623-2.stderr @@ -0,0 +1,29 @@ +error[E0106]: missing lifetime specifier + --> $DIR/rfc1623-2.rs:8:42 + | +LL | static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = + | --- --- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the type lifetime-generic with a new `'a` lifetime + | +LL | static NON_ELIDABLE_FN: &for<'a> fn(&'a u8, &'a u8) -> &'a u8 = + | ^^^^^^^ ^^^^^^ ^^^^^^ ^^^ + +error[E0106]: missing lifetime specifier + --> $DIR/rfc1623-2.rs:10:39 + | +LL | &(non_elidable as fn(&u8, &u8) -> &u8); + | --- --- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the type lifetime-generic with a new `'a` lifetime + | +LL | &(non_elidable as for<'a> fn(&'a u8, &'a u8) -> &'a u8); + | ^^^^^^^ ^^^^^^ ^^^^^^ ^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/rfc1623.rs b/src/test/ui/rfc1623.rs index ebb4d56af9e..55f5d0b94dc 100644 --- a/src/test/ui/rfc1623.rs +++ b/src/test/ui/rfc1623.rs @@ -4,11 +4,10 @@ fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { a } -// the boundaries of elision -static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = -//~^ ERROR missing lifetime specifier [E0106] - &(non_elidable as fn(&u8, &u8) -> &u8); - //~^ ERROR missing lifetime specifier [E0106] +// The incorrect case without `for<'a>` is tested for in `rfc1623-2.rs` +static NON_ELIDABLE_FN: &for<'a> fn(&'a u8, &'a u8) -> &'a u8 = + &(non_elidable as for<'a> fn(&'a u8, &'a u8) -> &'a u8); + struct SomeStruct<'x, 'y, 'z: 'x> { foo: &'x Foo<'z>, @@ -20,10 +19,12 @@ fn id<T>(t: T) -> T { t } -static SOME_STRUCT: &SomeStruct = SomeStruct { +static SOME_STRUCT: &SomeStruct = SomeStruct { //~ ERROR mismatched types foo: &Foo { bools: &[false, true] }, bar: &Bar { bools: &[true, true] }, f: &id, + //~^ ERROR type mismatch in function arguments + //~| ERROR type mismatch resolving }; // very simple test for a 'static static with default lifetime diff --git a/src/test/ui/rfc1623.stderr b/src/test/ui/rfc1623.stderr index 5b665e18141..ca956004ef7 100644 --- a/src/test/ui/rfc1623.stderr +++ b/src/test/ui/rfc1623.stderr @@ -1,19 +1,46 @@ -error[E0106]: missing lifetime specifier - --> $DIR/rfc1623.rs:8:42 +error[E0308]: mismatched types + --> $DIR/rfc1623.rs:22:35 | -LL | static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = - | ^ expected named lifetime parameter +LL | static SOME_STRUCT: &SomeStruct = SomeStruct { + | ___________________________________^ +LL | | foo: &Foo { bools: &[false, true] }, +LL | | bar: &Bar { bools: &[true, true] }, +LL | | f: &id, +LL | | +LL | | +LL | | }; + | |_^ expected `&SomeStruct<'static, 'static, 'static>`, found struct `SomeStruct` | - = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 +help: consider borrowing here + | +LL | static SOME_STRUCT: &SomeStruct = &SomeStruct { +LL | foo: &Foo { bools: &[false, true] }, +LL | bar: &Bar { bools: &[true, true] }, +LL | f: &id, +LL | +LL | + ... + +error[E0631]: type mismatch in function arguments + --> $DIR/rfc1623.rs:25:8 + | +LL | fn id<T>(t: T) -> T { + | ------------------- found signature of `fn(_) -> _` +... +LL | f: &id, + | ^^^ expected signature of `for<'a, 'b> fn(&'a Foo<'b>) -> _` + | + = note: required for the cast to the object type `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` -error[E0106]: missing lifetime specifier - --> $DIR/rfc1623.rs:10:39 +error[E0271]: type mismatch resolving `for<'a, 'b> <fn(_) -> _ {id::<_>} as std::ops::FnOnce<(&'a Foo<'b>,)>>::Output == &'a Foo<'b>` + --> $DIR/rfc1623.rs:25:8 | -LL | &(non_elidable as fn(&u8, &u8) -> &u8); - | ^ expected named lifetime parameter +LL | f: &id, + | ^^^ expected bound lifetime parameter 'a, found concrete lifetime | - = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 + = note: required for the cast to the object type `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0106`. +Some errors have detailed explanations: E0271, E0308, E0631. +For more information about an error, try `rustc --explain E0271`. diff --git a/src/test/ui/suggestions/fn-missing-lifetime-in-item.rs b/src/test/ui/suggestions/fn-missing-lifetime-in-item.rs new file mode 100644 index 00000000000..dac6610b335 --- /dev/null +++ b/src/test/ui/suggestions/fn-missing-lifetime-in-item.rs @@ -0,0 +1,8 @@ +struct S1<F: Fn(&i32, &i32) -> &'a i32>(F); //~ ERROR use of undeclared lifetime name `'a` +struct S2<F: Fn(&i32, &i32) -> &i32>(F); //~ ERROR missing lifetime specifier +struct S3<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F); +//~^ ERROR binding for associated type `Output` references lifetime `'a`, which does not appear +struct S4<F: for<'x> Fn(&'x i32, &'x i32) -> &'x i32>(F); +const C: Option<Box<dyn for<'a> Fn(&usize, &usize) -> &'a usize>> = None; +//~^ ERROR binding for associated type `Output` references lifetime `'a`, which does not appear +fn main() {} diff --git a/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr b/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr new file mode 100644 index 00000000000..fe9c3445fc4 --- /dev/null +++ b/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr @@ -0,0 +1,49 @@ +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/fn-missing-lifetime-in-item.rs:1:33 + | +LL | struct S1<F: Fn(&i32, &i32) -> &'a i32>(F); + | ^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider introducing lifetime `'a` here + | +LL | struct S1<'a, F: Fn(&i32, &i32) -> &'a i32>(F); + | ^^^ +help: consider making the bound lifetime-generic with a new `'a` lifetime + | +LL | struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F); + | ^^^^^^^ + +error[E0106]: missing lifetime specifier + --> $DIR/fn-missing-lifetime-in-item.rs:2:32 + | +LL | struct S2<F: Fn(&i32, &i32) -> &i32>(F); + | ---- ---- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'a` lifetime + | +LL | struct S2<F: for<'a> Fn(&'a i32, &'a i32) -> &'a i32>(F); + | ^^^^^^^ ^^^^^^^ ^^^^^^^ ^^^ +help: consider introducing a named lifetime parameter + | +LL | struct S2<'a, F: Fn(&'a i32, &'a i32) -> &'a i32>(F); + | ^^^ ^^^^^^^ ^^^^^^^ ^^^ + +error[E0582]: binding for associated type `Output` references lifetime `'a`, which does not appear in the trait input types + --> $DIR/fn-missing-lifetime-in-item.rs:3:40 + | +LL | struct S3<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F); + | ^^^^^^^ + +error[E0582]: binding for associated type `Output` references lifetime `'a`, which does not appear in the trait input types + --> $DIR/fn-missing-lifetime-in-item.rs:6:55 + | +LL | const C: Option<Box<dyn for<'a> Fn(&usize, &usize) -> &'a usize>> = None; + | ^^^^^^^^^ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0106, E0261, E0582. +For more information about an error, try `rustc --explain E0106`. diff --git a/src/test/ui/suggestions/impl-trait-missing-lifetime.rs b/src/test/ui/suggestions/impl-trait-missing-lifetime.rs new file mode 100644 index 00000000000..22dc448c97f --- /dev/null +++ b/src/test/ui/suggestions/impl-trait-missing-lifetime.rs @@ -0,0 +1,2 @@ +fn f(_: impl Iterator<Item = &'_ ()>) {} //~ ERROR missing lifetime specifier +fn main() {} diff --git a/src/test/ui/suggestions/impl-trait-missing-lifetime.stderr b/src/test/ui/suggestions/impl-trait-missing-lifetime.stderr new file mode 100644 index 00000000000..e31f25ab603 --- /dev/null +++ b/src/test/ui/suggestions/impl-trait-missing-lifetime.stderr @@ -0,0 +1,14 @@ +error[E0106]: missing lifetime specifier + --> $DIR/impl-trait-missing-lifetime.rs:1:31 + | +LL | fn f(_: impl Iterator<Item = &'_ ()>) {} + | ^^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | fn f<'a>(_: impl Iterator<Item = &'a ()>) {} + | ^^^^ ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/suggestions/return-without-lifetime.stderr b/src/test/ui/suggestions/return-without-lifetime.stderr index 7f5ff95938e..ce3b1748da4 100644 --- a/src/test/ui/suggestions/return-without-lifetime.stderr +++ b/src/test/ui/suggestions/return-without-lifetime.stderr @@ -8,7 +8,7 @@ error[E0106]: missing lifetime specifier --> $DIR/return-without-lifetime.rs:5:34 | LL | fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() } - | ^ help: consider using the named lifetime: `&'a` + | --------- ^ help: consider using the named lifetime: `&'a` | = help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from @@ -16,7 +16,7 @@ error[E0106]: missing lifetime specifier --> $DIR/return-without-lifetime.rs:7:35 | LL | fn func2<'a>(_arg: &Thing<'a>) -> &() { unimplemented!() } - | ^ help: consider using the named lifetime: `&'a` + | ---------- ^ help: consider using the named lifetime: `&'a` | = help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from diff --git a/src/test/ui/suggestions/suggest-split-at-mut.rs b/src/test/ui/suggestions/suggest-split-at-mut.rs new file mode 100644 index 00000000000..d294c20b824 --- /dev/null +++ b/src/test/ui/suggestions/suggest-split-at-mut.rs @@ -0,0 +1,8 @@ +fn main() { + let mut foo = [1, 2, 3, 4]; + let a = &mut foo[2]; + let b = &mut foo[3]; //~ ERROR cannot borrow `foo[_]` as mutable more than once at a time + *a = 5; + *b = 6; + println!("{:?} {:?}", a, b); +} diff --git a/src/test/ui/suggestions/suggest-split-at-mut.stderr b/src/test/ui/suggestions/suggest-split-at-mut.stderr new file mode 100644 index 00000000000..330f012b2a9 --- /dev/null +++ b/src/test/ui/suggestions/suggest-split-at-mut.stderr @@ -0,0 +1,15 @@ +error[E0499]: cannot borrow `foo[_]` as mutable more than once at a time + --> $DIR/suggest-split-at-mut.rs:4:13 + | +LL | let a = &mut foo[2]; + | ----------- first mutable borrow occurs here +LL | let b = &mut foo[3]; + | ^^^^^^^^^^^ second mutable borrow occurs here +LL | *a = 5; + | ------ first borrow later used here + | + = help: consider using `.split_at_mut(position)` or similar method to obtain two mutable non-overlapping sub-slices + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/super-fast-paren-parsing.rs b/src/test/ui/super-fast-paren-parsing.rs index 60c8db53a8c..cb42ff2c644 100644 --- a/src/test/ui/super-fast-paren-parsing.rs +++ b/src/test/ui/super-fast-paren-parsing.rs @@ -1,5 +1,6 @@ // run-pass +#![allow(unused_parens)] #![allow(non_upper_case_globals)] #![allow(dead_code)] // exec-env:RUST_MIN_STACK=16000000 diff --git a/src/test/ui/traits/overlap-permitted-for-marker-traits-neg.rs b/src/test/ui/traits/overlap-not-permitted-for-builtin-trait.rs index bc8dc8dbd05..86029473b51 100644 --- a/src/test/ui/traits/overlap-permitted-for-marker-traits-neg.rs +++ b/src/test/ui/traits/overlap-not-permitted-for-builtin-trait.rs @@ -1,12 +1,11 @@ -// run-pass #![allow(dead_code)] -#![feature(overlapping_marker_traits)] #![feature(optin_builtin_traits)] -// Overlapping negative impls for `MyStruct` are permitted: +// Overlapping negative impls for `MyStruct` are not permitted: struct MyStruct; impl !Send for MyStruct {} impl !Send for MyStruct {} +//~^ ERROR conflicting implementations of trait fn main() { } diff --git a/src/test/ui/traits/overlap-not-permitted-for-builtin-trait.stderr b/src/test/ui/traits/overlap-not-permitted-for-builtin-trait.stderr new file mode 100644 index 00000000000..94a0c287f4a --- /dev/null +++ b/src/test/ui/traits/overlap-not-permitted-for-builtin-trait.stderr @@ -0,0 +1,11 @@ +error[E0119]: conflicting implementations of trait `std::marker::Send` for type `MyStruct`: + --> $DIR/overlap-not-permitted-for-builtin-trait.rs:7:1 + | +LL | impl !Send for MyStruct {} + | ----------------------- first implementation here +LL | impl !Send for MyStruct {} + | ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `MyStruct` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/traits/overlap-permitted-for-marker-traits.rs b/src/test/ui/traits/overlap-permitted-for-marker-traits.rs deleted file mode 100644 index 59ec9d5689d..00000000000 --- a/src/test/ui/traits/overlap-permitted-for-marker-traits.rs +++ /dev/null @@ -1,27 +0,0 @@ -// run-pass -// Tests for RFC 1268: we allow overlapping impls of marker traits, -// that is, traits without items. In this case, a type `T` is -// `MyMarker` if it is either `Debug` or `Display`. - -#![feature(overlapping_marker_traits)] -#![feature(optin_builtin_traits)] - -use std::fmt::{Debug, Display}; - -trait MyMarker {} - -impl<T: Debug> MyMarker for T {} -impl<T: Display> MyMarker for T {} - -fn foo<T: MyMarker>(t: T) -> T { - t -} - -fn main() { - // Debug && Display: - assert_eq!(1, foo(1)); - assert_eq!(2.0, foo(2.0)); - - // Debug && !Display: - assert_eq!(vec![1], foo(vec![1])); -} diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr index 0a028e44919..1719a99d421 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr @@ -2,12 +2,12 @@ error[E0106]: missing lifetime specifier --> $DIR/unboxed-closure-sugar-lifetime-elision.rs:26:39 | LL | let _: dyn Foo(&isize, &usize) -> &usize; - | ^ expected named lifetime parameter + | ------ ------ ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2 help: consider introducing a named lifetime parameter | -LL | fn main<'lifetime>() { +LL | fn main<'a>() { LL | eq::< dyn for<'a> Foo<(&'a isize,), Output=&'a isize>, LL | dyn Foo(&isize) -> &isize >(); LL | eq::< dyn for<'a> Foo<(&'a isize,), Output=(&'a isize, &'a isize)>, diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr index 04df2e45703..fe242e6a909 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr @@ -6,8 +6,8 @@ LL | x: Box<dyn Debug + '_>, | help: consider introducing a named lifetime parameter | -LL | struct Foo<'lifetime> { -LL | x: Box<dyn Debug + 'lifetime>, +LL | struct Foo<'a> { +LL | x: Box<dyn Debug + 'a>, | error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound diff --git a/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr b/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr index cf820249c80..8d2c82e59ed 100644 --- a/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr +++ b/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr @@ -2,13 +2,13 @@ error[E0106]: missing lifetime specifier --> $DIR/in-fn-return-illegal.rs:5:30 | LL | fn foo(x: &u32, y: &u32) -> &'_ u32 { loop { } } - | ^^ expected named lifetime parameter + | ---- ---- ^^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y` help: consider introducing a named lifetime parameter | -LL | fn foo<'lifetime>(x: &u32, y: &u32) -> &'lifetime u32 { loop { } } - | ^^^^^^^^^^^ ^^^^^^^^^ +LL | fn foo<'a>(x: &'a u32, y: &'a u32) -> &'a u32 { loop { } } + | ^^^^ ^^^^^^^ ^^^^^^^ ^^ error: aborting due to previous error diff --git a/src/test/ui/underscore-lifetime/in-struct.stderr b/src/test/ui/underscore-lifetime/in-struct.stderr index e01b39a4b64..4275cc26f73 100644 --- a/src/test/ui/underscore-lifetime/in-struct.stderr +++ b/src/test/ui/underscore-lifetime/in-struct.stderr @@ -6,8 +6,8 @@ LL | x: &'_ u32, | help: consider introducing a named lifetime parameter | -LL | struct Foo<'lifetime> { -LL | x: &'lifetime u32, +LL | struct Foo<'a> { +LL | x: &'a u32, | error[E0106]: missing lifetime specifier @@ -18,8 +18,8 @@ LL | Variant(&'_ u32), | help: consider introducing a named lifetime parameter | -LL | enum Bar<'lifetime> { -LL | Variant(&'lifetime u32), +LL | enum Bar<'a> { +LL | Variant(&'a u32), | error: aborting due to 2 previous errors diff --git a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr index 517904ee628..c7cda38e476 100644 --- a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr +++ b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr @@ -28,13 +28,13 @@ error[E0106]: missing lifetime specifier --> $DIR/underscore-lifetime-binders.rs:16:35 | LL | fn foo2(_: &'_ u8, y: &'_ u8) -> &'_ u8 { y } - | ^^ expected named lifetime parameter + | ------ ------ ^^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or `y` help: consider introducing a named lifetime parameter | -LL | fn foo2<'lifetime>(_: &'_ u8, y: &'_ u8) -> &'lifetime u8 { y } - | ^^^^^^^^^^^ ^^^^^^^^^ +LL | fn foo2<'a>(_: &'a u8, y: &'a u8) -> &'a u8 { y } + | ^^^^ ^^^^^^ ^^^^^^ ^^ error: aborting due to 5 previous errors |
