mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 08:44:35 +00:00
Merge branch 'master' into redox_builder
This commit is contained in:
commit
51dcdcfd94
21
Cargo.lock
21
Cargo.lock
@ -106,7 +106,7 @@ dependencies = [
|
||||
"cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-std-workspace-core 1.0.0",
|
||||
]
|
||||
|
||||
@ -1138,19 +1138,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.4.0"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-std-workspace-alloc 1.0.0",
|
||||
"rustc-std-workspace-core 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@ -2736,7 +2729,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.15"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2894,7 +2887,7 @@ dependencies = [
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"punycode 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc 0.0.0",
|
||||
"rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_data_structures 0.0.0",
|
||||
"rustc_metadata 0.0.0",
|
||||
"rustc_target 0.0.0",
|
||||
@ -3534,8 +3527,9 @@ dependencies = [
|
||||
"core 0.0.0",
|
||||
"dlmalloc 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fortanix-sgx-abi 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hashbrown 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hashbrown 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hashbrown 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"panic_abort 0.0.0",
|
||||
"panic_unwind 0.0.0",
|
||||
"profiler_builtins 0.0.0",
|
||||
@ -4450,7 +4444,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum globset 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef4feaabe24a0a658fd9cf4a9acf6ed284f045c77df0f49020ba3245cfb7b454"
|
||||
"checksum h2 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "a539b63339fbbb00e081e84b6e11bd1d9634a82d91da2984a18ac74a8823f392"
|
||||
"checksum handlebars 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "df044dd42cdb7e32f28557b661406fc0f2494be75199779998810dbc35030e0d"
|
||||
"checksum hashbrown 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9529213c67695ca2d146e6f263b7b72df8fa973368beadf767e8ed80c03f2f36"
|
||||
"checksum hashbrown 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e1de41fb8dba9714efd92241565cdff73f78508c95697dd56787d3cba27e2353"
|
||||
"checksum heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea04fa3ead4e05e51a7c806fc07271fdbde4e246a6c6d1efd52e72230b771b82"
|
||||
"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
|
||||
@ -4600,7 +4593,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum rustc-ap-serialize 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "61673783f2089e01033ffa82d1988f55175402071b31253a358292e1624d4602"
|
||||
"checksum rustc-ap-syntax 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "28f3dd1346d5b0269c07a4a78855e309a298ab569c9c1302d4d4f57f8eee4e84"
|
||||
"checksum rustc-ap-syntax_pos 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "45e67b526dbda3a0c7dab91c8947d43685e7697f52686a4949da3c179cd7c979"
|
||||
"checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af"
|
||||
"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
|
||||
"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8"
|
||||
"checksum rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d2e07e19601f21c59aad953c2632172ba70cb27e685771514ea66e4062b3363"
|
||||
"checksum rustc-rayon-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "79d38ca7cbc22fa59f09d8534ea4b27f67b0facf0cbe274433aceea227a02543"
|
||||
|
@ -144,7 +144,7 @@ then you may need to force rustbuild to use an older version. This can be done
|
||||
by manually calling the appropriate vcvars file before running the bootstrap.
|
||||
|
||||
```batch
|
||||
> CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvars64.bat"
|
||||
> CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"
|
||||
> python x.py build
|
||||
```
|
||||
|
||||
|
@ -22,7 +22,7 @@ Language
|
||||
- [You can now use `_` as an identifier for consts.][61347] e.g. You can write
|
||||
`const _: u32 = 5;`.
|
||||
- [You can now use `#[repr(align(X)]` on enums.][61229]
|
||||
- [The `?`/_"Kleene"_ macro operator is now available in the
|
||||
- [The `?` Kleene macro operator is now available in the
|
||||
2015 edition.][60932]
|
||||
|
||||
Compiler
|
||||
|
@ -141,10 +141,10 @@
|
||||
# library and facade crates.
|
||||
#compiler-docs = false
|
||||
|
||||
# Indicate whether submodules are managed and updated automatically.
|
||||
# Indicate whether git submodules are managed and updated automatically.
|
||||
#submodules = true
|
||||
|
||||
# Update submodules only when the checked out commit in the submodules differs
|
||||
# Update git submodules only when the checked out commit in the submodules differs
|
||||
# from what is committed in the main rustc repo.
|
||||
#fast-submodules = true
|
||||
|
||||
|
@ -37,7 +37,7 @@ fn main() {
|
||||
let mut new = None;
|
||||
if let Some(current_as_str) = args[i].to_str() {
|
||||
if (&*args[i - 1] == "-C" && current_as_str.starts_with("metadata")) ||
|
||||
current_as_str.starts_with("-Cmetadata") {
|
||||
current_as_str.starts_with("-Cmetadata") {
|
||||
new = Some(format!("{}-{}", current_as_str, s));
|
||||
}
|
||||
}
|
||||
@ -45,18 +45,6 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
// Drop `--error-format json` because despite our desire for json messages
|
||||
// from Cargo we don't want any from rustc itself.
|
||||
if let Some(n) = args.iter().position(|n| n == "--error-format") {
|
||||
args.remove(n);
|
||||
args.remove(n);
|
||||
}
|
||||
|
||||
if let Some(s) = env::var_os("RUSTC_ERROR_FORMAT") {
|
||||
args.push("--error-format".into());
|
||||
args.push(s);
|
||||
}
|
||||
|
||||
// Detect whether or not we're a build script depending on whether --target
|
||||
// is passed (a bit janky...)
|
||||
let target = args.windows(2)
|
||||
@ -101,7 +89,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");
|
||||
}
|
||||
@ -110,8 +98,17 @@ fn main() {
|
||||
|
||||
// Non-zero stages must all be treated uniformly to avoid problems when attempting to uplift
|
||||
// compiler libraries and such from stage 1 to 2.
|
||||
//
|
||||
// FIXME: the fact that core here is excluded is due to core_arch from our stdarch submodule
|
||||
// being broken on the beta compiler with bootstrap passed, so this is a temporary workaround
|
||||
// (we've just snapped, so there are no cfg(bootstrap) related annotations in core).
|
||||
if stage == "0" {
|
||||
cmd.arg("--cfg").arg("bootstrap");
|
||||
if crate_name != Some("core") {
|
||||
cmd.arg("--cfg").arg("bootstrap");
|
||||
} else {
|
||||
// NOTE(eddyb) see FIXME above, except now we need annotations again in core.
|
||||
cmd.arg("--cfg").arg("boostrap_stdarch_ignore_this");
|
||||
}
|
||||
}
|
||||
|
||||
// Print backtrace in case of ICE
|
||||
@ -132,10 +129,7 @@ fn main() {
|
||||
cmd.arg("-Dwarnings");
|
||||
cmd.arg("-Drust_2018_idioms");
|
||||
cmd.arg("-Dunused_lifetimes");
|
||||
// cfg(not(bootstrap)): Remove this during the next stage 0 compiler update.
|
||||
// `-Drustc::internal` is a new feature and `rustc_version` mis-reports the `stage`.
|
||||
let cfg_not_bootstrap = stage != "0" && crate_name != Some("rustc_version");
|
||||
if cfg_not_bootstrap && use_internal_lints(crate_name) {
|
||||
if use_internal_lints(crate_name) {
|
||||
cmd.arg("-Zunstable-options");
|
||||
cmd.arg("-Drustc::internal");
|
||||
}
|
||||
@ -287,10 +281,6 @@ fn main() {
|
||||
cmd.arg("-C").arg("target-feature=-crt-static");
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") {
|
||||
cmd.arg("--remap-path-prefix").arg(&map);
|
||||
}
|
||||
} else {
|
||||
// Override linker if necessary.
|
||||
if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") {
|
||||
@ -307,6 +297,10 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") {
|
||||
cmd.arg("--remap-path-prefix").arg(&map);
|
||||
}
|
||||
|
||||
// Force all crates compiled by this compiler to (a) be unstable and (b)
|
||||
// allow the `rustc_private` feature to link to other unstable crates
|
||||
// also in the sysroot. We also do this for host crates, since those
|
||||
|
@ -145,7 +145,7 @@ impl StepDescription {
|
||||
only_hosts: S::ONLY_HOSTS,
|
||||
should_run: S::should_run,
|
||||
make_run: S::make_run,
|
||||
name: unsafe { ::std::intrinsics::type_name::<S>() },
|
||||
name: std::any::type_name::<S>(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -754,76 +754,20 @@ impl<'a> Builder<'a> {
|
||||
let mut cargo = Command::new(&self.initial_cargo);
|
||||
let out_dir = self.stage_out(compiler, mode);
|
||||
|
||||
// command specific path, we call clear_if_dirty with this
|
||||
let mut my_out = match cmd {
|
||||
"build" => self.cargo_out(compiler, mode, target),
|
||||
|
||||
// This is the intended out directory for crate documentation.
|
||||
"doc" | "rustdoc" => self.crate_doc_out(target),
|
||||
|
||||
_ => self.stage_out(compiler, mode),
|
||||
};
|
||||
|
||||
// This is for the original compiler, but if we're forced to use stage 1, then
|
||||
// std/test/rustc stamps won't exist in stage 2, so we need to get those from stage 1, since
|
||||
// we copy the libs forward.
|
||||
let cmp = self.compiler_for(compiler.stage, compiler.host, target);
|
||||
|
||||
let libstd_stamp = match cmd {
|
||||
"check" | "clippy" | "fix" => check::libstd_stamp(self, cmp, target),
|
||||
_ => compile::libstd_stamp(self, cmp, target),
|
||||
};
|
||||
|
||||
let libtest_stamp = match cmd {
|
||||
"check" | "clippy" | "fix" => check::libtest_stamp(self, cmp, target),
|
||||
_ => compile::libtest_stamp(self, cmp, target),
|
||||
};
|
||||
|
||||
let librustc_stamp = match cmd {
|
||||
"check" | "clippy" | "fix" => check::librustc_stamp(self, cmp, target),
|
||||
_ => compile::librustc_stamp(self, cmp, target),
|
||||
};
|
||||
// Codegen backends are not yet tracked by -Zbinary-dep-depinfo,
|
||||
// so we need to explicitly clear out if they've been updated.
|
||||
for backend in self.codegen_backends(compiler) {
|
||||
self.clear_if_dirty(&out_dir, &backend);
|
||||
}
|
||||
|
||||
if cmd == "doc" || cmd == "rustdoc" {
|
||||
if mode == Mode::Rustc || mode == Mode::ToolRustc || mode == Mode::Codegen {
|
||||
let my_out = match mode {
|
||||
// This is the intended out directory for compiler documentation.
|
||||
my_out = self.compiler_doc_out(target);
|
||||
}
|
||||
Mode::Rustc | Mode::ToolRustc | Mode::Codegen => self.compiler_doc_out(target),
|
||||
_ => self.crate_doc_out(target),
|
||||
};
|
||||
let rustdoc = self.rustdoc(compiler);
|
||||
self.clear_if_dirty(&my_out, &rustdoc);
|
||||
} else if cmd != "test" {
|
||||
match mode {
|
||||
Mode::Std => {
|
||||
self.clear_if_dirty(&my_out, &self.rustc(compiler));
|
||||
for backend in self.codegen_backends(compiler) {
|
||||
self.clear_if_dirty(&my_out, &backend);
|
||||
}
|
||||
},
|
||||
Mode::Test => {
|
||||
self.clear_if_dirty(&my_out, &libstd_stamp);
|
||||
},
|
||||
Mode::Rustc => {
|
||||
self.clear_if_dirty(&my_out, &self.rustc(compiler));
|
||||
self.clear_if_dirty(&my_out, &libstd_stamp);
|
||||
self.clear_if_dirty(&my_out, &libtest_stamp);
|
||||
},
|
||||
Mode::Codegen => {
|
||||
self.clear_if_dirty(&my_out, &librustc_stamp);
|
||||
},
|
||||
Mode::ToolBootstrap => { },
|
||||
Mode::ToolStd => {
|
||||
self.clear_if_dirty(&my_out, &libstd_stamp);
|
||||
},
|
||||
Mode::ToolTest => {
|
||||
self.clear_if_dirty(&my_out, &libstd_stamp);
|
||||
self.clear_if_dirty(&my_out, &libtest_stamp);
|
||||
},
|
||||
Mode::ToolRustc => {
|
||||
self.clear_if_dirty(&my_out, &libstd_stamp);
|
||||
self.clear_if_dirty(&my_out, &libtest_stamp);
|
||||
self.clear_if_dirty(&my_out, &librustc_stamp);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
cargo
|
||||
@ -861,6 +805,19 @@ impl<'a> Builder<'a> {
|
||||
},
|
||||
}
|
||||
|
||||
// This tells Cargo (and in turn, rustc) to output more complete
|
||||
// dependency information. Most importantly for rustbuild, this
|
||||
// includes sysroot artifacts, like libstd, which means that we don't
|
||||
// need to track those in rustbuild (an error prone process!). This
|
||||
// feature is currently unstable as there may be some bugs and such, but
|
||||
// it represents a big improvement in rustbuild's reliability on
|
||||
// rebuilds, so we're using it here.
|
||||
//
|
||||
// For some additional context, see #63470 (the PR originally adding
|
||||
// this), as well as #63012 which is the tracking issue for this
|
||||
// feature on the rustc side.
|
||||
cargo.arg("-Zbinary-dep-depinfo");
|
||||
|
||||
cargo.arg("-j").arg(self.jobs().to_string());
|
||||
// Remove make-related flags to ensure Cargo can correctly set things up
|
||||
cargo.env_remove("MAKEFLAGS");
|
||||
@ -980,9 +937,6 @@ impl<'a> Builder<'a> {
|
||||
if let Some(target_linker) = self.linker(target) {
|
||||
cargo.env("RUSTC_TARGET_LINKER", target_linker);
|
||||
}
|
||||
if let Some(ref error_format) = self.config.rustc_error_format {
|
||||
cargo.env("RUSTC_ERROR_FORMAT", error_format);
|
||||
}
|
||||
if !(["build", "check", "clippy", "fix", "rustc"].contains(&cmd)) && want_rustdoc {
|
||||
cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(compiler));
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ fn cc2ar(cc: &Path, target: &str) -> Option<PathBuf> {
|
||||
} else if target.contains("openbsd") {
|
||||
Some(PathBuf::from("ar"))
|
||||
} else if target.contains("vxworks") {
|
||||
Some(PathBuf::from("vx-ar"))
|
||||
Some(PathBuf::from("wr-ar"))
|
||||
} else {
|
||||
let parent = cc.parent().unwrap();
|
||||
let file = cc.file_name().unwrap().to_str().unwrap();
|
||||
|
@ -13,7 +13,7 @@ use build_helper::output;
|
||||
use crate::Build;
|
||||
|
||||
// The version number
|
||||
pub const CFG_RELEASE_NUM: &str = "1.38.0";
|
||||
pub const CFG_RELEASE_NUM: &str = "1.39.0";
|
||||
|
||||
pub struct GitInfo {
|
||||
inner: Option<Info>,
|
||||
|
@ -245,7 +245,6 @@ impl Step for Rustdoc {
|
||||
let libdir = builder.sysroot_libdir(compiler, target);
|
||||
let hostdir = builder.sysroot_libdir(compiler, compiler.host);
|
||||
add_to_sysroot(&builder, &libdir, &hostdir, &rustdoc_stamp(builder, compiler, target));
|
||||
builder.cargo(compiler, Mode::ToolRustc, target, "clean");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ use std::path::{Path, PathBuf};
|
||||
use std::process::{Command, Stdio, exit};
|
||||
use std::str;
|
||||
|
||||
use build_helper::{output, mtime, t, up_to_date};
|
||||
use build_helper::{output, t, up_to_date};
|
||||
use filetime::FileTime;
|
||||
use serde::Deserialize;
|
||||
use serde_json;
|
||||
@ -274,8 +274,6 @@ impl Step for StdLink {
|
||||
// for reason why the sanitizers are not built in stage0.
|
||||
copy_apple_sanitizer_dylibs(builder, &builder.native_dir(target), "osx", &libdir);
|
||||
}
|
||||
|
||||
builder.cargo(target_compiler, Mode::ToolStd, target, "clean");
|
||||
}
|
||||
}
|
||||
|
||||
@ -480,8 +478,6 @@ impl Step for TestLink {
|
||||
&builder.sysroot_libdir(target_compiler, compiler.host),
|
||||
&libtest_stamp(builder, compiler, target)
|
||||
);
|
||||
|
||||
builder.cargo(target_compiler, Mode::ToolTest, target, "clean");
|
||||
}
|
||||
}
|
||||
|
||||
@ -639,7 +635,6 @@ impl Step for RustcLink {
|
||||
&builder.sysroot_libdir(target_compiler, compiler.host),
|
||||
&librustc_stamp(builder, compiler, target)
|
||||
);
|
||||
builder.cargo(target_compiler, Mode::ToolRustc, target, "clean");
|
||||
}
|
||||
}
|
||||
|
||||
@ -795,6 +790,9 @@ pub fn build_codegen_backend(builder: &Builder<'_>,
|
||||
if builder.config.llvm_use_libcxx {
|
||||
cargo.env("LLVM_USE_LIBCXX", "1");
|
||||
}
|
||||
if builder.config.llvm_optimize && !builder.config.llvm_release_debuginfo {
|
||||
cargo.env("LLVM_NDEBUG", "1");
|
||||
}
|
||||
}
|
||||
_ => panic!("unknown backend: {}", backend),
|
||||
}
|
||||
@ -1116,10 +1114,6 @@ pub fn run_cargo(builder: &Builder<'_>,
|
||||
},
|
||||
..
|
||||
} => (filenames, crate_types),
|
||||
CargoMessage::CompilerMessage { message } => {
|
||||
eprintln!("{}", message.rendered);
|
||||
return;
|
||||
}
|
||||
_ => return,
|
||||
};
|
||||
for filename in filenames {
|
||||
@ -1206,41 +1200,13 @@ pub fn run_cargo(builder: &Builder<'_>,
|
||||
deps.push((path_to_add.into(), false));
|
||||
}
|
||||
|
||||
// Now we want to update the contents of the stamp file, if necessary. First
|
||||
// we read off the previous contents along with its mtime. If our new
|
||||
// contents (the list of files to copy) is different or if any dep's mtime
|
||||
// is newer then we rewrite the stamp file.
|
||||
deps.sort();
|
||||
let stamp_contents = fs::read(stamp);
|
||||
let stamp_mtime = mtime(&stamp);
|
||||
let mut new_contents = Vec::new();
|
||||
let mut max = None;
|
||||
let mut max_path = None;
|
||||
for (dep, proc_macro) in deps.iter() {
|
||||
let mtime = mtime(dep);
|
||||
if Some(mtime) > max {
|
||||
max = Some(mtime);
|
||||
max_path = Some(dep.clone());
|
||||
}
|
||||
new_contents.extend(if *proc_macro { b"h" } else { b"t" });
|
||||
new_contents.extend(dep.to_str().unwrap().as_bytes());
|
||||
new_contents.extend(b"\0");
|
||||
}
|
||||
let max = max.unwrap();
|
||||
let max_path = max_path.unwrap();
|
||||
let contents_equal = stamp_contents
|
||||
.map(|contents| contents == new_contents)
|
||||
.unwrap_or_default();
|
||||
if contents_equal && max <= stamp_mtime {
|
||||
builder.verbose(&format!("not updating {:?}; contents equal and {:?} <= {:?}",
|
||||
stamp, max, stamp_mtime));
|
||||
return deps.into_iter().map(|(d, _)| d).collect()
|
||||
}
|
||||
if max > stamp_mtime {
|
||||
builder.verbose(&format!("updating {:?} as {:?} changed", stamp, max_path));
|
||||
} else {
|
||||
builder.verbose(&format!("updating {:?} as deps changed", stamp));
|
||||
}
|
||||
t!(fs::write(&stamp, &new_contents));
|
||||
deps.into_iter().map(|(d, _)| d).collect()
|
||||
}
|
||||
@ -1256,8 +1222,12 @@ pub fn stream_cargo(
|
||||
}
|
||||
// Instruct Cargo to give us json messages on stdout, critically leaving
|
||||
// stderr as piped so we can get those pretty colors.
|
||||
cargo.arg("--message-format").arg("json")
|
||||
.stdout(Stdio::piped());
|
||||
let mut message_format = String::from("json-render-diagnostics");
|
||||
if let Some(s) = &builder.config.rustc_error_format {
|
||||
message_format.push_str(",json-diagnostic-");
|
||||
message_format.push_str(s);
|
||||
}
|
||||
cargo.arg("--message-format").arg(message_format).stdout(Stdio::piped());
|
||||
|
||||
for arg in tail_args {
|
||||
cargo.arg(arg);
|
||||
@ -1310,12 +1280,4 @@ pub enum CargoMessage<'a> {
|
||||
BuildScriptExecuted {
|
||||
package_id: Cow<'a, str>,
|
||||
},
|
||||
CompilerMessage {
|
||||
message: ClippyMessage<'a>
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ClippyMessage<'a> {
|
||||
rendered: Cow<'a, str>,
|
||||
}
|
||||
|
@ -81,5 +81,14 @@ ci-subset-1:
|
||||
ci-subset-2:
|
||||
$(Q)$(BOOTSTRAP) test $(TESTS_IN_2)
|
||||
|
||||
TESTS_IN_MINGW_2 := \
|
||||
src/test/ui \
|
||||
src/test/compile-fail
|
||||
|
||||
ci-mingw-subset-1:
|
||||
$(Q)$(BOOTSTRAP) test $(TESTS_IN_MINGW_2:%=--exclude %)
|
||||
ci-mingw-subset-2:
|
||||
$(Q)$(BOOTSTRAP) test $(TESTS_IN_MINGW_2)
|
||||
|
||||
|
||||
.PHONY: dist
|
||||
|
@ -202,10 +202,6 @@ pub fn check(build: &mut Build) {
|
||||
panic!("couldn't find libc.a in musl dir: {}",
|
||||
root.join("lib").display());
|
||||
}
|
||||
if fs::metadata(root.join("lib/libunwind.a")).is_err() {
|
||||
panic!("couldn't find libunwind.a in musl dir: {}",
|
||||
root.join("lib").display());
|
||||
}
|
||||
}
|
||||
None => {
|
||||
panic!("when targeting MUSL either the rust.musl-root \
|
||||
|
@ -272,8 +272,8 @@ jobs:
|
||||
i686-mingw-1:
|
||||
MSYS_BITS: 32
|
||||
RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
|
||||
SCRIPT: make ci-subset-1
|
||||
MINGW_URL: https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror
|
||||
SCRIPT: make ci-mingw-subset-1
|
||||
MINGW_URL: https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc
|
||||
MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z
|
||||
MINGW_DIR: mingw32
|
||||
# FIXME(#59637)
|
||||
@ -282,15 +282,15 @@ jobs:
|
||||
i686-mingw-2:
|
||||
MSYS_BITS: 32
|
||||
RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
|
||||
SCRIPT: make ci-subset-2
|
||||
MINGW_URL: https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror
|
||||
SCRIPT: make ci-mingw-subset-2
|
||||
MINGW_URL: https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc
|
||||
MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z
|
||||
MINGW_DIR: mingw32
|
||||
x86_64-mingw-1:
|
||||
MSYS_BITS: 64
|
||||
SCRIPT: make ci-subset-1
|
||||
SCRIPT: make ci-mingw-subset-1
|
||||
RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu
|
||||
MINGW_URL: https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror
|
||||
MINGW_URL: https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc
|
||||
MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z
|
||||
MINGW_DIR: mingw64
|
||||
# FIXME(#59637)
|
||||
@ -298,9 +298,9 @@ jobs:
|
||||
NO_LLVM_ASSERTIONS: 1
|
||||
x86_64-mingw-2:
|
||||
MSYS_BITS: 64
|
||||
SCRIPT: make ci-subset-2
|
||||
SCRIPT: make ci-mingw-subset-2
|
||||
RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu
|
||||
MINGW_URL: https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror
|
||||
MINGW_URL: https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc
|
||||
MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z
|
||||
MINGW_DIR: mingw64
|
||||
|
||||
@ -327,7 +327,7 @@ jobs:
|
||||
MSYS_BITS: 32
|
||||
RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-full-tools --enable-profiler
|
||||
SCRIPT: python x.py dist
|
||||
MINGW_URL: https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror
|
||||
MINGW_URL: https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc
|
||||
MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z
|
||||
MINGW_DIR: mingw32
|
||||
DIST_REQUIRE_ALL_TOOLS: 1
|
||||
@ -336,7 +336,7 @@ jobs:
|
||||
MSYS_BITS: 64
|
||||
SCRIPT: python x.py dist
|
||||
RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler
|
||||
MINGW_URL: https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror
|
||||
MINGW_URL: https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc
|
||||
MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z
|
||||
MINGW_DIR: mingw64
|
||||
DIST_REQUIRE_ALL_TOOLS: 1
|
||||
|
@ -36,7 +36,7 @@ steps:
|
||||
set -e
|
||||
mkdir -p citools
|
||||
cd citools
|
||||
curl -f https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/LLVM-7.0.0-win64.tar.gz | tar xzf -
|
||||
curl -f https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/LLVM-7.0.0-win64.tar.gz | tar xzf -
|
||||
echo "##vso[task.setvariable variable=RUST_CONFIGURE_ARGS]$RUST_CONFIGURE_ARGS --set llvm.clang-cl=`pwd`/clang-rust/bin/clang-cl.exe"
|
||||
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), eq(variables['MINGW_URL'],''))
|
||||
displayName: Install clang (Windows)
|
||||
|
@ -2,14 +2,14 @@ steps:
|
||||
|
||||
- bash: |
|
||||
set -e
|
||||
curl -fo /usr/local/bin/sccache https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2018-04-02-sccache-x86_64-apple-darwin
|
||||
curl -fo /usr/local/bin/sccache https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/2018-04-02-sccache-x86_64-apple-darwin
|
||||
chmod +x /usr/local/bin/sccache
|
||||
displayName: Install sccache (OSX)
|
||||
condition: and(succeeded(), eq(variables['Agent.OS'], 'Darwin'))
|
||||
|
||||
- script: |
|
||||
md sccache
|
||||
powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf sccache\sccache.exe https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2018-04-26-sccache-x86_64-pc-windows-msvc"
|
||||
powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf sccache\sccache.exe https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/2018-04-26-sccache-x86_64-pc-windows-msvc"
|
||||
echo ##vso[task.prependpath]%CD%\sccache
|
||||
displayName: Install sccache (Windows)
|
||||
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
|
||||
|
@ -4,7 +4,7 @@ steps:
|
||||
# https://github.com/wixtoolset/wix3 originally
|
||||
- bash: |
|
||||
set -e
|
||||
curl -O https://rust-lang-ci2.s3-us-west-1.amazonaws.com/rust-ci-mirror/wix311-binaries.zip
|
||||
curl -O https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/wix311-binaries.zip
|
||||
echo "##vso[task.setvariable variable=WIX]`pwd`/wix"
|
||||
mkdir -p wix/bin
|
||||
cd wix/bin
|
||||
@ -18,7 +18,7 @@ steps:
|
||||
# one is MSI installers and one is EXE, but they're not used so frequently at
|
||||
# this point anyway so perhaps it's a wash!
|
||||
- script: |
|
||||
powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf is-install.exe https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2017-08-22-is.exe"
|
||||
powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf is-install.exe https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/2017-08-22-is.exe"
|
||||
is-install.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP-
|
||||
echo ##vso[task.prependpath]C:\Program Files (x86)\Inno Setup 5
|
||||
displayName: Install InnoSetup
|
||||
@ -109,7 +109,7 @@ steps:
|
||||
# Note that this is originally from the github releases patch of Ninja
|
||||
- script: |
|
||||
md ninja
|
||||
powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf 2017-03-15-ninja-win.zip https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2017-03-15-ninja-win.zip"
|
||||
powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf 2017-03-15-ninja-win.zip https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/2017-03-15-ninja-win.zip"
|
||||
7z x -oninja 2017-03-15-ninja-win.zip
|
||||
del 2017-03-15-ninja-win.zip
|
||||
set RUST_CONFIGURE_ARGS=%RUST_CONFIGURE_ARGS% --enable-ninja
|
||||
|
@ -199,7 +199,7 @@ steps:
|
||||
# Upload CPU usage statistics that we've been gathering this whole time. Always
|
||||
# execute this step in case we want to inspect failed builds, but don't let
|
||||
# errors here ever fail the build since this is just informational.
|
||||
- bash: aws s3 cp --acl public-read cpu-usage.csv s3://$DEPLOY_BUCKET/rustc-builds/$BUILD_SOURCEVERSION/cpu-$SYSTEM_JOBNAME.csv
|
||||
- bash: aws s3 cp --acl public-read cpu-usage.csv s3://$DEPLOY_BUCKET/rustc-builds/$BUILD_SOURCEVERSION/cpu-$CI_JOB_NAME.csv
|
||||
env:
|
||||
AWS_SECRET_ACCESS_KEY: $(AWS_SECRET_ACCESS_KEY)
|
||||
condition: variables['AWS_SECRET_ACCESS_KEY']
|
||||
|
@ -72,7 +72,7 @@ RUN arm-linux-gnueabihf-gcc addentropy.c -o rootfs/addentropy -static
|
||||
|
||||
# TODO: What is this?!
|
||||
# Source of the file: https://github.com/vfdev-5/qemu-rpi2-vexpress/raw/master/vexpress-v2p-ca15-tc1.dtb
|
||||
RUN curl -O https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/vexpress-v2p-ca15-tc1.dtb
|
||||
RUN curl -O https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/vexpress-v2p-ca15-tc1.dtb
|
||||
|
||||
COPY scripts/sccache.sh /scripts/
|
||||
RUN sh /scripts/sccache.sh
|
||||
|
@ -5,7 +5,7 @@ mkdir /usr/local/mips-linux-musl
|
||||
# originally from
|
||||
# https://downloads.openwrt.org/snapshots/trunk/ar71xx/generic/
|
||||
# OpenWrt-Toolchain-ar71xx-generic_gcc-5.3.0_musl-1.1.16.Linux-x86_64.tar.bz2
|
||||
URL="https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror"
|
||||
URL="https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc"
|
||||
FILE="OpenWrt-Toolchain-ar71xx-generic_gcc-5.3.0_musl-1.1.16.Linux-x86_64.tar.bz2"
|
||||
curl -L "$URL/$FILE" | tar xjf - -C /usr/local/mips-linux-musl --strip-components=2
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
set -ex
|
||||
|
||||
# Originally from https://releases.llvm.org/8.0.0/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-14.04.tar.xz
|
||||
curl https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/clang%2Bllvm-8.0.0-x86_64-linux-gnu-ubuntu-14.04.tar.xz | \
|
||||
curl https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/clang%2Bllvm-8.0.0-x86_64-linux-gnu-ubuntu-14.04.tar.xz | \
|
||||
tar xJf -
|
||||
export PATH=`pwd`/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-14.04/bin:$PATH
|
||||
|
||||
|
@ -4,7 +4,7 @@ set -ex
|
||||
source shared.sh
|
||||
|
||||
VERSION=1.0.2k
|
||||
URL=https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/openssl-$VERSION.tar.gz
|
||||
URL=https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/openssl-$VERSION.tar.gz
|
||||
|
||||
curl $URL | tar xzf -
|
||||
|
||||
|
@ -25,7 +25,7 @@ cd netbsd
|
||||
|
||||
mkdir -p /x-tools/x86_64-unknown-netbsd/sysroot
|
||||
|
||||
URL=https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror
|
||||
URL=https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc
|
||||
|
||||
# Originally from ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-$BSD/source/sets/*.tgz
|
||||
curl $URL/2018-03-01-netbsd-src.tgz | tar xzf -
|
||||
|
@ -23,8 +23,9 @@ REPOSITORIES = [
|
||||
HOST_OS = "linux"
|
||||
|
||||
# Mirroring options
|
||||
MIRROR_BUCKET = "rust-lang-ci2"
|
||||
MIRROR_BASE_DIR = "rust-ci-mirror/android/"
|
||||
MIRROR_BUCKET = "rust-lang-ci-mirrors"
|
||||
MIRROR_BUCKET_REGION = "us-west-1"
|
||||
MIRROR_BASE_DIR = "rustc/android/"
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
@ -144,7 +145,8 @@ def cli_install(args):
|
||||
lockfile = Lockfile(args.lockfile)
|
||||
for package in lockfile.packages.values():
|
||||
# Download the file from the mirror into a temp file
|
||||
url = "https://" + MIRROR_BUCKET + ".s3.amazonaws.com/" + MIRROR_BASE_DIR
|
||||
url = "https://" + MIRROR_BUCKET + ".s3-" + MIRROR_BUCKET_REGION + \
|
||||
".amazonaws.com/" + MIRROR_BASE_DIR
|
||||
downloaded = package.download(url)
|
||||
# Extract the file in a temporary directory
|
||||
extract_dir = tempfile.mkdtemp()
|
||||
|
@ -59,7 +59,7 @@ done
|
||||
|
||||
# Originally downloaded from:
|
||||
# https://download.freebsd.org/ftp/releases/${freebsd_arch}/${freebsd_version}-RELEASE/base.txz
|
||||
URL=https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2019-04-04-freebsd-${freebsd_arch}-${freebsd_version}-RELEASE-base.txz
|
||||
URL=https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/2019-04-04-freebsd-${freebsd_arch}-${freebsd_version}-RELEASE-base.txz
|
||||
curl "$URL" | tar xJf - -C "$sysroot" --wildcards "${files_to_extract[@]}"
|
||||
|
||||
# Fix up absolute symlinks from the system image. This can be removed
|
||||
|
@ -54,29 +54,3 @@ if [ "$REPLACE_CC" = "1" ]; then
|
||||
ln -s $TARGET-g++ /usr/local/bin/$exec
|
||||
done
|
||||
fi
|
||||
|
||||
export CC=$TARGET-gcc
|
||||
export CXX=$TARGET-g++
|
||||
|
||||
LLVM=70
|
||||
|
||||
# may have been downloaded in a previous run
|
||||
if [ ! -d libunwind-release_$LLVM ]; then
|
||||
curl -L https://github.com/llvm-mirror/llvm/archive/release_$LLVM.tar.gz | tar xzf -
|
||||
curl -L https://github.com/llvm-mirror/libunwind/archive/release_$LLVM.tar.gz | tar xzf -
|
||||
fi
|
||||
|
||||
# fixme(mati865): Replace it with https://github.com/rust-lang/rust/pull/59089
|
||||
mkdir libunwind-build
|
||||
cd libunwind-build
|
||||
cmake ../libunwind-release_$LLVM \
|
||||
-DLLVM_PATH=/build/llvm-release_$LLVM \
|
||||
-DLIBUNWIND_ENABLE_SHARED=0 \
|
||||
-DCMAKE_C_COMPILER=$CC \
|
||||
-DCMAKE_CXX_COMPILER=$CXX \
|
||||
-DCMAKE_C_FLAGS="$CFLAGS" \
|
||||
-DCMAKE_CXX_FLAGS="$CXXFLAGS"
|
||||
|
||||
hide_output make -j$(nproc)
|
||||
cp lib/libunwind.a $OUTPUT/$TARGET/lib
|
||||
cd - && rm -rf libunwind-build
|
||||
|
@ -20,6 +20,8 @@ exit 1
|
||||
TAG=$1
|
||||
shift
|
||||
|
||||
# Ancient binutils versions don't understand debug symbols produced by more recent tools.
|
||||
# Apparently applying `-fPIC` everywhere allows them to link successfully.
|
||||
export CFLAGS="-fPIC $CFLAGS"
|
||||
|
||||
MUSL=musl-1.1.22
|
||||
@ -38,27 +40,3 @@ else
|
||||
fi
|
||||
hide_output make install
|
||||
hide_output make clean
|
||||
|
||||
cd ..
|
||||
|
||||
LLVM=70
|
||||
|
||||
# may have been downloaded in a previous run
|
||||
if [ ! -d libunwind-release_$LLVM ]; then
|
||||
curl -L https://github.com/llvm-mirror/llvm/archive/release_$LLVM.tar.gz | tar xzf -
|
||||
curl -L https://github.com/llvm-mirror/libunwind/archive/release_$LLVM.tar.gz | tar xzf -
|
||||
fi
|
||||
|
||||
mkdir libunwind-build
|
||||
cd libunwind-build
|
||||
cmake ../libunwind-release_$LLVM \
|
||||
-DLLVM_PATH=/build/llvm-release_$LLVM \
|
||||
-DLIBUNWIND_ENABLE_SHARED=0 \
|
||||
-DCMAKE_C_COMPILER=$CC \
|
||||
-DCMAKE_CXX_COMPILER=$CXX \
|
||||
-DCMAKE_C_FLAGS="$CFLAGS" \
|
||||
-DCMAKE_CXX_FLAGS="$CXXFLAGS"
|
||||
|
||||
hide_output make -j$(nproc)
|
||||
cp lib/libunwind.a /musl-$TAG/lib
|
||||
cd ../ && rm -rf libunwind-build
|
||||
|
@ -1,6 +1,6 @@
|
||||
set -ex
|
||||
|
||||
curl -fo /usr/local/bin/sccache \
|
||||
https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2018-04-02-sccache-x86_64-unknown-linux-musl
|
||||
https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/2018-04-02-sccache-x86_64-unknown-linux-musl
|
||||
|
||||
chmod +x /usr/local/bin/sccache
|
||||
|
@ -16,7 +16,7 @@
|
||||
set -euo pipefail
|
||||
IFS=$'\n\t'
|
||||
|
||||
MIRROR="https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2019-07-27-awscli.tar"
|
||||
MIRROR="https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/2019-07-27-awscli.tar"
|
||||
DEPS_DIR="/tmp/awscli-deps"
|
||||
|
||||
pip="pip"
|
||||
|
@ -78,6 +78,21 @@ if [ "$RUST_RELEASE_CHANNEL" = "nightly" ] || [ "$DIST_REQUIRE_ALL_TOOLS" = "" ]
|
||||
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-missing-tools"
|
||||
fi
|
||||
|
||||
# Print the date from the local machine and the date from an external source to
|
||||
# check for clock drifts. An HTTP URL is used instead of HTTPS since on Azure
|
||||
# Pipelines it happened that the certificates were marked as expired.
|
||||
datecheck() {
|
||||
echo "== clock drift check =="
|
||||
echo -n " local time: "
|
||||
date
|
||||
echo -n " network time: "
|
||||
curl -fs --head http://detectportal.firefox.com/success.txt | grep ^Date: \
|
||||
| sed 's/Date: //g' || true
|
||||
echo "== end clock drift check =="
|
||||
}
|
||||
datecheck
|
||||
trap datecheck EXIT
|
||||
|
||||
# We've had problems in the past of shell scripts leaking fds into the sccache
|
||||
# server (#48192) which causes Cargo to erroneously think that a build script
|
||||
# hasn't finished yet. Try to solve that problem by starting a very long-lived
|
||||
|
@ -1163,6 +1163,9 @@ impl<T> FusedIterator for Drain<'_, T> {}
|
||||
|
||||
#[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
|
||||
impl<T: Ord> From<Vec<T>> for BinaryHeap<T> {
|
||||
/// Converts a `Vec<T>` into a `BinaryHeap<T>`.
|
||||
///
|
||||
/// This conversion happens in-place, and has `O(n)` time complexity.
|
||||
fn from(vec: Vec<T>) -> BinaryHeap<T> {
|
||||
let mut heap = BinaryHeap { data: vec };
|
||||
heap.rebuild();
|
||||
|
@ -106,8 +106,8 @@ impl<K, V> LeafNode<K, V> {
|
||||
LeafNode {
|
||||
// As a general policy, we leave fields uninitialized if they can be, as this should
|
||||
// be both slightly faster and easier to track in Valgrind.
|
||||
keys: uninit_array![_; CAPACITY],
|
||||
vals: uninit_array![_; CAPACITY],
|
||||
keys: [MaybeUninit::UNINIT; CAPACITY],
|
||||
vals: [MaybeUninit::UNINIT; CAPACITY],
|
||||
parent: ptr::null(),
|
||||
parent_idx: MaybeUninit::uninit(),
|
||||
len: 0
|
||||
@ -159,7 +159,7 @@ impl<K, V> InternalNode<K, V> {
|
||||
unsafe fn new() -> Self {
|
||||
InternalNode {
|
||||
data: LeafNode::new(),
|
||||
edges: uninit_array![_; 2*B],
|
||||
edges: [MaybeUninit::UNINIT; 2*B]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,32 +41,35 @@ pub use linked_list::LinkedList;
|
||||
#[doc(no_inline)]
|
||||
pub use vec_deque::VecDeque;
|
||||
|
||||
use crate::alloc::{AllocErr, LayoutErr};
|
||||
use crate::alloc::{Layout, LayoutErr};
|
||||
|
||||
/// Augments `AllocErr` with a CapacityOverflow variant.
|
||||
/// The error type for `try_reserve` methods.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
|
||||
pub enum CollectionAllocErr {
|
||||
pub enum TryReserveError {
|
||||
/// Error due to the computed capacity exceeding the collection's maximum
|
||||
/// (usually `isize::MAX` bytes).
|
||||
CapacityOverflow,
|
||||
/// Error due to the allocator (see the `AllocErr` type's docs).
|
||||
AllocErr,
|
||||
|
||||
/// The memory allocator returned an error
|
||||
AllocError {
|
||||
/// The layout of allocation request that failed
|
||||
layout: Layout,
|
||||
|
||||
#[doc(hidden)]
|
||||
#[unstable(feature = "container_error_extra", issue = "0", reason = "\
|
||||
Enable exposing the allocator’s custom error value \
|
||||
if an associated type is added in the future: \
|
||||
https://github.com/rust-lang/wg-allocators/issues/23")]
|
||||
non_exhaustive: (),
|
||||
},
|
||||
}
|
||||
|
||||
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
|
||||
impl From<AllocErr> for CollectionAllocErr {
|
||||
#[inline]
|
||||
fn from(AllocErr: AllocErr) -> Self {
|
||||
CollectionAllocErr::AllocErr
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
|
||||
impl From<LayoutErr> for CollectionAllocErr {
|
||||
impl From<LayoutErr> for TryReserveError {
|
||||
#[inline]
|
||||
fn from(_: LayoutErr) -> Self {
|
||||
CollectionAllocErr::CapacityOverflow
|
||||
TryReserveError::CapacityOverflow
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ use core::ptr::{self, NonNull};
|
||||
use core::slice;
|
||||
use core::hash::{Hash, Hasher};
|
||||
|
||||
use crate::collections::CollectionAllocErr;
|
||||
use crate::collections::TryReserveError;
|
||||
use crate::raw_vec::RawVec;
|
||||
use crate::vec::Vec;
|
||||
|
||||
@ -576,10 +576,10 @@ impl<T> VecDeque<T> {
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(try_reserve)]
|
||||
/// use std::collections::CollectionAllocErr;
|
||||
/// use std::collections::TryReserveError;
|
||||
/// use std::collections::VecDeque;
|
||||
///
|
||||
/// fn process_data(data: &[u32]) -> Result<VecDeque<u32>, CollectionAllocErr> {
|
||||
/// fn process_data(data: &[u32]) -> Result<VecDeque<u32>, TryReserveError> {
|
||||
/// let mut output = VecDeque::new();
|
||||
///
|
||||
/// // Pre-reserve the memory, exiting if we can't
|
||||
@ -595,7 +595,7 @@ impl<T> VecDeque<T> {
|
||||
/// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
|
||||
/// ```
|
||||
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
|
||||
pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), CollectionAllocErr> {
|
||||
pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
|
||||
self.try_reserve(additional)
|
||||
}
|
||||
|
||||
@ -614,10 +614,10 @@ impl<T> VecDeque<T> {
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(try_reserve)]
|
||||
/// use std::collections::CollectionAllocErr;
|
||||
/// use std::collections::TryReserveError;
|
||||
/// use std::collections::VecDeque;
|
||||
///
|
||||
/// fn process_data(data: &[u32]) -> Result<VecDeque<u32>, CollectionAllocErr> {
|
||||
/// fn process_data(data: &[u32]) -> Result<VecDeque<u32>, TryReserveError> {
|
||||
/// let mut output = VecDeque::new();
|
||||
///
|
||||
/// // Pre-reserve the memory, exiting if we can't
|
||||
@ -633,12 +633,12 @@ impl<T> VecDeque<T> {
|
||||
/// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
|
||||
/// ```
|
||||
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
|
||||
pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> {
|
||||
pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
|
||||
let old_cap = self.cap();
|
||||
let used_cap = self.len() + 1;
|
||||
let new_cap = used_cap.checked_add(additional)
|
||||
.and_then(|needed_cap| needed_cap.checked_next_power_of_two())
|
||||
.ok_or(CollectionAllocErr::CapacityOverflow)?;
|
||||
.ok_or(TryReserveError::CapacityOverflow)?;
|
||||
|
||||
if new_cap > old_cap {
|
||||
self.buf.try_reserve_exact(used_cap, new_cap - used_cap)?;
|
||||
|
@ -69,7 +69,7 @@
|
||||
#![warn(missing_debug_implementations)]
|
||||
#![deny(intra_doc_link_resolution_failure)] // rustdoc is run without -D warnings
|
||||
#![allow(explicit_outlives_requirements)]
|
||||
#![cfg_attr(not(bootstrap), allow(incomplete_features))]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
#![cfg_attr(not(test), feature(generator_trait))]
|
||||
#![cfg_attr(test, feature(test))]
|
||||
@ -84,9 +84,10 @@
|
||||
#![feature(coerce_unsized)]
|
||||
#![feature(const_generic_impls_guard)]
|
||||
#![feature(const_generics)]
|
||||
#![cfg_attr(not(bootstrap), feature(const_in_array_repeat_expressions))]
|
||||
#![feature(const_in_array_repeat_expressions)]
|
||||
#![feature(dispatch_from_dyn)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(container_error_extra)]
|
||||
#![feature(dropck_eyepatch)]
|
||||
#![feature(exact_size_is_empty)]
|
||||
#![feature(fmt_internals)]
|
||||
@ -118,7 +119,7 @@
|
||||
#![feature(rustc_const_unstable)]
|
||||
#![feature(const_vec_new)]
|
||||
#![feature(slice_partition_dedup)]
|
||||
#![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_array)]
|
||||
#![feature(maybe_uninit_extra, maybe_uninit_slice)]
|
||||
#![feature(alloc_layout_extra)]
|
||||
#![feature(try_trait)]
|
||||
#![feature(mem_take)]
|
||||
|
@ -98,5 +98,5 @@ macro_rules! vec {
|
||||
#[macro_export]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
macro_rules! format {
|
||||
($($arg:tt)*) => ($crate::fmt::format(format_args!($($arg)*)))
|
||||
($($arg:tt)*) => ($crate::fmt::format(::core::format_args!($($arg)*)))
|
||||
}
|
||||
|
@ -7,8 +7,8 @@ use core::ops::Drop;
|
||||
use core::ptr::{self, NonNull, Unique};
|
||||
use core::slice;
|
||||
|
||||
use crate::alloc::{Alloc, Layout, Global, handle_alloc_error};
|
||||
use crate::collections::CollectionAllocErr::{self, *};
|
||||
use crate::alloc::{Alloc, Layout, Global, AllocErr, handle_alloc_error};
|
||||
use crate::collections::TryReserveError::{self, *};
|
||||
use crate::boxed::Box;
|
||||
|
||||
#[cfg(test)]
|
||||
@ -385,7 +385,7 @@ impl<T, A: Alloc> RawVec<T, A> {
|
||||
|
||||
/// The same as `reserve_exact`, but returns on errors instead of panicking or aborting.
|
||||
pub fn try_reserve_exact(&mut self, used_capacity: usize, needed_extra_capacity: usize)
|
||||
-> Result<(), CollectionAllocErr> {
|
||||
-> Result<(), TryReserveError> {
|
||||
|
||||
self.reserve_internal(used_capacity, needed_extra_capacity, Fallible, Exact)
|
||||
}
|
||||
@ -413,7 +413,7 @@ impl<T, A: Alloc> RawVec<T, A> {
|
||||
pub fn reserve_exact(&mut self, used_capacity: usize, needed_extra_capacity: usize) {
|
||||
match self.reserve_internal(used_capacity, needed_extra_capacity, Infallible, Exact) {
|
||||
Err(CapacityOverflow) => capacity_overflow(),
|
||||
Err(AllocErr) => unreachable!(),
|
||||
Err(AllocError { .. }) => unreachable!(),
|
||||
Ok(()) => { /* yay */ }
|
||||
}
|
||||
}
|
||||
@ -422,7 +422,7 @@ impl<T, A: Alloc> RawVec<T, A> {
|
||||
/// needed_extra_capacity` elements. This logic is used in amortized reserve methods.
|
||||
/// Returns `(new_capacity, new_alloc_size)`.
|
||||
fn amortized_new_size(&self, used_capacity: usize, needed_extra_capacity: usize)
|
||||
-> Result<usize, CollectionAllocErr> {
|
||||
-> Result<usize, TryReserveError> {
|
||||
|
||||
// Nothing we can really do about these checks :(
|
||||
let required_cap = used_capacity.checked_add(needed_extra_capacity)
|
||||
@ -435,7 +435,7 @@ impl<T, A: Alloc> RawVec<T, A> {
|
||||
|
||||
/// The same as `reserve`, but returns on errors instead of panicking or aborting.
|
||||
pub fn try_reserve(&mut self, used_capacity: usize, needed_extra_capacity: usize)
|
||||
-> Result<(), CollectionAllocErr> {
|
||||
-> Result<(), TryReserveError> {
|
||||
self.reserve_internal(used_capacity, needed_extra_capacity, Fallible, Amortized)
|
||||
}
|
||||
|
||||
@ -494,7 +494,7 @@ impl<T, A: Alloc> RawVec<T, A> {
|
||||
pub fn reserve(&mut self, used_capacity: usize, needed_extra_capacity: usize) {
|
||||
match self.reserve_internal(used_capacity, needed_extra_capacity, Infallible, Amortized) {
|
||||
Err(CapacityOverflow) => capacity_overflow(),
|
||||
Err(AllocErr) => unreachable!(),
|
||||
Err(AllocError { .. }) => unreachable!(),
|
||||
Ok(()) => { /* yay */ }
|
||||
}
|
||||
}
|
||||
@ -640,10 +640,8 @@ impl<T, A: Alloc> RawVec<T, A> {
|
||||
needed_extra_capacity: usize,
|
||||
fallibility: Fallibility,
|
||||
strategy: ReserveStrategy,
|
||||
) -> Result<(), CollectionAllocErr> {
|
||||
) -> Result<(), TryReserveError> {
|
||||
unsafe {
|
||||
use crate::alloc::AllocErr;
|
||||
|
||||
// NOTE: we don't early branch on ZSTs here because we want this
|
||||
// to actually catch "asking for more than usize::MAX" in that case.
|
||||
// If we make it past the first branch then we are guaranteed to
|
||||
@ -672,12 +670,16 @@ impl<T, A: Alloc> RawVec<T, A> {
|
||||
None => self.a.alloc(new_layout),
|
||||
};
|
||||
|
||||
match (&res, fallibility) {
|
||||
let ptr = match (res, fallibility) {
|
||||
(Err(AllocErr), Infallible) => handle_alloc_error(new_layout),
|
||||
_ => {}
|
||||
}
|
||||
(Err(AllocErr), Fallible) => return Err(TryReserveError::AllocError {
|
||||
layout: new_layout,
|
||||
non_exhaustive: (),
|
||||
}),
|
||||
(Ok(ptr), _) => ptr,
|
||||
};
|
||||
|
||||
self.ptr = res?.cast().into();
|
||||
self.ptr = ptr.cast().into();
|
||||
self.cap = new_cap;
|
||||
|
||||
Ok(())
|
||||
@ -737,7 +739,7 @@ unsafe impl<#[may_dangle] T, A: Alloc> Drop for RawVec<T, A> {
|
||||
// all 4GB in user-space. e.g., PAE or x32
|
||||
|
||||
#[inline]
|
||||
fn alloc_guard(alloc_size: usize) -> Result<(), CollectionAllocErr> {
|
||||
fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> {
|
||||
if mem::size_of::<usize>() < 8 && alloc_size > core::isize::MAX as usize {
|
||||
Err(CapacityOverflow)
|
||||
} else {
|
||||
|
@ -56,7 +56,7 @@ use core::ptr;
|
||||
use core::str::{pattern::Pattern, lossy};
|
||||
|
||||
use crate::borrow::{Cow, ToOwned};
|
||||
use crate::collections::CollectionAllocErr;
|
||||
use crate::collections::TryReserveError;
|
||||
use crate::boxed::Box;
|
||||
use crate::str::{self, from_boxed_utf8_unchecked, FromStr, Utf8Error, Chars};
|
||||
use crate::vec::Vec;
|
||||
@ -937,9 +937,9 @@ impl String {
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(try_reserve)]
|
||||
/// use std::collections::CollectionAllocErr;
|
||||
/// use std::collections::TryReserveError;
|
||||
///
|
||||
/// fn process_data(data: &str) -> Result<String, CollectionAllocErr> {
|
||||
/// fn process_data(data: &str) -> Result<String, TryReserveError> {
|
||||
/// let mut output = String::new();
|
||||
///
|
||||
/// // Pre-reserve the memory, exiting if we can't
|
||||
@ -953,7 +953,7 @@ impl String {
|
||||
/// # process_data("rust").expect("why is the test harness OOMing on 4 bytes?");
|
||||
/// ```
|
||||
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
|
||||
pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> {
|
||||
pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
|
||||
self.vec.try_reserve(additional)
|
||||
}
|
||||
|
||||
@ -975,9 +975,9 @@ impl String {
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(try_reserve)]
|
||||
/// use std::collections::CollectionAllocErr;
|
||||
/// use std::collections::TryReserveError;
|
||||
///
|
||||
/// fn process_data(data: &str) -> Result<String, CollectionAllocErr> {
|
||||
/// fn process_data(data: &str) -> Result<String, TryReserveError> {
|
||||
/// let mut output = String::new();
|
||||
///
|
||||
/// // Pre-reserve the memory, exiting if we can't
|
||||
@ -991,7 +991,7 @@ impl String {
|
||||
/// # process_data("rust").expect("why is the test harness OOMing on 4 bytes?");
|
||||
/// ```
|
||||
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
|
||||
pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), CollectionAllocErr> {
|
||||
pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
|
||||
self.vec.try_reserve_exact(additional)
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use std::borrow::Cow;
|
||||
use std::collections::CollectionAllocErr::*;
|
||||
use std::collections::TryReserveError::*;
|
||||
use std::mem::size_of;
|
||||
use std::{usize, isize};
|
||||
|
||||
@ -566,11 +566,11 @@ fn test_try_reserve() {
|
||||
} else { panic!("usize::MAX should trigger an overflow!") }
|
||||
} else {
|
||||
// Check isize::MAX + 1 is an OOM
|
||||
if let Err(AllocErr) = empty_string.try_reserve(MAX_CAP + 1) {
|
||||
if let Err(AllocError { .. }) = empty_string.try_reserve(MAX_CAP + 1) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
|
||||
// Check usize::MAX is an OOM
|
||||
if let Err(AllocErr) = empty_string.try_reserve(MAX_USIZE) {
|
||||
if let Err(AllocError { .. }) = empty_string.try_reserve(MAX_USIZE) {
|
||||
} else { panic!("usize::MAX should trigger an OOM!") }
|
||||
}
|
||||
}
|
||||
@ -590,7 +590,7 @@ fn test_try_reserve() {
|
||||
if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
|
||||
} else {
|
||||
if let Err(AllocErr) = ten_bytes.try_reserve(MAX_CAP - 9) {
|
||||
if let Err(AllocError { .. }) = ten_bytes.try_reserve(MAX_CAP - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
}
|
||||
// Should always overflow in the add-to-len
|
||||
@ -629,10 +629,10 @@ fn test_try_reserve_exact() {
|
||||
if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_USIZE) {
|
||||
} else { panic!("usize::MAX should trigger an overflow!") }
|
||||
} else {
|
||||
if let Err(AllocErr) = empty_string.try_reserve_exact(MAX_CAP + 1) {
|
||||
if let Err(AllocError { .. }) = empty_string.try_reserve_exact(MAX_CAP + 1) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
|
||||
if let Err(AllocErr) = empty_string.try_reserve_exact(MAX_USIZE) {
|
||||
if let Err(AllocError { .. }) = empty_string.try_reserve_exact(MAX_USIZE) {
|
||||
} else { panic!("usize::MAX should trigger an OOM!") }
|
||||
}
|
||||
}
|
||||
@ -651,7 +651,7 @@ fn test_try_reserve_exact() {
|
||||
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
|
||||
} else {
|
||||
if let Err(AllocErr) = ten_bytes.try_reserve_exact(MAX_CAP - 9) {
|
||||
if let Err(AllocError { .. }) = ten_bytes.try_reserve_exact(MAX_CAP - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
}
|
||||
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) {
|
||||
|
@ -2,7 +2,7 @@ use std::borrow::Cow;
|
||||
use std::mem::size_of;
|
||||
use std::{usize, isize};
|
||||
use std::vec::{Drain, IntoIter};
|
||||
use std::collections::CollectionAllocErr::*;
|
||||
use std::collections::TryReserveError::*;
|
||||
|
||||
struct DropCounter<'a> {
|
||||
count: &'a mut u32,
|
||||
@ -1121,11 +1121,11 @@ fn test_try_reserve() {
|
||||
} else { panic!("usize::MAX should trigger an overflow!") }
|
||||
} else {
|
||||
// Check isize::MAX + 1 is an OOM
|
||||
if let Err(AllocErr) = empty_bytes.try_reserve(MAX_CAP + 1) {
|
||||
if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_CAP + 1) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
|
||||
// Check usize::MAX is an OOM
|
||||
if let Err(AllocErr) = empty_bytes.try_reserve(MAX_USIZE) {
|
||||
if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE) {
|
||||
} else { panic!("usize::MAX should trigger an OOM!") }
|
||||
}
|
||||
}
|
||||
@ -1145,7 +1145,7 @@ fn test_try_reserve() {
|
||||
if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
|
||||
} else {
|
||||
if let Err(AllocErr) = ten_bytes.try_reserve(MAX_CAP - 9) {
|
||||
if let Err(AllocError { .. }) = ten_bytes.try_reserve(MAX_CAP - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
}
|
||||
// Should always overflow in the add-to-len
|
||||
@ -1168,7 +1168,7 @@ fn test_try_reserve() {
|
||||
if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP/4 - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
|
||||
} else {
|
||||
if let Err(AllocErr) = ten_u32s.try_reserve(MAX_CAP/4 - 9) {
|
||||
if let Err(AllocError { .. }) = ten_u32s.try_reserve(MAX_CAP/4 - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
}
|
||||
// Should fail in the mul-by-size
|
||||
@ -1209,10 +1209,10 @@ fn test_try_reserve_exact() {
|
||||
if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_USIZE) {
|
||||
} else { panic!("usize::MAX should trigger an overflow!") }
|
||||
} else {
|
||||
if let Err(AllocErr) = empty_bytes.try_reserve_exact(MAX_CAP + 1) {
|
||||
if let Err(AllocError { .. }) = empty_bytes.try_reserve_exact(MAX_CAP + 1) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
|
||||
if let Err(AllocErr) = empty_bytes.try_reserve_exact(MAX_USIZE) {
|
||||
if let Err(AllocError { .. }) = empty_bytes.try_reserve_exact(MAX_USIZE) {
|
||||
} else { panic!("usize::MAX should trigger an OOM!") }
|
||||
}
|
||||
}
|
||||
@ -1231,7 +1231,7 @@ fn test_try_reserve_exact() {
|
||||
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
|
||||
} else {
|
||||
if let Err(AllocErr) = ten_bytes.try_reserve_exact(MAX_CAP - 9) {
|
||||
if let Err(AllocError { .. }) = ten_bytes.try_reserve_exact(MAX_CAP - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
}
|
||||
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) {
|
||||
@ -1252,7 +1252,7 @@ fn test_try_reserve_exact() {
|
||||
if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
|
||||
} else {
|
||||
if let Err(AllocErr) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) {
|
||||
if let Err(AllocError { .. }) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
}
|
||||
if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_USIZE - 20) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::fmt::Debug;
|
||||
use std::collections::{VecDeque, vec_deque::Drain};
|
||||
use std::collections::CollectionAllocErr::*;
|
||||
use std::collections::TryReserveError::*;
|
||||
use std::mem::size_of;
|
||||
use std::{usize, isize};
|
||||
|
||||
@ -1168,7 +1168,7 @@ fn test_try_reserve() {
|
||||
// VecDeque starts with capacity 7, always adds 1 to the capacity
|
||||
// and also rounds the number to next power of 2 so this is the
|
||||
// furthest we can go without triggering CapacityOverflow
|
||||
if let Err(AllocErr) = empty_bytes.try_reserve(MAX_CAP) {
|
||||
if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_CAP) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
}
|
||||
}
|
||||
@ -1188,7 +1188,7 @@ fn test_try_reserve() {
|
||||
if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
|
||||
} else {
|
||||
if let Err(AllocErr) = ten_bytes.try_reserve(MAX_CAP - 9) {
|
||||
if let Err(AllocError { .. }) = ten_bytes.try_reserve(MAX_CAP - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
}
|
||||
// Should always overflow in the add-to-len
|
||||
@ -1211,7 +1211,7 @@ fn test_try_reserve() {
|
||||
if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP/4 - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
|
||||
} else {
|
||||
if let Err(AllocErr) = ten_u32s.try_reserve(MAX_CAP/4 - 9) {
|
||||
if let Err(AllocError { .. }) = ten_u32s.try_reserve(MAX_CAP/4 - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
}
|
||||
// Should fail in the mul-by-size
|
||||
@ -1256,7 +1256,7 @@ fn test_try_reserve_exact() {
|
||||
// VecDeque starts with capacity 7, always adds 1 to the capacity
|
||||
// and also rounds the number to next power of 2 so this is the
|
||||
// furthest we can go without triggering CapacityOverflow
|
||||
if let Err(AllocErr) = empty_bytes.try_reserve_exact(MAX_CAP) {
|
||||
if let Err(AllocError { .. }) = empty_bytes.try_reserve_exact(MAX_CAP) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
}
|
||||
}
|
||||
@ -1275,7 +1275,7 @@ fn test_try_reserve_exact() {
|
||||
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
|
||||
} else {
|
||||
if let Err(AllocErr) = ten_bytes.try_reserve_exact(MAX_CAP - 9) {
|
||||
if let Err(AllocError { .. }) = ten_bytes.try_reserve_exact(MAX_CAP - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
}
|
||||
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) {
|
||||
@ -1296,7 +1296,7 @@ fn test_try_reserve_exact() {
|
||||
if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
|
||||
} else {
|
||||
if let Err(AllocErr) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) {
|
||||
if let Err(AllocError { .. }) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
}
|
||||
if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_USIZE - 20) {
|
||||
|
@ -70,7 +70,7 @@ use core::ptr::{self, NonNull};
|
||||
use core::slice::{self, SliceIndex};
|
||||
|
||||
use crate::borrow::{ToOwned, Cow};
|
||||
use crate::collections::CollectionAllocErr;
|
||||
use crate::collections::TryReserveError;
|
||||
use crate::boxed::Box;
|
||||
use crate::raw_vec::RawVec;
|
||||
|
||||
@ -498,9 +498,9 @@ impl<T> Vec<T> {
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(try_reserve)]
|
||||
/// use std::collections::CollectionAllocErr;
|
||||
/// use std::collections::TryReserveError;
|
||||
///
|
||||
/// fn process_data(data: &[u32]) -> Result<Vec<u32>, CollectionAllocErr> {
|
||||
/// fn process_data(data: &[u32]) -> Result<Vec<u32>, TryReserveError> {
|
||||
/// let mut output = Vec::new();
|
||||
///
|
||||
/// // Pre-reserve the memory, exiting if we can't
|
||||
@ -516,7 +516,7 @@ impl<T> Vec<T> {
|
||||
/// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
|
||||
/// ```
|
||||
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
|
||||
pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> {
|
||||
pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
|
||||
self.buf.try_reserve(self.len, additional)
|
||||
}
|
||||
|
||||
@ -538,9 +538,9 @@ impl<T> Vec<T> {
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(try_reserve)]
|
||||
/// use std::collections::CollectionAllocErr;
|
||||
/// use std::collections::TryReserveError;
|
||||
///
|
||||
/// fn process_data(data: &[u32]) -> Result<Vec<u32>, CollectionAllocErr> {
|
||||
/// fn process_data(data: &[u32]) -> Result<Vec<u32>, TryReserveError> {
|
||||
/// let mut output = Vec::new();
|
||||
///
|
||||
/// // Pre-reserve the memory, exiting if we can't
|
||||
@ -556,7 +556,7 @@ impl<T> Vec<T> {
|
||||
/// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
|
||||
/// ```
|
||||
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
|
||||
pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), CollectionAllocErr> {
|
||||
pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
|
||||
self.buf.try_reserve_exact(self.len, additional)
|
||||
}
|
||||
|
||||
|
@ -470,10 +470,5 @@ impl TypeId {
|
||||
#[stable(feature = "type_name", since = "1.38.0")]
|
||||
#[rustc_const_unstable(feature = "const_type_name")]
|
||||
pub const fn type_name<T: ?Sized>() -> &'static str {
|
||||
#[cfg(bootstrap)]
|
||||
unsafe {
|
||||
intrinsics::type_name::<T>()
|
||||
}
|
||||
#[cfg(not(bootstrap))]
|
||||
intrinsics::type_name::<T>()
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
use crate::fmt;
|
||||
use crate::ops::Range;
|
||||
use crate::iter::FusedIterator;
|
||||
use crate::str::from_utf8_unchecked;
|
||||
|
||||
/// An iterator over the escaped version of a byte.
|
||||
///
|
||||
@ -22,6 +23,7 @@ use crate::iter::FusedIterator;
|
||||
///
|
||||
/// [`escape_default`]: fn.escape_default.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[derive(Clone)]
|
||||
pub struct EscapeDefault {
|
||||
range: Range<usize>,
|
||||
data: [u8; 4],
|
||||
@ -130,6 +132,13 @@ impl ExactSizeIterator for EscapeDefault {}
|
||||
#[stable(feature = "fused", since = "1.26.0")]
|
||||
impl FusedIterator for EscapeDefault {}
|
||||
|
||||
#[stable(feature = "ascii_escape_display", since = "1.39.0")]
|
||||
impl fmt::Display for EscapeDefault {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(unsafe { from_utf8_unchecked(&self.data[self.range.clone()]) })
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "std_debug", since = "1.16.0")]
|
||||
impl fmt::Debug for EscapeDefault {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
|
@ -553,12 +553,7 @@ impl char {
|
||||
/// `XID_Start` is a Unicode Derived Property specified in
|
||||
/// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
|
||||
/// mostly similar to `ID_Start` but modified for closure under `NFKx`.
|
||||
#[cfg_attr(bootstrap,
|
||||
unstable(feature = "rustc_private",
|
||||
reason = "mainly needed for compiler internals",
|
||||
issue = "27812"))]
|
||||
#[cfg_attr(not(bootstrap),
|
||||
unstable(feature = "unicode_internals", issue = "0"))]
|
||||
#[unstable(feature = "unicode_internals", issue = "0")]
|
||||
pub fn is_xid_start(self) -> bool {
|
||||
derived_property::XID_Start(self)
|
||||
}
|
||||
@ -569,12 +564,7 @@ impl char {
|
||||
/// `XID_Continue` is a Unicode Derived Property specified in
|
||||
/// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
|
||||
/// mostly similar to `ID_Continue` but modified for closure under NFKx.
|
||||
#[cfg_attr(bootstrap,
|
||||
unstable(feature = "rustc_private",
|
||||
reason = "mainly needed for compiler internals",
|
||||
issue = "27812"))]
|
||||
#[cfg_attr(not(bootstrap),
|
||||
unstable(feature = "unicode_internals", issue = "0"))]
|
||||
#[unstable(feature = "unicode_internals", issue = "0")]
|
||||
#[inline]
|
||||
pub fn is_xid_continue(self) -> bool {
|
||||
derived_property::XID_Continue(self)
|
||||
|
@ -134,9 +134,8 @@ pub trait Clone : Sized {
|
||||
}
|
||||
|
||||
/// Derive macro generating an impl of the trait `Clone`.
|
||||
#[cfg(not(bootstrap))]
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[cfg_attr(boostrap_stdarch_ignore_this, rustc_macro_transparency = "semitransparent")]
|
||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||
#[allow_internal_unstable(core_intrinsics, derive_clone_copy)]
|
||||
pub macro Clone($item:item) { /* compiler built-in */ }
|
||||
|
@ -201,9 +201,8 @@ pub trait PartialEq<Rhs: ?Sized = Self> {
|
||||
}
|
||||
|
||||
/// Derive macro generating an impl of the trait `PartialEq`.
|
||||
#[cfg(not(bootstrap))]
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[cfg_attr(boostrap_stdarch_ignore_this, rustc_macro_transparency = "semitransparent")]
|
||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||
#[allow_internal_unstable(core_intrinsics)]
|
||||
pub macro PartialEq($item:item) { /* compiler built-in */ }
|
||||
@ -265,9 +264,8 @@ pub trait Eq: PartialEq<Self> {
|
||||
}
|
||||
|
||||
/// Derive macro generating an impl of the trait `Eq`.
|
||||
#[cfg(not(bootstrap))]
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[cfg_attr(boostrap_stdarch_ignore_this, rustc_macro_transparency = "semitransparent")]
|
||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||
#[allow_internal_unstable(core_intrinsics, derive_eq)]
|
||||
pub macro Eq($item:item) { /* compiler built-in */ }
|
||||
@ -617,9 +615,8 @@ pub trait Ord: Eq + PartialOrd<Self> {
|
||||
}
|
||||
|
||||
/// Derive macro generating an impl of the trait `Ord`.
|
||||
#[cfg(not(bootstrap))]
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[cfg_attr(boostrap_stdarch_ignore_this, rustc_macro_transparency = "semitransparent")]
|
||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||
#[allow_internal_unstable(core_intrinsics)]
|
||||
pub macro Ord($item:item) { /* compiler built-in */ }
|
||||
@ -867,9 +864,8 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
|
||||
}
|
||||
|
||||
/// Derive macro generating an impl of the trait `PartialOrd`.
|
||||
#[cfg(not(bootstrap))]
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[cfg_attr(boostrap_stdarch_ignore_this, rustc_macro_transparency = "semitransparent")]
|
||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||
#[allow_internal_unstable(core_intrinsics)]
|
||||
pub macro PartialOrd($item:item) { /* compiler built-in */ }
|
||||
|
@ -116,9 +116,8 @@ pub trait Default: Sized {
|
||||
}
|
||||
|
||||
/// Derive macro generating an impl of the trait `Default`.
|
||||
#[cfg(not(bootstrap))]
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[cfg_attr(boostrap_stdarch_ignore_this, rustc_macro_transparency = "semitransparent")]
|
||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||
#[allow_internal_unstable(core_intrinsics)]
|
||||
pub macro Default($item:item) { /* compiler built-in */ }
|
||||
|
@ -98,7 +98,7 @@ pub struct DebugStruct<'a, 'b: 'a> {
|
||||
has_fields: bool,
|
||||
}
|
||||
|
||||
pub fn debug_struct_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>,
|
||||
pub(super) fn debug_struct_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>,
|
||||
name: &str)
|
||||
-> DebugStruct<'a, 'b> {
|
||||
let result = fmt.write_str(name);
|
||||
@ -251,7 +251,10 @@ pub struct DebugTuple<'a, 'b: 'a> {
|
||||
empty_name: bool,
|
||||
}
|
||||
|
||||
pub fn debug_tuple_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> DebugTuple<'a, 'b> {
|
||||
pub(super) fn debug_tuple_new<'a, 'b>(
|
||||
fmt: &'a mut fmt::Formatter<'b>,
|
||||
name: &str,
|
||||
) -> DebugTuple<'a, 'b> {
|
||||
let result = fmt.write_str(name);
|
||||
DebugTuple {
|
||||
fmt,
|
||||
@ -418,7 +421,7 @@ pub struct DebugSet<'a, 'b: 'a> {
|
||||
inner: DebugInner<'a, 'b>,
|
||||
}
|
||||
|
||||
pub fn debug_set_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugSet<'a, 'b> {
|
||||
pub(super) fn debug_set_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugSet<'a, 'b> {
|
||||
let result = fmt.write_str("{");
|
||||
DebugSet {
|
||||
inner: DebugInner {
|
||||
@ -555,7 +558,7 @@ pub struct DebugList<'a, 'b: 'a> {
|
||||
inner: DebugInner<'a, 'b>,
|
||||
}
|
||||
|
||||
pub fn debug_list_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugList<'a, 'b> {
|
||||
pub(super) fn debug_list_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugList<'a, 'b> {
|
||||
let result = fmt.write_str("[");
|
||||
DebugList {
|
||||
inner: DebugInner {
|
||||
@ -697,7 +700,7 @@ pub struct DebugMap<'a, 'b: 'a> {
|
||||
state: PadAdapterState,
|
||||
}
|
||||
|
||||
pub fn debug_map_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugMap<'a, 'b> {
|
||||
pub(super) fn debug_map_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugMap<'a, 'b> {
|
||||
let result = fmt.write_str("{");
|
||||
DebugMap {
|
||||
fmt,
|
||||
|
@ -546,16 +546,14 @@ pub trait Debug {
|
||||
}
|
||||
|
||||
// Separate module to reexport the macro `Debug` from prelude without the trait `Debug`.
|
||||
#[cfg(not(bootstrap))]
|
||||
pub(crate) mod macros {
|
||||
/// Derive macro generating an impl of the trait `Debug`.
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[cfg_attr(boostrap_stdarch_ignore_this, rustc_macro_transparency = "semitransparent")]
|
||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||
#[allow_internal_unstable(core_intrinsics)]
|
||||
pub macro Debug($item:item) { /* compiler built-in */ }
|
||||
}
|
||||
#[cfg(not(bootstrap))]
|
||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||
#[doc(inline)]
|
||||
pub use macros::Debug;
|
||||
|
@ -199,16 +199,14 @@ pub trait Hash {
|
||||
}
|
||||
|
||||
// Separate module to reexport the macro `Hash` from prelude without the trait `Hash`.
|
||||
#[cfg(not(bootstrap))]
|
||||
pub(crate) mod macros {
|
||||
/// Derive macro generating an impl of the trait `Hash`.
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[cfg_attr(boostrap_stdarch_ignore_this, rustc_macro_transparency = "semitransparent")]
|
||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||
#[allow_internal_unstable(core_intrinsics)]
|
||||
pub macro Hash($item:item) { /* compiler built-in */ }
|
||||
}
|
||||
#[cfg(not(bootstrap))]
|
||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||
#[doc(inline)]
|
||||
pub use macros::Hash;
|
||||
@ -553,8 +551,6 @@ impl<H> PartialEq for BuildHasherDefault<H> {
|
||||
#[stable(since = "1.29.0", feature = "build_hasher_eq")]
|
||||
impl<H> Eq for BuildHasherDefault<H> {}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
mod impls {
|
||||
use crate::mem;
|
||||
use crate::slice;
|
||||
|
@ -1293,18 +1293,40 @@ extern "rust-intrinsic" {
|
||||
/// The stabilized versions of this intrinsic are available on the integer
|
||||
/// primitives via the `wrapping_add` method. For example,
|
||||
/// [`std::u32::wrapping_add`](../../std/primitive.u32.html#method.wrapping_add)
|
||||
#[cfg(boostrap_stdarch_ignore_this)]
|
||||
pub fn overflowing_add<T>(a: T, b: T) -> T;
|
||||
/// Returns (a - b) mod 2<sup>N</sup>, where N is the width of T in bits.
|
||||
/// The stabilized versions of this intrinsic are available on the integer
|
||||
/// primitives via the `wrapping_sub` method. For example,
|
||||
/// [`std::u32::wrapping_sub`](../../std/primitive.u32.html#method.wrapping_sub)
|
||||
#[cfg(boostrap_stdarch_ignore_this)]
|
||||
pub fn overflowing_sub<T>(a: T, b: T) -> T;
|
||||
/// Returns (a * b) mod 2<sup>N</sup>, where N is the width of T in bits.
|
||||
/// The stabilized versions of this intrinsic are available on the integer
|
||||
/// primitives via the `wrapping_mul` method. For example,
|
||||
/// [`std::u32::wrapping_mul`](../../std/primitive.u32.html#method.wrapping_mul)
|
||||
#[cfg(boostrap_stdarch_ignore_this)]
|
||||
pub fn overflowing_mul<T>(a: T, b: T) -> T;
|
||||
|
||||
/// Returns (a + b) mod 2<sup>N</sup>, where N is the width of T in bits.
|
||||
/// The stabilized versions of this intrinsic are available on the integer
|
||||
/// primitives via the `wrapping_add` method. For example,
|
||||
/// [`std::u32::wrapping_add`](../../std/primitive.u32.html#method.wrapping_add)
|
||||
#[cfg(not(boostrap_stdarch_ignore_this))]
|
||||
pub fn wrapping_add<T>(a: T, b: T) -> T;
|
||||
/// Returns (a - b) mod 2<sup>N</sup>, where N is the width of T in bits.
|
||||
/// The stabilized versions of this intrinsic are available on the integer
|
||||
/// primitives via the `wrapping_sub` method. For example,
|
||||
/// [`std::u32::wrapping_sub`](../../std/primitive.u32.html#method.wrapping_sub)
|
||||
#[cfg(not(boostrap_stdarch_ignore_this))]
|
||||
pub fn wrapping_sub<T>(a: T, b: T) -> T;
|
||||
/// Returns (a * b) mod 2<sup>N</sup>, where N is the width of T in bits.
|
||||
/// The stabilized versions of this intrinsic are available on the integer
|
||||
/// primitives via the `wrapping_mul` method. For example,
|
||||
/// [`std::u32::wrapping_mul`](../../std/primitive.u32.html#method.wrapping_mul)
|
||||
#[cfg(not(boostrap_stdarch_ignore_this))]
|
||||
pub fn wrapping_mul<T>(a: T, b: T) -> T;
|
||||
|
||||
/// Computes `a + b`, while saturating at numeric bounds.
|
||||
/// The stabilized versions of this intrinsic are available on the integer
|
||||
/// primitives via the `saturating_add` method. For example,
|
||||
|
@ -207,6 +207,29 @@ impl<A, B> DoubleEndedIterator for Chain<A, B> where
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn nth_back(&mut self, mut n: usize) -> Option<A::Item> {
|
||||
match self.state {
|
||||
ChainState::Both | ChainState::Back => {
|
||||
for x in self.b.by_ref().rev() {
|
||||
if n == 0 {
|
||||
return Some(x)
|
||||
}
|
||||
n -= 1;
|
||||
}
|
||||
if let ChainState::Both = self.state {
|
||||
self.state = ChainState::Front;
|
||||
}
|
||||
}
|
||||
ChainState::Front => {}
|
||||
}
|
||||
if let ChainState::Front = self.state {
|
||||
self.a.nth_back(n)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn try_rfold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R where
|
||||
Self: Sized, F: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
|
||||
{
|
||||
|
@ -72,8 +72,7 @@ impl<I: Iterator, U: IntoIterator, F> Iterator for FlatMap<I, U, F>
|
||||
impl<I: DoubleEndedIterator, U, F> DoubleEndedIterator for FlatMap<I, U, F>
|
||||
where
|
||||
F: FnMut(I::Item) -> U,
|
||||
U: IntoIterator,
|
||||
U::IntoIter: DoubleEndedIterator,
|
||||
U: IntoIterator<IntoIter: DoubleEndedIterator>,
|
||||
{
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<U::Item> { self.inner.next_back() }
|
||||
@ -107,10 +106,7 @@ impl<I, U, F> FusedIterator for FlatMap<I, U, F>
|
||||
/// [`Iterator`]: trait.Iterator.html
|
||||
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||
#[stable(feature = "iterator_flatten", since = "1.29.0")]
|
||||
pub struct Flatten<I: Iterator>
|
||||
where
|
||||
I::Item: IntoIterator,
|
||||
{
|
||||
pub struct Flatten<I: Iterator<Item: IntoIterator>> {
|
||||
inner: FlattenCompat<I, <I::Item as IntoIterator>::IntoIter>,
|
||||
}
|
||||
|
||||
@ -229,7 +225,7 @@ where
|
||||
if let elt@Some(_) = inner.next() { return elt }
|
||||
}
|
||||
match self.iter.next() {
|
||||
None => return self.backiter.as_mut().and_then(|it| it.next()),
|
||||
None => return self.backiter.as_mut()?.next(),
|
||||
Some(inner) => self.frontiter = Some(inner.into_iter()),
|
||||
}
|
||||
}
|
||||
@ -237,8 +233,8 @@ where
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let (flo, fhi) = self.frontiter.as_ref().map_or((0, Some(0)), |it| it.size_hint());
|
||||
let (blo, bhi) = self.backiter.as_ref().map_or((0, Some(0)), |it| it.size_hint());
|
||||
let (flo, fhi) = self.frontiter.as_ref().map_or((0, Some(0)), U::size_hint);
|
||||
let (blo, bhi) = self.backiter.as_ref().map_or((0, Some(0)), U::size_hint);
|
||||
let lo = flo.saturating_add(blo);
|
||||
match (self.iter.size_hint(), fhi, bhi) {
|
||||
((0, Some(0)), Some(a), Some(b)) => (lo, a.checked_add(b)),
|
||||
@ -250,20 +246,25 @@ where
|
||||
fn try_fold<Acc, Fold, R>(&mut self, mut init: Acc, mut fold: Fold) -> R where
|
||||
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
|
||||
{
|
||||
#[inline]
|
||||
fn flatten<'a, T: IntoIterator, Acc, R: Try<Ok = Acc>>(
|
||||
frontiter: &'a mut Option<T::IntoIter>,
|
||||
fold: &'a mut impl FnMut(Acc, T::Item) -> R,
|
||||
) -> impl FnMut(Acc, T) -> R + 'a {
|
||||
move |acc, x| {
|
||||
let mut mid = x.into_iter();
|
||||
let r = mid.try_fold(acc, &mut *fold);
|
||||
*frontiter = Some(mid);
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref mut front) = self.frontiter {
|
||||
init = front.try_fold(init, &mut fold)?;
|
||||
}
|
||||
self.frontiter = None;
|
||||
|
||||
{
|
||||
let frontiter = &mut self.frontiter;
|
||||
init = self.iter.try_fold(init, |acc, x| {
|
||||
let mut mid = x.into_iter();
|
||||
let r = mid.try_fold(acc, &mut fold);
|
||||
*frontiter = Some(mid);
|
||||
r
|
||||
})?;
|
||||
}
|
||||
init = self.iter.try_fold(init, flatten(&mut self.frontiter, &mut fold))?;
|
||||
self.frontiter = None;
|
||||
|
||||
if let Some(ref mut back) = self.backiter {
|
||||
@ -275,13 +276,20 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
fn fold<Acc, Fold>(self, init: Acc, ref mut fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
#[inline]
|
||||
fn flatten<U: Iterator, Acc>(
|
||||
fold: &mut impl FnMut(Acc, U::Item) -> Acc,
|
||||
) -> impl FnMut(Acc, U) -> Acc + '_ {
|
||||
move |acc, iter| iter.fold(acc, &mut *fold)
|
||||
}
|
||||
|
||||
self.frontiter.into_iter()
|
||||
.chain(self.iter.map(IntoIterator::into_iter))
|
||||
.chain(self.backiter)
|
||||
.fold(init, |acc, iter| iter.fold(acc, &mut fold))
|
||||
.fold(init, flatten(fold))
|
||||
}
|
||||
}
|
||||
|
||||
@ -297,7 +305,7 @@ where
|
||||
if let elt@Some(_) = inner.next_back() { return elt }
|
||||
}
|
||||
match self.iter.next_back() {
|
||||
None => return self.frontiter.as_mut().and_then(|it| it.next_back()),
|
||||
None => return self.frontiter.as_mut()?.next_back(),
|
||||
next => self.backiter = next.map(IntoIterator::into_iter),
|
||||
}
|
||||
}
|
||||
@ -307,20 +315,27 @@ where
|
||||
fn try_rfold<Acc, Fold, R>(&mut self, mut init: Acc, mut fold: Fold) -> R where
|
||||
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
|
||||
{
|
||||
#[inline]
|
||||
fn flatten<'a, T: IntoIterator, Acc, R: Try<Ok = Acc>>(
|
||||
backiter: &'a mut Option<T::IntoIter>,
|
||||
fold: &'a mut impl FnMut(Acc, T::Item) -> R,
|
||||
) -> impl FnMut(Acc, T) -> R + 'a where
|
||||
T::IntoIter: DoubleEndedIterator,
|
||||
{
|
||||
move |acc, x| {
|
||||
let mut mid = x.into_iter();
|
||||
let r = mid.try_rfold(acc, &mut *fold);
|
||||
*backiter = Some(mid);
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref mut back) = self.backiter {
|
||||
init = back.try_rfold(init, &mut fold)?;
|
||||
}
|
||||
self.backiter = None;
|
||||
|
||||
{
|
||||
let backiter = &mut self.backiter;
|
||||
init = self.iter.try_rfold(init, |acc, x| {
|
||||
let mut mid = x.into_iter();
|
||||
let r = mid.try_rfold(acc, &mut fold);
|
||||
*backiter = Some(mid);
|
||||
r
|
||||
})?;
|
||||
}
|
||||
init = self.iter.try_rfold(init, flatten(&mut self.backiter, &mut fold))?;
|
||||
self.backiter = None;
|
||||
|
||||
if let Some(ref mut front) = self.frontiter {
|
||||
@ -332,12 +347,19 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
fn rfold<Acc, Fold>(self, init: Acc, ref mut fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
#[inline]
|
||||
fn flatten<U: DoubleEndedIterator, Acc>(
|
||||
fold: &mut impl FnMut(Acc, U::Item) -> Acc,
|
||||
) -> impl FnMut(Acc, U) -> Acc + '_ {
|
||||
move |acc, iter| iter.rfold(acc, &mut *fold)
|
||||
}
|
||||
|
||||
self.frontiter.into_iter()
|
||||
.chain(self.iter.map(IntoIterator::into_iter))
|
||||
.chain(self.backiter)
|
||||
.rfold(init, |acc, iter| iter.rfold(acc, &mut fold))
|
||||
.rfold(init, flatten(fold))
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::cmp;
|
||||
use crate::fmt;
|
||||
use crate::ops::Try;
|
||||
use crate::ops::{Add, AddAssign, Try};
|
||||
use crate::usize;
|
||||
use crate::intrinsics;
|
||||
|
||||
@ -143,6 +143,18 @@ impl<I> Copied<I> {
|
||||
}
|
||||
}
|
||||
|
||||
fn copy_fold<T: Copy, Acc>(
|
||||
mut f: impl FnMut(Acc, T) -> Acc,
|
||||
) -> impl FnMut(Acc, &T) -> Acc {
|
||||
move |acc, &elt| f(acc, elt)
|
||||
}
|
||||
|
||||
fn copy_try_fold<T: Copy, Acc, R>(
|
||||
mut f: impl FnMut(Acc, T) -> R,
|
||||
) -> impl FnMut(Acc, &T) -> R {
|
||||
move |acc, &elt| f(acc, elt)
|
||||
}
|
||||
|
||||
#[stable(feature = "iter_copied", since = "1.36.0")]
|
||||
impl<'a, I, T: 'a> Iterator for Copied<I>
|
||||
where I: Iterator<Item=&'a T>, T: Copy
|
||||
@ -157,16 +169,16 @@ impl<'a, I, T: 'a> Iterator for Copied<I>
|
||||
self.it.size_hint()
|
||||
}
|
||||
|
||||
fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R where
|
||||
fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R where
|
||||
Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B>
|
||||
{
|
||||
self.it.try_fold(init, move |acc, &elt| f(acc, elt))
|
||||
self.it.try_fold(init, copy_try_fold(f))
|
||||
}
|
||||
|
||||
fn fold<Acc, F>(self, init: Acc, mut f: F) -> Acc
|
||||
fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
|
||||
where F: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
self.it.fold(init, move |acc, &elt| f(acc, elt))
|
||||
self.it.fold(init, copy_fold(f))
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,16 +190,16 @@ impl<'a, I, T: 'a> DoubleEndedIterator for Copied<I>
|
||||
self.it.next_back().copied()
|
||||
}
|
||||
|
||||
fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R where
|
||||
fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R where
|
||||
Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B>
|
||||
{
|
||||
self.it.try_rfold(init, move |acc, &elt| f(acc, elt))
|
||||
self.it.try_rfold(init, copy_try_fold(f))
|
||||
}
|
||||
|
||||
fn rfold<Acc, F>(self, init: Acc, mut f: F) -> Acc
|
||||
fn rfold<Acc, F>(self, init: Acc, f: F) -> Acc
|
||||
where F: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
self.it.rfold(init, move |acc, &elt| f(acc, elt))
|
||||
self.it.rfold(init, copy_fold(f))
|
||||
}
|
||||
}
|
||||
|
||||
@ -248,6 +260,12 @@ impl<I> Cloned<I> {
|
||||
}
|
||||
}
|
||||
|
||||
fn clone_try_fold<T: Clone, Acc, R>(
|
||||
mut f: impl FnMut(Acc, T) -> R,
|
||||
) -> impl FnMut(Acc, &T) -> R {
|
||||
move |acc, elt| f(acc, elt.clone())
|
||||
}
|
||||
|
||||
#[stable(feature = "iter_cloned", since = "1.1.0")]
|
||||
impl<'a, I, T: 'a> Iterator for Cloned<I>
|
||||
where I: Iterator<Item=&'a T>, T: Clone
|
||||
@ -262,16 +280,16 @@ impl<'a, I, T: 'a> Iterator for Cloned<I>
|
||||
self.it.size_hint()
|
||||
}
|
||||
|
||||
fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R where
|
||||
fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R where
|
||||
Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B>
|
||||
{
|
||||
self.it.try_fold(init, move |acc, elt| f(acc, elt.clone()))
|
||||
self.it.try_fold(init, clone_try_fold(f))
|
||||
}
|
||||
|
||||
fn fold<Acc, F>(self, init: Acc, mut f: F) -> Acc
|
||||
fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
|
||||
where F: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
self.it.fold(init, move |acc, elt| f(acc, elt.clone()))
|
||||
self.it.map(T::clone).fold(init, f)
|
||||
}
|
||||
}
|
||||
|
||||
@ -283,16 +301,16 @@ impl<'a, I, T: 'a> DoubleEndedIterator for Cloned<I>
|
||||
self.it.next_back().cloned()
|
||||
}
|
||||
|
||||
fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R where
|
||||
fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R where
|
||||
Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B>
|
||||
{
|
||||
self.it.try_rfold(init, move |acc, elt| f(acc, elt.clone()))
|
||||
self.it.try_rfold(init, clone_try_fold(f))
|
||||
}
|
||||
|
||||
fn rfold<Acc, F>(self, init: Acc, mut f: F) -> Acc
|
||||
fn rfold<Acc, F>(self, init: Acc, f: F) -> Acc
|
||||
where F: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
self.it.rfold(init, move |acc, elt| f(acc, elt.clone()))
|
||||
self.it.map(T::clone).rfold(init, f)
|
||||
}
|
||||
}
|
||||
|
||||
@ -387,6 +405,36 @@ impl<I> Iterator for Cycle<I> where I: Clone + Iterator {
|
||||
_ => (usize::MAX, None)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_fold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R
|
||||
where
|
||||
F: FnMut(Acc, Self::Item) -> R,
|
||||
R: Try<Ok = Acc>,
|
||||
{
|
||||
// fully iterate the current iterator. this is necessary because
|
||||
// `self.iter` may be empty even when `self.orig` isn't
|
||||
acc = self.iter.try_fold(acc, &mut f)?;
|
||||
self.iter = self.orig.clone();
|
||||
|
||||
// complete a full cycle, keeping track of whether the cycled
|
||||
// iterator is empty or not. we need to return early in case
|
||||
// of an empty iterator to prevent an infinite loop
|
||||
let mut is_empty = true;
|
||||
acc = self.iter.try_fold(acc, |acc, x| {
|
||||
is_empty = false;
|
||||
f(acc, x)
|
||||
})?;
|
||||
|
||||
if is_empty {
|
||||
return Try::from_ok(acc);
|
||||
}
|
||||
|
||||
loop {
|
||||
self.iter = self.orig.clone();
|
||||
acc = self.iter.try_fold(acc, &mut f)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "fused", since = "1.26.0")]
|
||||
@ -430,14 +478,24 @@ impl<I> Iterator for StepBy<I> where I: Iterator {
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let inner_hint = self.iter.size_hint();
|
||||
#[inline]
|
||||
fn first_size(step: usize) -> impl Fn(usize) -> usize {
|
||||
move |n| if n == 0 { 0 } else { 1 + (n - 1) / (step + 1) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn other_size(step: usize) -> impl Fn(usize) -> usize {
|
||||
move |n| n / (step + 1)
|
||||
}
|
||||
|
||||
let (low, high) = self.iter.size_hint();
|
||||
|
||||
if self.first_take {
|
||||
let f = |n| if n == 0 { 0 } else { 1 + (n-1)/(self.step+1) };
|
||||
(f(inner_hint.0), inner_hint.1.map(f))
|
||||
let f = first_size(self.step);
|
||||
(f(low), high.map(f))
|
||||
} else {
|
||||
let f = |n| n / (self.step+1);
|
||||
(f(inner_hint.0), inner_hint.1.map(f))
|
||||
let f = other_size(self.step);
|
||||
(f(low), high.map(f))
|
||||
}
|
||||
}
|
||||
|
||||
@ -594,6 +652,20 @@ impl<I: fmt::Debug, F> fmt::Debug for Map<I, F> {
|
||||
}
|
||||
}
|
||||
|
||||
fn map_fold<T, B, Acc>(
|
||||
mut f: impl FnMut(T) -> B,
|
||||
mut g: impl FnMut(Acc, B) -> Acc,
|
||||
) -> impl FnMut(Acc, T) -> Acc {
|
||||
move |acc, elt| g(acc, f(elt))
|
||||
}
|
||||
|
||||
fn map_try_fold<'a, T, B, Acc, R>(
|
||||
f: &'a mut impl FnMut(T) -> B,
|
||||
mut g: impl FnMut(Acc, B) -> R + 'a,
|
||||
) -> impl FnMut(Acc, T) -> R + 'a {
|
||||
move |acc, elt| g(acc, f(elt))
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<B, I: Iterator, F> Iterator for Map<I, F> where F: FnMut(I::Item) -> B {
|
||||
type Item = B;
|
||||
@ -608,18 +680,16 @@ impl<B, I: Iterator, F> Iterator for Map<I, F> where F: FnMut(I::Item) -> B {
|
||||
self.iter.size_hint()
|
||||
}
|
||||
|
||||
fn try_fold<Acc, G, R>(&mut self, init: Acc, mut g: G) -> R where
|
||||
fn try_fold<Acc, G, R>(&mut self, init: Acc, g: G) -> R where
|
||||
Self: Sized, G: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
|
||||
{
|
||||
let f = &mut self.f;
|
||||
self.iter.try_fold(init, move |acc, elt| g(acc, f(elt)))
|
||||
self.iter.try_fold(init, map_try_fold(&mut self.f, g))
|
||||
}
|
||||
|
||||
fn fold<Acc, G>(self, init: Acc, mut g: G) -> Acc
|
||||
fn fold<Acc, G>(self, init: Acc, g: G) -> Acc
|
||||
where G: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let mut f = self.f;
|
||||
self.iter.fold(init, move |acc, elt| g(acc, f(elt)))
|
||||
self.iter.fold(init, map_fold(self.f, g))
|
||||
}
|
||||
}
|
||||
|
||||
@ -632,18 +702,16 @@ impl<B, I: DoubleEndedIterator, F> DoubleEndedIterator for Map<I, F> where
|
||||
self.iter.next_back().map(&mut self.f)
|
||||
}
|
||||
|
||||
fn try_rfold<Acc, G, R>(&mut self, init: Acc, mut g: G) -> R where
|
||||
fn try_rfold<Acc, G, R>(&mut self, init: Acc, g: G) -> R where
|
||||
Self: Sized, G: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
|
||||
{
|
||||
let f = &mut self.f;
|
||||
self.iter.try_rfold(init, move |acc, elt| g(acc, f(elt)))
|
||||
self.iter.try_rfold(init, map_try_fold(&mut self.f, g))
|
||||
}
|
||||
|
||||
fn rfold<Acc, G>(self, init: Acc, mut g: G) -> Acc
|
||||
fn rfold<Acc, G>(self, init: Acc, g: G) -> Acc
|
||||
where G: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let mut f = self.f;
|
||||
self.iter.rfold(init, move |acc, elt| g(acc, f(elt)))
|
||||
self.iter.rfold(init, map_fold(self.f, g))
|
||||
}
|
||||
}
|
||||
|
||||
@ -710,13 +778,27 @@ impl<I: fmt::Debug, P> fmt::Debug for Filter<I, P> {
|
||||
}
|
||||
}
|
||||
|
||||
fn filter_fold<T, Acc>(
|
||||
mut predicate: impl FnMut(&T) -> bool,
|
||||
mut fold: impl FnMut(Acc, T) -> Acc,
|
||||
) -> impl FnMut(Acc, T) -> Acc {
|
||||
move |acc, item| if predicate(&item) { fold(acc, item) } else { acc }
|
||||
}
|
||||
|
||||
fn filter_try_fold<'a, T, Acc, R: Try<Ok = Acc>>(
|
||||
predicate: &'a mut impl FnMut(&T) -> bool,
|
||||
mut fold: impl FnMut(Acc, T) -> R + 'a,
|
||||
) -> impl FnMut(Acc, T) -> R + 'a {
|
||||
move |acc, item| if predicate(&item) { fold(acc, item) } else { R::from_ok(acc) }
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<I: Iterator, P> Iterator for Filter<I, P> where P: FnMut(&I::Item) -> bool {
|
||||
type Item = I::Item;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<I::Item> {
|
||||
self.try_for_each(Err).err()
|
||||
self.iter.find(&mut self.predicate)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -738,32 +820,26 @@ impl<I: Iterator, P> Iterator for Filter<I, P> where P: FnMut(&I::Item) -> bool
|
||||
// leaving more budget for LLVM optimizations.
|
||||
#[inline]
|
||||
fn count(self) -> usize {
|
||||
let mut predicate = self.predicate;
|
||||
self.iter.map(|x| predicate(&x) as usize).sum()
|
||||
#[inline]
|
||||
fn to_usize<T>(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut(T) -> usize {
|
||||
move |x| predicate(&x) as usize
|
||||
}
|
||||
|
||||
self.iter.map(to_usize(self.predicate)).sum()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, mut fold: Fold) -> R where
|
||||
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
|
||||
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
|
||||
{
|
||||
let predicate = &mut self.predicate;
|
||||
self.iter.try_fold(init, move |acc, item| if predicate(&item) {
|
||||
fold(acc, item)
|
||||
} else {
|
||||
Try::from_ok(acc)
|
||||
})
|
||||
self.iter.try_fold(init, filter_try_fold(&mut self.predicate, fold))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let mut predicate = self.predicate;
|
||||
self.iter.fold(init, move |acc, item| if predicate(&item) {
|
||||
fold(acc, item)
|
||||
} else {
|
||||
acc
|
||||
})
|
||||
self.iter.fold(init, filter_fold(self.predicate, fold))
|
||||
}
|
||||
}
|
||||
|
||||
@ -773,31 +849,21 @@ impl<I: DoubleEndedIterator, P> DoubleEndedIterator for Filter<I, P>
|
||||
{
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<I::Item> {
|
||||
self.try_rfold((), |_, x| Err(x)).err()
|
||||
self.iter.rfind(&mut self.predicate)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, mut fold: Fold) -> R where
|
||||
fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
|
||||
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
|
||||
{
|
||||
let predicate = &mut self.predicate;
|
||||
self.iter.try_rfold(init, move |acc, item| if predicate(&item) {
|
||||
fold(acc, item)
|
||||
} else {
|
||||
Try::from_ok(acc)
|
||||
})
|
||||
self.iter.try_rfold(init, filter_try_fold(&mut self.predicate, fold))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let mut predicate = self.predicate;
|
||||
self.iter.rfold(init, move |acc, item| if predicate(&item) {
|
||||
fold(acc, item)
|
||||
} else {
|
||||
acc
|
||||
})
|
||||
self.iter.rfold(init, filter_fold(self.predicate, fold))
|
||||
}
|
||||
}
|
||||
|
||||
@ -834,6 +900,26 @@ impl<I: fmt::Debug, F> fmt::Debug for FilterMap<I, F> {
|
||||
}
|
||||
}
|
||||
|
||||
fn filter_map_fold<T, B, Acc>(
|
||||
mut f: impl FnMut(T) -> Option<B>,
|
||||
mut fold: impl FnMut(Acc, B) -> Acc,
|
||||
) -> impl FnMut(Acc, T) -> Acc {
|
||||
move |acc, item| match f(item) {
|
||||
Some(x) => fold(acc, x),
|
||||
None => acc,
|
||||
}
|
||||
}
|
||||
|
||||
fn filter_map_try_fold<'a, T, B, Acc, R: Try<Ok = Acc>>(
|
||||
f: &'a mut impl FnMut(T) -> Option<B>,
|
||||
mut fold: impl FnMut(Acc, B) -> R + 'a,
|
||||
) -> impl FnMut(Acc, T) -> R + 'a {
|
||||
move |acc, item| match f(item) {
|
||||
Some(x) => fold(acc, x),
|
||||
None => R::from_ok(acc),
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<B, I: Iterator, F> Iterator for FilterMap<I, F>
|
||||
where F: FnMut(I::Item) -> Option<B>,
|
||||
@ -842,7 +928,7 @@ impl<B, I: Iterator, F> Iterator for FilterMap<I, F>
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<B> {
|
||||
self.try_for_each(Err).err()
|
||||
self.iter.find_map(&mut self.f)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -852,25 +938,17 @@ impl<B, I: Iterator, F> Iterator for FilterMap<I, F>
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, mut fold: Fold) -> R where
|
||||
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
|
||||
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
|
||||
{
|
||||
let f = &mut self.f;
|
||||
self.iter.try_fold(init, move |acc, item| match f(item) {
|
||||
Some(x) => fold(acc, x),
|
||||
None => Try::from_ok(acc),
|
||||
})
|
||||
self.iter.try_fold(init, filter_map_try_fold(&mut self.f, fold))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let mut f = self.f;
|
||||
self.iter.fold(init, move |acc, item| match f(item) {
|
||||
Some(x) => fold(acc, x),
|
||||
None => acc,
|
||||
})
|
||||
self.iter.fold(init, filter_map_fold(self.f, fold))
|
||||
}
|
||||
}
|
||||
|
||||
@ -880,29 +958,31 @@ impl<B, I: DoubleEndedIterator, F> DoubleEndedIterator for FilterMap<I, F>
|
||||
{
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<B> {
|
||||
self.try_rfold((), |_, x| Err(x)).err()
|
||||
#[inline]
|
||||
fn find<T, B>(
|
||||
f: &mut impl FnMut(T) -> Option<B>
|
||||
) -> impl FnMut((), T) -> LoopState<(), B> + '_ {
|
||||
move |(), x| match f(x) {
|
||||
Some(x) => LoopState::Break(x),
|
||||
None => LoopState::Continue(()),
|
||||
}
|
||||
}
|
||||
|
||||
self.iter.try_rfold((), find(&mut self.f)).break_value()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, mut fold: Fold) -> R where
|
||||
fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
|
||||
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
|
||||
{
|
||||
let f = &mut self.f;
|
||||
self.iter.try_rfold(init, move |acc, item| match f(item) {
|
||||
Some(x) => fold(acc, x),
|
||||
None => Try::from_ok(acc),
|
||||
})
|
||||
self.iter.try_rfold(init, filter_map_try_fold(&mut self.f, fold))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let mut f = self.f;
|
||||
self.iter.rfold(init, move |acc, item| match f(item) {
|
||||
Some(x) => fold(acc, x),
|
||||
None => acc,
|
||||
})
|
||||
self.iter.rfold(init, filter_map_fold(self.f, fold))
|
||||
}
|
||||
}
|
||||
|
||||
@ -944,14 +1024,12 @@ impl<I> Iterator for Enumerate<I> where I: Iterator {
|
||||
///
|
||||
/// Might panic if the index of the element overflows a `usize`.
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
fn next(&mut self) -> Option<(usize, <I as Iterator>::Item)> {
|
||||
self.iter.next().map(|a| {
|
||||
let ret = (self.count, a);
|
||||
// Possible undefined overflow.
|
||||
self.count += 1;
|
||||
ret
|
||||
})
|
||||
let a = self.iter.next()?;
|
||||
let i = self.count;
|
||||
// Possible undefined overflow.
|
||||
AddAssign::add_assign(&mut self.count, 1);
|
||||
Some((i, a))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -960,13 +1038,12 @@ impl<I> Iterator for Enumerate<I> where I: Iterator {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
fn nth(&mut self, n: usize) -> Option<(usize, I::Item)> {
|
||||
self.iter.nth(n).map(|a| {
|
||||
let i = self.count + n;
|
||||
self.count = i + 1;
|
||||
(i, a)
|
||||
})
|
||||
let a = self.iter.nth(n)?;
|
||||
// Possible undefined overflow.
|
||||
let i = Add::add(self.count, n);
|
||||
self.count = Add::add(i, 1);
|
||||
Some((i, a))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -975,29 +1052,43 @@ impl<I> Iterator for Enumerate<I> where I: Iterator {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, mut fold: Fold) -> R where
|
||||
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
|
||||
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
|
||||
{
|
||||
let count = &mut self.count;
|
||||
self.iter.try_fold(init, move |acc, item| {
|
||||
let acc = fold(acc, (*count, item));
|
||||
*count += 1;
|
||||
acc
|
||||
})
|
||||
#[inline]
|
||||
fn enumerate<'a, T, Acc, R>(
|
||||
count: &'a mut usize,
|
||||
mut fold: impl FnMut(Acc, (usize, T)) -> R + 'a,
|
||||
) -> impl FnMut(Acc, T) -> R + 'a {
|
||||
move |acc, item| {
|
||||
let acc = fold(acc, (*count, item));
|
||||
// Possible undefined overflow.
|
||||
AddAssign::add_assign(count, 1);
|
||||
acc
|
||||
}
|
||||
}
|
||||
|
||||
self.iter.try_fold(init, enumerate(&mut self.count, fold))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let mut count = self.count;
|
||||
self.iter.fold(init, move |acc, item| {
|
||||
let acc = fold(acc, (count, item));
|
||||
count += 1;
|
||||
acc
|
||||
})
|
||||
#[inline]
|
||||
fn enumerate<T, Acc>(
|
||||
mut count: usize,
|
||||
mut fold: impl FnMut(Acc, (usize, T)) -> Acc,
|
||||
) -> impl FnMut(Acc, T) -> Acc {
|
||||
move |acc, item| {
|
||||
let acc = fold(acc, (count, item));
|
||||
// Possible undefined overflow.
|
||||
AddAssign::add_assign(&mut count, 1);
|
||||
acc
|
||||
}
|
||||
}
|
||||
|
||||
self.iter.fold(init, enumerate(self.count, fold))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1007,48 +1098,60 @@ impl<I> DoubleEndedIterator for Enumerate<I> where
|
||||
{
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<(usize, <I as Iterator>::Item)> {
|
||||
self.iter.next_back().map(|a| {
|
||||
let len = self.iter.len();
|
||||
// Can safely add, `ExactSizeIterator` promises that the number of
|
||||
// elements fits into a `usize`.
|
||||
(self.count + len, a)
|
||||
})
|
||||
let a = self.iter.next_back()?;
|
||||
let len = self.iter.len();
|
||||
// Can safely add, `ExactSizeIterator` promises that the number of
|
||||
// elements fits into a `usize`.
|
||||
Some((self.count + len, a))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn nth_back(&mut self, n: usize) -> Option<(usize, <I as Iterator>::Item)> {
|
||||
self.iter.nth_back(n).map(|a| {
|
||||
let len = self.iter.len();
|
||||
// Can safely add, `ExactSizeIterator` promises that the number of
|
||||
// elements fits into a `usize`.
|
||||
(self.count + len, a)
|
||||
})
|
||||
let a = self.iter.nth_back(n)?;
|
||||
let len = self.iter.len();
|
||||
// Can safely add, `ExactSizeIterator` promises that the number of
|
||||
// elements fits into a `usize`.
|
||||
Some((self.count + len, a))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, mut fold: Fold) -> R where
|
||||
fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
|
||||
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
|
||||
{
|
||||
// Can safely add and subtract the count, as `ExactSizeIterator` promises
|
||||
// that the number of elements fits into a `usize`.
|
||||
let mut count = self.count + self.iter.len();
|
||||
self.iter.try_rfold(init, move |acc, item| {
|
||||
count -= 1;
|
||||
fold(acc, (count, item))
|
||||
})
|
||||
fn enumerate<T, Acc, R>(
|
||||
mut count: usize,
|
||||
mut fold: impl FnMut(Acc, (usize, T)) -> R,
|
||||
) -> impl FnMut(Acc, T) -> R {
|
||||
move |acc, item| {
|
||||
count -= 1;
|
||||
fold(acc, (count, item))
|
||||
}
|
||||
}
|
||||
|
||||
let count = self.count + self.iter.len();
|
||||
self.iter.try_rfold(init, enumerate(count, fold))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
// Can safely add and subtract the count, as `ExactSizeIterator` promises
|
||||
// that the number of elements fits into a `usize`.
|
||||
let mut count = self.count + self.iter.len();
|
||||
self.iter.rfold(init, move |acc, item| {
|
||||
count -= 1;
|
||||
fold(acc, (count, item))
|
||||
})
|
||||
fn enumerate<T, Acc>(
|
||||
mut count: usize,
|
||||
mut fold: impl FnMut(Acc, (usize, T)) -> Acc,
|
||||
) -> impl FnMut(Acc, T) -> Acc {
|
||||
move |acc, item| {
|
||||
count -= 1;
|
||||
fold(acc, (count, item))
|
||||
}
|
||||
}
|
||||
|
||||
let count = self.count + self.iter.len();
|
||||
self.iter.rfold(init, enumerate(count, fold))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1162,7 +1265,10 @@ impl<I: Iterator> Iterator for Peekable<I> {
|
||||
};
|
||||
let (lo, hi) = self.iter.size_hint();
|
||||
let lo = lo.saturating_add(peek_len);
|
||||
let hi = hi.and_then(|x| x.checked_add(peek_len));
|
||||
let hi = match hi {
|
||||
Some(x) => x.checked_add(peek_len),
|
||||
None => None,
|
||||
};
|
||||
(lo, hi)
|
||||
}
|
||||
|
||||
@ -1321,16 +1427,23 @@ impl<I: Iterator, P> Iterator for SkipWhile<I, P>
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<I::Item> {
|
||||
fn check<'a, T>(
|
||||
flag: &'a mut bool,
|
||||
pred: &'a mut impl FnMut(&T) -> bool,
|
||||
) -> impl FnMut(&T) -> bool + 'a {
|
||||
move |x| {
|
||||
if *flag || !pred(x) {
|
||||
*flag = true;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let flag = &mut self.flag;
|
||||
let pred = &mut self.predicate;
|
||||
self.iter.find(move |x| {
|
||||
if *flag || !pred(x) {
|
||||
*flag = true;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
self.iter.find(check(flag, pred))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -1412,14 +1525,13 @@ impl<I: Iterator, P> Iterator for TakeWhile<I, P>
|
||||
if self.flag {
|
||||
None
|
||||
} else {
|
||||
self.iter.next().and_then(|x| {
|
||||
if (self.predicate)(&x) {
|
||||
Some(x)
|
||||
} else {
|
||||
self.flag = true;
|
||||
None
|
||||
}
|
||||
})
|
||||
let x = self.iter.next()?;
|
||||
if (self.predicate)(&x) {
|
||||
Some(x)
|
||||
} else {
|
||||
self.flag = true;
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1434,22 +1546,30 @@ impl<I: Iterator, P> Iterator for TakeWhile<I, P>
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, mut fold: Fold) -> R where
|
||||
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
|
||||
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
|
||||
{
|
||||
if self.flag {
|
||||
Try::from_ok(init)
|
||||
} else {
|
||||
let flag = &mut self.flag;
|
||||
let p = &mut self.predicate;
|
||||
self.iter.try_fold(init, move |acc, x|{
|
||||
fn check<'a, T, Acc, R: Try<Ok = Acc>>(
|
||||
flag: &'a mut bool,
|
||||
p: &'a mut impl FnMut(&T) -> bool,
|
||||
mut fold: impl FnMut(Acc, T) -> R + 'a,
|
||||
) -> impl FnMut(Acc, T) -> LoopState<Acc, R> + 'a {
|
||||
move |acc, x| {
|
||||
if p(&x) {
|
||||
LoopState::from_try(fold(acc, x))
|
||||
} else {
|
||||
*flag = true;
|
||||
LoopState::Break(Try::from_ok(acc))
|
||||
}
|
||||
}).into_try()
|
||||
}
|
||||
}
|
||||
|
||||
if self.flag {
|
||||
Try::from_ok(init)
|
||||
} else {
|
||||
let flag = &mut self.flag;
|
||||
let p = &mut self.predicate;
|
||||
self.iter.try_fold(init, check(flag, p, fold)).into_try()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1534,7 +1654,10 @@ impl<I> Iterator for Skip<I> where I: Iterator {
|
||||
let (lower, upper) = self.iter.size_hint();
|
||||
|
||||
let lower = lower.saturating_sub(self.n);
|
||||
let upper = upper.map(|x| x.saturating_sub(self.n));
|
||||
let upper = match upper {
|
||||
Some(x) => Some(x.saturating_sub(self.n)),
|
||||
None => None,
|
||||
};
|
||||
|
||||
(lower, upper)
|
||||
}
|
||||
@ -1595,19 +1718,26 @@ impl<I> DoubleEndedIterator for Skip<I> where I: DoubleEndedIterator + ExactSize
|
||||
}
|
||||
}
|
||||
|
||||
fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, mut fold: Fold) -> R where
|
||||
fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
|
||||
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
|
||||
{
|
||||
let mut n = self.len();
|
||||
if n == 0 {
|
||||
Try::from_ok(init)
|
||||
} else {
|
||||
self.iter.try_rfold(init, move |acc, x| {
|
||||
fn check<T, Acc, R: Try<Ok = Acc>>(
|
||||
mut n: usize,
|
||||
mut fold: impl FnMut(Acc, T) -> R,
|
||||
) -> impl FnMut(Acc, T) -> LoopState<Acc, R> {
|
||||
move |acc, x| {
|
||||
n -= 1;
|
||||
let r = fold(acc, x);
|
||||
if n == 0 { LoopState::Break(r) }
|
||||
else { LoopState::from_try(r) }
|
||||
}).into_try()
|
||||
}
|
||||
}
|
||||
|
||||
let n = self.len();
|
||||
if n == 0 {
|
||||
Try::from_ok(init)
|
||||
} else {
|
||||
self.iter.try_rfold(init, check(n, fold)).into_try()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1682,19 +1812,26 @@ impl<I> Iterator for Take<I> where I: Iterator{
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, mut fold: Fold) -> R where
|
||||
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
|
||||
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
|
||||
{
|
||||
if self.n == 0 {
|
||||
Try::from_ok(init)
|
||||
} else {
|
||||
let n = &mut self.n;
|
||||
self.iter.try_fold(init, move |acc, x| {
|
||||
fn check<'a, T, Acc, R: Try<Ok = Acc>>(
|
||||
n: &'a mut usize,
|
||||
mut fold: impl FnMut(Acc, T) -> R + 'a,
|
||||
) -> impl FnMut(Acc, T) -> LoopState<Acc, R> + 'a {
|
||||
move |acc, x| {
|
||||
*n -= 1;
|
||||
let r = fold(acc, x);
|
||||
if *n == 0 { LoopState::Break(r) }
|
||||
else { LoopState::from_try(r) }
|
||||
}).into_try()
|
||||
}
|
||||
}
|
||||
|
||||
if self.n == 0 {
|
||||
Try::from_ok(init)
|
||||
} else {
|
||||
let n = &mut self.n;
|
||||
self.iter.try_fold(init, check(n, fold)).into_try()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1793,7 +1930,8 @@ impl<B, I, St, F> Iterator for Scan<I, St, F> where
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<B> {
|
||||
self.iter.next().and_then(|a| (self.f)(&mut self.state, a))
|
||||
let a = self.iter.next()?;
|
||||
(self.f)(&mut self.state, a)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -1803,17 +1941,25 @@ impl<B, I, St, F> Iterator for Scan<I, St, F> where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, mut fold: Fold) -> R where
|
||||
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
|
||||
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
|
||||
{
|
||||
fn scan<'a, T, St, B, Acc, R: Try<Ok = Acc>>(
|
||||
state: &'a mut St,
|
||||
f: &'a mut impl FnMut(&mut St, T) -> Option<B>,
|
||||
mut fold: impl FnMut(Acc, B) -> R + 'a,
|
||||
) -> impl FnMut(Acc, T) -> LoopState<Acc, R> + 'a {
|
||||
move |acc, x| {
|
||||
match f(state, x) {
|
||||
None => LoopState::Break(Try::from_ok(acc)),
|
||||
Some(x) => LoopState::from_try(fold(acc, x)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let state = &mut self.state;
|
||||
let f = &mut self.f;
|
||||
self.iter.try_fold(init, move |acc, x| {
|
||||
match f(state, x) {
|
||||
None => LoopState::Break(Try::from_ok(acc)),
|
||||
Some(x) => LoopState::from_try(fold(acc, x)),
|
||||
}
|
||||
}).into_try()
|
||||
self.iter.try_fold(init, scan(state, f, fold)).into_try()
|
||||
}
|
||||
}
|
||||
|
||||
@ -2104,6 +2250,20 @@ impl<I: Iterator, F> Inspect<I, F> where F: FnMut(&I::Item) {
|
||||
}
|
||||
}
|
||||
|
||||
fn inspect_fold<T, Acc>(
|
||||
mut f: impl FnMut(&T),
|
||||
mut fold: impl FnMut(Acc, T) -> Acc,
|
||||
) -> impl FnMut(Acc, T) -> Acc {
|
||||
move |acc, item| { f(&item); fold(acc, item) }
|
||||
}
|
||||
|
||||
fn inspect_try_fold<'a, T, Acc, R>(
|
||||
f: &'a mut impl FnMut(&T),
|
||||
mut fold: impl FnMut(Acc, T) -> R + 'a,
|
||||
) -> impl FnMut(Acc, T) -> R + 'a {
|
||||
move |acc, item| { f(&item); fold(acc, item) }
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<I: Iterator, F> Iterator for Inspect<I, F> where F: FnMut(&I::Item) {
|
||||
type Item = I::Item;
|
||||
@ -2120,19 +2280,17 @@ impl<I: Iterator, F> Iterator for Inspect<I, F> where F: FnMut(&I::Item) {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, mut fold: Fold) -> R where
|
||||
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
|
||||
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
|
||||
{
|
||||
let f = &mut self.f;
|
||||
self.iter.try_fold(init, move |acc, item| { f(&item); fold(acc, item) })
|
||||
self.iter.try_fold(init, inspect_try_fold(&mut self.f, fold))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let mut f = self.f;
|
||||
self.iter.fold(init, move |acc, item| { f(&item); fold(acc, item) })
|
||||
self.iter.fold(init, inspect_fold(self.f, fold))
|
||||
}
|
||||
}
|
||||
|
||||
@ -2147,19 +2305,17 @@ impl<I: DoubleEndedIterator, F> DoubleEndedIterator for Inspect<I, F>
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, mut fold: Fold) -> R where
|
||||
fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
|
||||
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
|
||||
{
|
||||
let f = &mut self.f;
|
||||
self.iter.try_rfold(init, move |acc, item| { f(&item); fold(acc, item) })
|
||||
self.iter.try_rfold(init, inspect_try_fold(&mut self.f, fold))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
|
||||
fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
|
||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let mut f = self.f;
|
||||
self.iter.rfold(init, move |acc, item| { f(&item); fold(acc, item) })
|
||||
self.iter.rfold(init, inspect_fold(self.f, fold))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -94,11 +94,9 @@ impl<A, B> ZipImpl<A, B> for Zip<A, B>
|
||||
|
||||
#[inline]
|
||||
default fn next(&mut self) -> Option<(A::Item, B::Item)> {
|
||||
self.a.next().and_then(|x| {
|
||||
self.b.next().and_then(|y| {
|
||||
Some((x, y))
|
||||
})
|
||||
})
|
||||
let x = self.a.next()?;
|
||||
let y = self.b.next()?;
|
||||
Some((x, y))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -394,7 +394,8 @@ impl<A, F: FnOnce() -> A> Iterator for OnceWith<F> {
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A> {
|
||||
self.gen.take().map(|f| f())
|
||||
let f = self.gen.take()?;
|
||||
Some(f())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -608,10 +609,9 @@ impl<T, F> Iterator for Successors<T, F>
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.next.take().map(|item| {
|
||||
self.next = (self.succ)(&item);
|
||||
item
|
||||
})
|
||||
let item = self.next.take()?;
|
||||
self.next = (self.succ)(&item);
|
||||
Some(item)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -85,28 +85,28 @@ macro_rules! float_sum_product {
|
||||
#[stable(feature = "iter_arith_traits", since = "1.12.0")]
|
||||
impl Sum for $a {
|
||||
fn sum<I: Iterator<Item=$a>>(iter: I) -> $a {
|
||||
iter.fold(0.0, |a, b| a + b)
|
||||
iter.fold(0.0, Add::add)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "iter_arith_traits", since = "1.12.0")]
|
||||
impl Product for $a {
|
||||
fn product<I: Iterator<Item=$a>>(iter: I) -> $a {
|
||||
iter.fold(1.0, |a, b| a * b)
|
||||
iter.fold(1.0, Mul::mul)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "iter_arith_traits", since = "1.12.0")]
|
||||
impl<'a> Sum<&'a $a> for $a {
|
||||
fn sum<I: Iterator<Item=&'a $a>>(iter: I) -> $a {
|
||||
iter.fold(0.0, |a, b| a + *b)
|
||||
iter.fold(0.0, Add::add)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "iter_arith_traits", since = "1.12.0")]
|
||||
impl<'a> Product<&'a $a> for $a {
|
||||
fn product<I: Iterator<Item=&'a $a>>(iter: I) -> $a {
|
||||
iter.fold(1.0, |a, b| a * *b)
|
||||
iter.fold(1.0, Mul::mul)
|
||||
}
|
||||
}
|
||||
)*)
|
||||
|
@ -69,7 +69,7 @@ pub trait DoubleEndedIterator: Iterator {
|
||||
/// Returns the `n`th element from the end of the iterator.
|
||||
///
|
||||
/// This is essentially the reversed version of [`nth`]. Although like most indexing
|
||||
/// operations, the count starts from zero, so `nth_back(0)` returns the first value fro
|
||||
/// operations, the count starts from zero, so `nth_back(0)` returns the first value from
|
||||
/// the end, `nth_back(1)` the second, and so on.
|
||||
///
|
||||
/// Note that all elements between the end and the returned element will be
|
||||
@ -219,12 +219,17 @@ pub trait DoubleEndedIterator: Iterator {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "iter_rfold", since = "1.27.0")]
|
||||
fn rfold<B, F>(mut self, accum: B, mut f: F) -> B
|
||||
fn rfold<B, F>(mut self, accum: B, f: F) -> B
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnMut(B, Self::Item) -> B,
|
||||
{
|
||||
self.try_rfold(accum, move |acc, x| Ok::<B, !>(f(acc, x))).unwrap()
|
||||
#[inline]
|
||||
fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
|
||||
move |acc, x| Ok(f(acc, x))
|
||||
}
|
||||
|
||||
self.try_rfold(accum, ok(f)).unwrap()
|
||||
}
|
||||
|
||||
/// Searches for an element of an iterator from the back that satisfies a predicate.
|
||||
@ -271,15 +276,21 @@ pub trait DoubleEndedIterator: Iterator {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "iter_rfind", since = "1.27.0")]
|
||||
fn rfind<P>(&mut self, mut predicate: P) -> Option<Self::Item>
|
||||
fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
|
||||
where
|
||||
Self: Sized,
|
||||
P: FnMut(&Self::Item) -> bool
|
||||
{
|
||||
self.try_rfold((), move |(), x| {
|
||||
if predicate(&x) { LoopState::Break(x) }
|
||||
else { LoopState::Continue(()) }
|
||||
}).break_value()
|
||||
#[inline]
|
||||
fn check<T>(
|
||||
mut predicate: impl FnMut(&T) -> bool,
|
||||
) -> impl FnMut((), T) -> LoopState<(), T> {
|
||||
move |(), x| {
|
||||
if predicate(&x) { LoopState::Break(x) } else { LoopState::Continue(()) }
|
||||
}
|
||||
}
|
||||
|
||||
self.try_rfold((), check(predicate)).break_value()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::cmp::Ordering;
|
||||
use crate::ops::Try;
|
||||
use crate::ops::{Add, Try};
|
||||
|
||||
use super::super::LoopState;
|
||||
use super::super::{Chain, Cycle, Copied, Cloned, Enumerate, Filter, FilterMap, Fuse};
|
||||
@ -234,11 +234,15 @@ pub trait Iterator {
|
||||
/// assert_eq!(a.iter().count(), 5);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn count(self) -> usize where Self: Sized {
|
||||
// Might overflow.
|
||||
self.fold(0, |cnt, _| cnt + 1)
|
||||
#[inline]
|
||||
fn add1<T>(count: usize, _: T) -> usize {
|
||||
// Might overflow.
|
||||
Add::add(count, 1)
|
||||
}
|
||||
|
||||
self.fold(0, add1)
|
||||
}
|
||||
|
||||
/// Consumes the iterator, returning the last element.
|
||||
@ -263,7 +267,12 @@ pub trait Iterator {
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn last(self) -> Option<Self::Item> where Self: Sized {
|
||||
self.fold(None, |_, x| Some(x))
|
||||
#[inline]
|
||||
fn some<T>(_: Option<T>, x: T) -> Option<T> {
|
||||
Some(x)
|
||||
}
|
||||
|
||||
self.fold(None, some)
|
||||
}
|
||||
|
||||
/// Returns the `n`th element of the iterator.
|
||||
@ -596,10 +605,15 @@ pub trait Iterator {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "iterator_for_each", since = "1.21.0")]
|
||||
fn for_each<F>(self, mut f: F) where
|
||||
fn for_each<F>(self, f: F) where
|
||||
Self: Sized, F: FnMut(Self::Item),
|
||||
{
|
||||
self.fold((), move |(), item| f(item));
|
||||
#[inline]
|
||||
fn call<T>(mut f: impl FnMut(T)) -> impl FnMut((), T) {
|
||||
move |(), item| f(item)
|
||||
}
|
||||
|
||||
self.fold((), call(f));
|
||||
}
|
||||
|
||||
/// Creates an iterator which uses a closure to determine if an element
|
||||
@ -1490,21 +1504,30 @@ pub trait Iterator {
|
||||
/// assert_eq!(odd, vec![1, 3]);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn partition<B, F>(self, mut f: F) -> (B, B) where
|
||||
fn partition<B, F>(self, f: F) -> (B, B) where
|
||||
Self: Sized,
|
||||
B: Default + Extend<Self::Item>,
|
||||
F: FnMut(&Self::Item) -> bool
|
||||
{
|
||||
#[inline]
|
||||
fn extend<'a, T, B: Extend<T>>(
|
||||
mut f: impl FnMut(&T) -> bool + 'a,
|
||||
left: &'a mut B,
|
||||
right: &'a mut B,
|
||||
) -> impl FnMut(T) + 'a {
|
||||
move |x| {
|
||||
if f(&x) {
|
||||
left.extend(Some(x));
|
||||
} else {
|
||||
right.extend(Some(x));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut left: B = Default::default();
|
||||
let mut right: B = Default::default();
|
||||
|
||||
self.for_each(|x| {
|
||||
if f(&x) {
|
||||
left.extend(Some(x))
|
||||
} else {
|
||||
right.extend(Some(x))
|
||||
}
|
||||
});
|
||||
self.for_each(extend(f, &mut left, &mut right));
|
||||
|
||||
(left, right)
|
||||
}
|
||||
@ -1702,10 +1725,15 @@ pub trait Iterator {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "iterator_try_fold", since = "1.27.0")]
|
||||
fn try_for_each<F, R>(&mut self, mut f: F) -> R where
|
||||
fn try_for_each<F, R>(&mut self, f: F) -> R where
|
||||
Self: Sized, F: FnMut(Self::Item) -> R, R: Try<Ok=()>
|
||||
{
|
||||
self.try_fold((), move |(), x| f(x))
|
||||
#[inline]
|
||||
fn call<T, R>(mut f: impl FnMut(T) -> R) -> impl FnMut((), T) -> R {
|
||||
move |(), x| f(x)
|
||||
}
|
||||
|
||||
self.try_fold((), call(f))
|
||||
}
|
||||
|
||||
/// An iterator method that applies a function, producing a single, final value.
|
||||
@ -1777,10 +1805,15 @@ pub trait Iterator {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn fold<B, F>(mut self, init: B, mut f: F) -> B where
|
||||
fn fold<B, F>(mut self, init: B, f: F) -> B where
|
||||
Self: Sized, F: FnMut(B, Self::Item) -> B,
|
||||
{
|
||||
self.try_fold(init, move |acc, x| Ok::<B, !>(f(acc, x))).unwrap()
|
||||
#[inline]
|
||||
fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
|
||||
move |acc, x| Ok(f(acc, x))
|
||||
}
|
||||
|
||||
self.try_fold(init, ok(f)).unwrap()
|
||||
}
|
||||
|
||||
/// Tests if every element of the iterator matches a predicate.
|
||||
@ -1822,13 +1855,18 @@ pub trait Iterator {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn all<F>(&mut self, mut f: F) -> bool where
|
||||
fn all<F>(&mut self, f: F) -> bool where
|
||||
Self: Sized, F: FnMut(Self::Item) -> bool
|
||||
{
|
||||
self.try_for_each(move |x| {
|
||||
if f(x) { LoopState::Continue(()) }
|
||||
else { LoopState::Break(()) }
|
||||
}) == LoopState::Continue(())
|
||||
#[inline]
|
||||
fn check<T>(mut f: impl FnMut(T) -> bool) -> impl FnMut(T) -> LoopState<(), ()> {
|
||||
move |x| {
|
||||
if f(x) { LoopState::Continue(()) }
|
||||
else { LoopState::Break(()) }
|
||||
}
|
||||
}
|
||||
|
||||
self.try_for_each(check(f)) == LoopState::Continue(())
|
||||
}
|
||||
|
||||
/// Tests if any element of the iterator matches a predicate.
|
||||
@ -1870,14 +1908,19 @@ pub trait Iterator {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn any<F>(&mut self, mut f: F) -> bool where
|
||||
fn any<F>(&mut self, f: F) -> bool where
|
||||
Self: Sized,
|
||||
F: FnMut(Self::Item) -> bool
|
||||
{
|
||||
self.try_for_each(move |x| {
|
||||
if f(x) { LoopState::Break(()) }
|
||||
else { LoopState::Continue(()) }
|
||||
}) == LoopState::Break(())
|
||||
#[inline]
|
||||
fn check<T>(mut f: impl FnMut(T) -> bool) -> impl FnMut(T) -> LoopState<(), ()> {
|
||||
move |x| {
|
||||
if f(x) { LoopState::Break(()) }
|
||||
else { LoopState::Continue(()) }
|
||||
}
|
||||
}
|
||||
|
||||
self.try_for_each(check(f)) == LoopState::Break(())
|
||||
}
|
||||
|
||||
/// Searches for an element of an iterator that satisfies a predicate.
|
||||
@ -1924,14 +1967,19 @@ pub trait Iterator {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item> where
|
||||
fn find<P>(&mut self, predicate: P) -> Option<Self::Item> where
|
||||
Self: Sized,
|
||||
P: FnMut(&Self::Item) -> bool,
|
||||
{
|
||||
self.try_for_each(move |x| {
|
||||
if predicate(&x) { LoopState::Break(x) }
|
||||
else { LoopState::Continue(()) }
|
||||
}).break_value()
|
||||
#[inline]
|
||||
fn check<T>(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut(T) -> LoopState<(), T> {
|
||||
move |x| {
|
||||
if predicate(&x) { LoopState::Break(x) }
|
||||
else { LoopState::Continue(()) }
|
||||
}
|
||||
}
|
||||
|
||||
self.try_for_each(check(predicate)).break_value()
|
||||
}
|
||||
|
||||
/// Applies function to the elements of iterator and returns
|
||||
@ -1951,16 +1999,19 @@ pub trait Iterator {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "iterator_find_map", since = "1.30.0")]
|
||||
fn find_map<B, F>(&mut self, mut f: F) -> Option<B> where
|
||||
fn find_map<B, F>(&mut self, f: F) -> Option<B> where
|
||||
Self: Sized,
|
||||
F: FnMut(Self::Item) -> Option<B>,
|
||||
{
|
||||
self.try_for_each(move |x| {
|
||||
match f(x) {
|
||||
#[inline]
|
||||
fn check<T, B>(mut f: impl FnMut(T) -> Option<B>) -> impl FnMut(T) -> LoopState<(), B> {
|
||||
move |x| match f(x) {
|
||||
Some(x) => LoopState::Break(x),
|
||||
None => LoopState::Continue(()),
|
||||
}
|
||||
}).break_value()
|
||||
}
|
||||
|
||||
self.try_for_each(check(f)).break_value()
|
||||
}
|
||||
|
||||
/// Searches for an element in an iterator, returning its index.
|
||||
@ -2018,17 +2069,23 @@ pub trait Iterator {
|
||||
///
|
||||
/// ```
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn position<P>(&mut self, mut predicate: P) -> Option<usize> where
|
||||
fn position<P>(&mut self, predicate: P) -> Option<usize> where
|
||||
Self: Sized,
|
||||
P: FnMut(Self::Item) -> bool,
|
||||
{
|
||||
// The addition might panic on overflow
|
||||
self.try_fold(0, move |i, x| {
|
||||
if predicate(x) { LoopState::Break(i) }
|
||||
else { LoopState::Continue(i + 1) }
|
||||
}).break_value()
|
||||
#[inline]
|
||||
fn check<T>(
|
||||
mut predicate: impl FnMut(T) -> bool,
|
||||
) -> impl FnMut(usize, T) -> LoopState<usize, usize> {
|
||||
// The addition might panic on overflow
|
||||
move |i, x| {
|
||||
if predicate(x) { LoopState::Break(i) }
|
||||
else { LoopState::Continue(Add::add(i, 1)) }
|
||||
}
|
||||
}
|
||||
|
||||
self.try_fold(0, check(predicate)).break_value()
|
||||
}
|
||||
|
||||
/// Searches for an element in an iterator from the right, returning its
|
||||
@ -2071,18 +2128,25 @@ pub trait Iterator {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn rposition<P>(&mut self, mut predicate: P) -> Option<usize> where
|
||||
fn rposition<P>(&mut self, predicate: P) -> Option<usize> where
|
||||
P: FnMut(Self::Item) -> bool,
|
||||
Self: Sized + ExactSizeIterator + DoubleEndedIterator
|
||||
{
|
||||
// No need for an overflow check here, because `ExactSizeIterator`
|
||||
// implies that the number of elements fits into a `usize`.
|
||||
#[inline]
|
||||
fn check<T>(
|
||||
mut predicate: impl FnMut(T) -> bool,
|
||||
) -> impl FnMut(usize, T) -> LoopState<usize, usize> {
|
||||
move |i, x| {
|
||||
let i = i - 1;
|
||||
if predicate(x) { LoopState::Break(i) }
|
||||
else { LoopState::Continue(i) }
|
||||
}
|
||||
}
|
||||
|
||||
let n = self.len();
|
||||
self.try_rfold(n, move |i, x| {
|
||||
let i = i - 1;
|
||||
if predicate(x) { LoopState::Break(i) }
|
||||
else { LoopState::Continue(i) }
|
||||
}).break_value()
|
||||
self.try_rfold(n, check(predicate)).break_value()
|
||||
}
|
||||
|
||||
/// Returns the maximum element of an iterator.
|
||||
@ -2151,11 +2215,22 @@ pub trait Iterator {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "iter_cmp_by_key", since = "1.6.0")]
|
||||
fn max_by_key<B: Ord, F>(self, mut f: F) -> Option<Self::Item>
|
||||
fn max_by_key<B: Ord, F>(self, f: F) -> Option<Self::Item>
|
||||
where Self: Sized, F: FnMut(&Self::Item) -> B,
|
||||
{
|
||||
#[inline]
|
||||
fn key<T, B>(mut f: impl FnMut(&T) -> B) -> impl FnMut(T) -> (B, T) {
|
||||
move |x| (f(&x), x)
|
||||
}
|
||||
|
||||
// switch to y even if it is only equal, to preserve stability.
|
||||
select_fold1(self.map(|x| (f(&x), x)), |(x_p, _), (y_p, _)| x_p <= y_p).map(|(_, x)| x)
|
||||
#[inline]
|
||||
fn select<T, B: Ord>((x_p, _): &(B, T), (y_p, _): &(B, T)) -> bool {
|
||||
x_p <= y_p
|
||||
}
|
||||
|
||||
let (_, x) = select_fold1(self.map(key(f)), select)?;
|
||||
Some(x)
|
||||
}
|
||||
|
||||
/// Returns the element that gives the maximum value with respect to the
|
||||
@ -2174,11 +2249,16 @@ pub trait Iterator {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "iter_max_by", since = "1.15.0")]
|
||||
fn max_by<F>(self, mut compare: F) -> Option<Self::Item>
|
||||
fn max_by<F>(self, compare: F) -> Option<Self::Item>
|
||||
where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering,
|
||||
{
|
||||
// switch to y even if it is only equal, to preserve stability.
|
||||
select_fold1(self, |x, y| compare(x, y) != Ordering::Greater)
|
||||
#[inline]
|
||||
fn select<T>(mut compare: impl FnMut(&T, &T) -> Ordering) -> impl FnMut(&T, &T) -> bool {
|
||||
move |x, y| compare(x, y) != Ordering::Greater
|
||||
}
|
||||
|
||||
select_fold1(self, select(compare))
|
||||
}
|
||||
|
||||
/// Returns the element that gives the minimum value from the
|
||||
@ -2195,12 +2275,24 @@ pub trait Iterator {
|
||||
/// let a = [-3_i32, 0, 1, 5, -10];
|
||||
/// assert_eq!(*a.iter().min_by_key(|x| x.abs()).unwrap(), 0);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "iter_cmp_by_key", since = "1.6.0")]
|
||||
fn min_by_key<B: Ord, F>(self, mut f: F) -> Option<Self::Item>
|
||||
fn min_by_key<B: Ord, F>(self, f: F) -> Option<Self::Item>
|
||||
where Self: Sized, F: FnMut(&Self::Item) -> B,
|
||||
{
|
||||
#[inline]
|
||||
fn key<T, B>(mut f: impl FnMut(&T) -> B) -> impl FnMut(T) -> (B, T) {
|
||||
move |x| (f(&x), x)
|
||||
}
|
||||
|
||||
// only switch to y if it is strictly smaller, to preserve stability.
|
||||
select_fold1(self.map(|x| (f(&x), x)), |(x_p, _), (y_p, _)| x_p > y_p).map(|(_, x)| x)
|
||||
#[inline]
|
||||
fn select<T, B: Ord>((x_p, _): &(B, T), (y_p, _): &(B, T)) -> bool {
|
||||
x_p > y_p
|
||||
}
|
||||
|
||||
let (_, x) = select_fold1(self.map(key(f)), select)?;
|
||||
Some(x)
|
||||
}
|
||||
|
||||
/// Returns the element that gives the minimum value with respect to the
|
||||
@ -2219,11 +2311,16 @@ pub trait Iterator {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "iter_min_by", since = "1.15.0")]
|
||||
fn min_by<F>(self, mut compare: F) -> Option<Self::Item>
|
||||
fn min_by<F>(self, compare: F) -> Option<Self::Item>
|
||||
where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering,
|
||||
{
|
||||
// only switch to y if it is strictly smaller, to preserve stability.
|
||||
select_fold1(self, |x, y| compare(x, y) == Ordering::Greater)
|
||||
#[inline]
|
||||
fn select<T>(mut compare: impl FnMut(&T, &T) -> Ordering) -> impl FnMut(&T, &T) -> bool {
|
||||
move |x, y| compare(x, y) == Ordering::Greater
|
||||
}
|
||||
|
||||
select_fold1(self, select(compare))
|
||||
}
|
||||
|
||||
|
||||
@ -2284,13 +2381,20 @@ pub trait Iterator {
|
||||
FromB: Default + Extend<B>,
|
||||
Self: Sized + Iterator<Item=(A, B)>,
|
||||
{
|
||||
fn extend<'a, A, B>(
|
||||
ts: &'a mut impl Extend<A>,
|
||||
us: &'a mut impl Extend<B>,
|
||||
) -> impl FnMut((A, B)) + 'a {
|
||||
move |(t, u)| {
|
||||
ts.extend(Some(t));
|
||||
us.extend(Some(u));
|
||||
}
|
||||
}
|
||||
|
||||
let mut ts: FromA = Default::default();
|
||||
let mut us: FromB = Default::default();
|
||||
|
||||
self.for_each(|(t, u)| {
|
||||
ts.extend(Some(t));
|
||||
us.extend(Some(u));
|
||||
});
|
||||
self.for_each(extend(&mut ts, &mut us));
|
||||
|
||||
(ts, us)
|
||||
}
|
||||
@ -2617,7 +2721,7 @@ pub trait Iterator {
|
||||
Self: Sized,
|
||||
Self::Item: PartialOrd,
|
||||
{
|
||||
self.is_sorted_by(|a, b| a.partial_cmp(b))
|
||||
self.is_sorted_by(PartialOrd::partial_cmp)
|
||||
}
|
||||
|
||||
/// Checks if the elements of this iterator are sorted using the given comparator function.
|
||||
@ -2639,10 +2743,7 @@ pub trait Iterator {
|
||||
};
|
||||
|
||||
while let Some(curr) = self.next() {
|
||||
if compare(&last, &curr)
|
||||
.map(|o| o == Ordering::Greater)
|
||||
.unwrap_or(true)
|
||||
{
|
||||
if let Some(Ordering::Greater) | None = compare(&last, &curr) {
|
||||
return false;
|
||||
}
|
||||
last = curr;
|
||||
@ -2687,17 +2788,21 @@ pub trait Iterator {
|
||||
/// commonalities of {max,min}{,_by}. In particular, this avoids
|
||||
/// having to implement optimizations several times.
|
||||
#[inline]
|
||||
fn select_fold1<I, F>(mut it: I, mut f: F) -> Option<I::Item>
|
||||
fn select_fold1<I, F>(mut it: I, f: F) -> Option<I::Item>
|
||||
where
|
||||
I: Iterator,
|
||||
F: FnMut(&I::Item, &I::Item) -> bool,
|
||||
{
|
||||
#[inline]
|
||||
fn select<T>(mut f: impl FnMut(&T, &T) -> bool) -> impl FnMut(T, T) -> T {
|
||||
move |sel, x| if f(&sel, &x) { x } else { sel }
|
||||
}
|
||||
|
||||
// start with the first element as our selection. This avoids
|
||||
// having to use `Option`s inside the loop, translating to a
|
||||
// sizeable performance gain (6x in one case).
|
||||
it.next().map(|first| {
|
||||
it.fold(first, |sel, x| if f(&sel, &x) { x } else { sel })
|
||||
})
|
||||
let first = it.next()?;
|
||||
Some(it.fold(first, select(f)))
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
@ -63,7 +63,7 @@
|
||||
#![warn(missing_debug_implementations)]
|
||||
#![deny(intra_doc_link_resolution_failure)] // rustdoc is run without -D warnings
|
||||
#![allow(explicit_outlives_requirements)]
|
||||
#![cfg_attr(not(bootstrap), allow(incomplete_features))]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
#![feature(allow_internal_unstable)]
|
||||
#![feature(arbitrary_self_types)]
|
||||
@ -129,7 +129,7 @@
|
||||
#![feature(structural_match)]
|
||||
#![feature(abi_unadjusted)]
|
||||
#![feature(adx_target_feature)]
|
||||
#![feature(maybe_uninit_slice, maybe_uninit_array)]
|
||||
#![feature(maybe_uninit_slice)]
|
||||
#![feature(external_doc)]
|
||||
#![feature(mem_take)]
|
||||
#![feature(associated_type_bounds)]
|
||||
|
@ -2,21 +2,21 @@
|
||||
///
|
||||
/// For details, see `std::macros`.
|
||||
#[macro_export]
|
||||
#[allow_internal_unstable(core_panic, __rust_unstable_column)]
|
||||
#[allow_internal_unstable(core_panic)]
|
||||
#[stable(feature = "core", since = "1.6.0")]
|
||||
macro_rules! panic {
|
||||
() => (
|
||||
$crate::panic!("explicit panic")
|
||||
);
|
||||
($msg:expr) => ({
|
||||
$crate::panicking::panic(&($msg, file!(), line!(), __rust_unstable_column!()))
|
||||
$crate::panicking::panic(&($msg, $crate::file!(), $crate::line!(), $crate::column!()))
|
||||
});
|
||||
($msg:expr,) => (
|
||||
$crate::panic!($msg)
|
||||
);
|
||||
($fmt:expr, $($arg:tt)+) => ({
|
||||
$crate::panicking::panic_fmt(format_args!($fmt, $($arg)+),
|
||||
&(file!(), line!(), __rust_unstable_column!()))
|
||||
$crate::panicking::panic_fmt($crate::format_args!($fmt, $($arg)+),
|
||||
&($crate::file!(), $crate::line!(), $crate::column!()))
|
||||
});
|
||||
}
|
||||
|
||||
@ -70,7 +70,7 @@ macro_rules! assert_eq {
|
||||
panic!(r#"assertion failed: `(left == right)`
|
||||
left: `{:?}`,
|
||||
right: `{:?}`: {}"#, &*left_val, &*right_val,
|
||||
format_args!($($arg)+))
|
||||
$crate::format_args!($($arg)+))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -127,7 +127,7 @@ macro_rules! assert_ne {
|
||||
panic!(r#"assertion failed: `(left != right)`
|
||||
left: `{:?}`,
|
||||
right: `{:?}`: {}"#, &*left_val, &*right_val,
|
||||
format_args!($($arg)+))
|
||||
$crate::format_args!($($arg)+))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -181,7 +181,7 @@ macro_rules! assert_ne {
|
||||
#[macro_export]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
macro_rules! debug_assert {
|
||||
($($arg:tt)*) => (if cfg!(debug_assertions) { assert!($($arg)*); })
|
||||
($($arg:tt)*) => (if $crate::cfg!(debug_assertions) { $crate::assert!($($arg)*); })
|
||||
}
|
||||
|
||||
/// Asserts that two expressions are equal to each other.
|
||||
@ -208,7 +208,7 @@ macro_rules! debug_assert {
|
||||
#[macro_export]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
macro_rules! debug_assert_eq {
|
||||
($($arg:tt)*) => (if cfg!(debug_assertions) { $crate::assert_eq!($($arg)*); })
|
||||
($($arg:tt)*) => (if $crate::cfg!(debug_assertions) { $crate::assert_eq!($($arg)*); })
|
||||
}
|
||||
|
||||
/// Asserts that two expressions are not equal to each other.
|
||||
@ -235,7 +235,7 @@ macro_rules! debug_assert_eq {
|
||||
#[macro_export]
|
||||
#[stable(feature = "assert_ne", since = "1.13.0")]
|
||||
macro_rules! debug_assert_ne {
|
||||
($($arg:tt)*) => (if cfg!(debug_assertions) { $crate::assert_ne!($($arg)*); })
|
||||
($($arg:tt)*) => (if $crate::cfg!(debug_assertions) { $crate::assert_ne!($($arg)*); })
|
||||
}
|
||||
|
||||
/// Unwraps a result or propagates its error.
|
||||
@ -386,7 +386,7 @@ macro_rules! r#try {
|
||||
#[macro_export]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
macro_rules! write {
|
||||
($dst:expr, $($arg:tt)*) => ($dst.write_fmt(format_args!($($arg)*)))
|
||||
($dst:expr, $($arg:tt)*) => ($dst.write_fmt($crate::format_args!($($arg)*)))
|
||||
}
|
||||
|
||||
/// Write formatted data into a buffer, with a newline appended.
|
||||
@ -446,7 +446,7 @@ macro_rules! writeln {
|
||||
$crate::writeln!($dst)
|
||||
);
|
||||
($dst:expr, $($arg:tt)*) => (
|
||||
$dst.write_fmt(format_args_nl!($($arg)*))
|
||||
$dst.write_fmt($crate::format_args_nl!($($arg)*))
|
||||
);
|
||||
}
|
||||
|
||||
@ -515,7 +515,7 @@ macro_rules! unreachable {
|
||||
$crate::unreachable!($msg)
|
||||
});
|
||||
($fmt:expr, $($arg:tt)*) => ({
|
||||
panic!(concat!("internal error: entered unreachable code: ", $fmt), $($arg)*)
|
||||
panic!($crate::concat!("internal error: entered unreachable code: ", $fmt), $($arg)*)
|
||||
});
|
||||
}
|
||||
|
||||
@ -573,7 +573,7 @@ macro_rules! unreachable {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
macro_rules! unimplemented {
|
||||
() => (panic!("not yet implemented"));
|
||||
($($arg:tt)+) => (panic!("not yet implemented: {}", format_args!($($arg)+)));
|
||||
($($arg:tt)+) => (panic!("not yet implemented: {}", $crate::format_args!($($arg)+)));
|
||||
}
|
||||
|
||||
/// Indicates unfinished code.
|
||||
@ -632,41 +632,7 @@ macro_rules! unimplemented {
|
||||
#[unstable(feature = "todo_macro", issue = "59277")]
|
||||
macro_rules! todo {
|
||||
() => (panic!("not yet implemented"));
|
||||
($($arg:tt)+) => (panic!("not yet implemented: {}", format_args!($($arg)+)));
|
||||
}
|
||||
|
||||
/// Creates an array of [`MaybeUninit`].
|
||||
///
|
||||
/// This macro constructs an uninitialized array of the type `[MaybeUninit<K>; N]`.
|
||||
/// It exists solely because bootstrap does not yet support const array-init expressions.
|
||||
///
|
||||
/// [`MaybeUninit`]: mem/union.MaybeUninit.html
|
||||
// FIXME: Remove both versions of this macro once bootstrap is 1.38.
|
||||
#[macro_export]
|
||||
#[unstable(feature = "maybe_uninit_array", issue = "53491")]
|
||||
#[cfg(bootstrap)]
|
||||
macro_rules! uninit_array {
|
||||
// This `assume_init` is safe because an array of `MaybeUninit` does not
|
||||
// require initialization.
|
||||
($t:ty; $size:expr) => (unsafe {
|
||||
MaybeUninit::<[MaybeUninit<$t>; $size]>::uninit().assume_init()
|
||||
});
|
||||
}
|
||||
|
||||
/// Creates an array of [`MaybeUninit`].
|
||||
///
|
||||
/// This macro constructs an uninitialized array of the type `[MaybeUninit<K>; N]`.
|
||||
/// It exists solely because bootstrap does not yet support const array-init expressions.
|
||||
///
|
||||
/// [`MaybeUninit`]: mem/union.MaybeUninit.html
|
||||
// FIXME: Just inline this version of the macro once bootstrap is 1.38.
|
||||
#[macro_export]
|
||||
#[unstable(feature = "maybe_uninit_array", issue = "53491")]
|
||||
#[cfg(not(bootstrap))]
|
||||
macro_rules! uninit_array {
|
||||
($t:ty; $size:expr) => (
|
||||
[MaybeUninit::<$t>::UNINIT; $size]
|
||||
);
|
||||
($($arg:tt)+) => (panic!("not yet implemented: {}", $crate::format_args!($($arg)+)));
|
||||
}
|
||||
|
||||
/// Definitions of built-in macros.
|
||||
@ -674,7 +640,6 @@ macro_rules! uninit_array {
|
||||
/// Most of the macro properties (stability, visibility, etc.) are taken from the source code here,
|
||||
/// with exception of expansion functions transforming macro inputs into outputs,
|
||||
/// those functions are provided by the compiler.
|
||||
#[cfg(not(bootstrap))]
|
||||
pub(crate) mod builtin {
|
||||
|
||||
/// Causes compilation to fail with the given error message when encountered.
|
||||
@ -962,13 +927,6 @@ pub(crate) mod builtin {
|
||||
#[macro_export]
|
||||
macro_rules! column { () => { /* compiler built-in */ } }
|
||||
|
||||
/// Same as `column`, but less likely to be shadowed.
|
||||
#[unstable(feature = "__rust_unstable_column", issue = "0",
|
||||
reason = "internal implementation detail of the `panic` macro")]
|
||||
#[rustc_builtin_macro]
|
||||
#[macro_export]
|
||||
macro_rules! __rust_unstable_column { () => { /* compiler built-in */ } }
|
||||
|
||||
/// Expands to the file name in which it was invoked.
|
||||
///
|
||||
/// With [`line!`] and [`column!`], these macros provide debugging information for
|
||||
@ -1305,14 +1263,14 @@ pub(crate) mod builtin {
|
||||
|
||||
/// Unstable implementation detail of the `rustc` compiler, do not use.
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[cfg_attr(boostrap_stdarch_ignore_this, rustc_macro_transparency = "semitransparent")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow_internal_unstable(core_intrinsics, libstd_sys_internals)]
|
||||
pub macro RustcDecodable($item:item) { /* compiler built-in */ }
|
||||
|
||||
/// Unstable implementation detail of the `rustc` compiler, do not use.
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[cfg_attr(boostrap_stdarch_ignore_this, rustc_macro_transparency = "semitransparent")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow_internal_unstable(core_intrinsics)]
|
||||
pub macro RustcEncodable($item:item) { /* compiler built-in */ }
|
||||
|
@ -289,9 +289,8 @@ pub trait Copy : Clone {
|
||||
}
|
||||
|
||||
/// Derive macro generating an impl of the trait `Copy`.
|
||||
#[cfg(not(bootstrap))]
|
||||
#[rustc_builtin_macro]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[cfg_attr(boostrap_stdarch_ignore_this, rustc_macro_transparency = "semitransparent")]
|
||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||
#[allow_internal_unstable(core_intrinsics, derive_clone_copy)]
|
||||
pub macro Copy($item:item) { /* compiler built-in */ }
|
||||
|
@ -213,7 +213,7 @@ use crate::mem::ManuallyDrop;
|
||||
#[allow(missing_debug_implementations)]
|
||||
#[stable(feature = "maybe_uninit", since = "1.36.0")]
|
||||
// Lang item so we can wrap other types in it. This is useful for generators.
|
||||
#[cfg_attr(not(bootstrap), lang = "maybe_uninit")]
|
||||
#[lang = "maybe_uninit"]
|
||||
#[derive(Copy)]
|
||||
#[repr(transparent)]
|
||||
pub union MaybeUninit<T> {
|
||||
@ -312,7 +312,7 @@ impl<T> MaybeUninit<T> {
|
||||
/// without dropping it, so be careful not to use this twice unless you want to
|
||||
/// skip running the destructor. For your convenience, this also returns a mutable
|
||||
/// reference to the (now safely initialized) contents of `self`.
|
||||
#[unstable(feature = "maybe_uninit_extra", issue = "53491")]
|
||||
#[unstable(feature = "maybe_uninit_extra", issue = "63567")]
|
||||
#[inline(always)]
|
||||
pub fn write(&mut self, val: T) -> &mut T {
|
||||
unsafe {
|
||||
@ -502,7 +502,7 @@ impl<T> MaybeUninit<T> {
|
||||
/// // We now created two copies of the same vector, leading to a double-free when
|
||||
/// // they both get dropped!
|
||||
/// ```
|
||||
#[unstable(feature = "maybe_uninit_extra", issue = "53491")]
|
||||
#[unstable(feature = "maybe_uninit_extra", issue = "63567")]
|
||||
#[inline(always)]
|
||||
pub unsafe fn read(&self) -> T {
|
||||
intrinsics::panic_if_uninhabited::<T>();
|
||||
@ -516,7 +516,7 @@ impl<T> MaybeUninit<T> {
|
||||
/// It is up to the caller to guarantee that the `MaybeUninit<T>` really is in an initialized
|
||||
/// state. Calling this when the content is not yet fully initialized causes undefined
|
||||
/// behavior.
|
||||
#[unstable(feature = "maybe_uninit_ref", issue = "53491")]
|
||||
#[unstable(feature = "maybe_uninit_ref", issue = "63568")]
|
||||
#[inline(always)]
|
||||
pub unsafe fn get_ref(&self) -> &T {
|
||||
&*self.value
|
||||
@ -532,21 +532,21 @@ impl<T> MaybeUninit<T> {
|
||||
// FIXME(#53491): We currently rely on the above being incorrect, i.e., we have references
|
||||
// to uninitialized data (e.g., in `libcore/fmt/float.rs`). We should make
|
||||
// a final decision about the rules before stabilization.
|
||||
#[unstable(feature = "maybe_uninit_ref", issue = "53491")]
|
||||
#[unstable(feature = "maybe_uninit_ref", issue = "63568")]
|
||||
#[inline(always)]
|
||||
pub unsafe fn get_mut(&mut self) -> &mut T {
|
||||
&mut *self.value
|
||||
}
|
||||
|
||||
/// Gets a pointer to the first element of the array.
|
||||
#[unstable(feature = "maybe_uninit_slice", issue = "53491")]
|
||||
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
|
||||
#[inline(always)]
|
||||
pub fn first_ptr(this: &[MaybeUninit<T>]) -> *const T {
|
||||
this as *const [MaybeUninit<T>] as *const T
|
||||
}
|
||||
|
||||
/// Gets a mutable pointer to the first element of the array.
|
||||
#[unstable(feature = "maybe_uninit_slice", issue = "53491")]
|
||||
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
|
||||
#[inline(always)]
|
||||
pub fn first_ptr_mut(this: &mut [MaybeUninit<T>]) -> *mut T {
|
||||
this as *mut [MaybeUninit<T>] as *mut T
|
||||
|
@ -453,7 +453,7 @@ pub const fn needs_drop<T>() -> bool {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(bootstrap, allow(deprecated_in_future))]
|
||||
#[allow(deprecated_in_future)]
|
||||
#[allow(deprecated)]
|
||||
pub unsafe fn zeroed<T>() -> T {
|
||||
intrinsics::panic_if_uninhabited::<T>();
|
||||
@ -481,7 +481,7 @@ pub unsafe fn zeroed<T>() -> T {
|
||||
#[inline]
|
||||
#[rustc_deprecated(since = "1.39.0", reason = "use `mem::MaybeUninit` instead")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(bootstrap, allow(deprecated_in_future))]
|
||||
#[allow(deprecated_in_future)]
|
||||
#[allow(deprecated)]
|
||||
pub unsafe fn uninitialized<T>() -> T {
|
||||
intrinsics::panic_if_uninhabited::<T>();
|
||||
|
@ -1112,7 +1112,13 @@ $EndFeature, "
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub const fn wrapping_add(self, rhs: Self) -> Self {
|
||||
intrinsics::overflowing_add(self, rhs)
|
||||
#[cfg(boostrap_stdarch_ignore_this)] {
|
||||
intrinsics::overflowing_add(self, rhs)
|
||||
}
|
||||
|
||||
#[cfg(not(boostrap_stdarch_ignore_this))] {
|
||||
intrinsics::wrapping_add(self, rhs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1135,7 +1141,13 @@ $EndFeature, "
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub const fn wrapping_sub(self, rhs: Self) -> Self {
|
||||
intrinsics::overflowing_sub(self, rhs)
|
||||
#[cfg(boostrap_stdarch_ignore_this)] {
|
||||
intrinsics::overflowing_sub(self, rhs)
|
||||
}
|
||||
|
||||
#[cfg(not(boostrap_stdarch_ignore_this))] {
|
||||
intrinsics::wrapping_sub(self, rhs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1157,7 +1169,13 @@ $EndFeature, "
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub const fn wrapping_mul(self, rhs: Self) -> Self {
|
||||
intrinsics::overflowing_mul(self, rhs)
|
||||
#[cfg(boostrap_stdarch_ignore_this)] {
|
||||
intrinsics::overflowing_mul(self, rhs)
|
||||
}
|
||||
|
||||
#[cfg(not(boostrap_stdarch_ignore_this))] {
|
||||
intrinsics::wrapping_mul(self, rhs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3031,7 +3049,13 @@ $EndFeature, "
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub const fn wrapping_add(self, rhs: Self) -> Self {
|
||||
intrinsics::overflowing_add(self, rhs)
|
||||
#[cfg(boostrap_stdarch_ignore_this)] {
|
||||
intrinsics::overflowing_add(self, rhs)
|
||||
}
|
||||
|
||||
#[cfg(not(boostrap_stdarch_ignore_this))] {
|
||||
intrinsics::wrapping_add(self, rhs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3053,7 +3077,13 @@ $EndFeature, "
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub const fn wrapping_sub(self, rhs: Self) -> Self {
|
||||
intrinsics::overflowing_sub(self, rhs)
|
||||
#[cfg(boostrap_stdarch_ignore_this)] {
|
||||
intrinsics::overflowing_sub(self, rhs)
|
||||
}
|
||||
|
||||
#[cfg(not(boostrap_stdarch_ignore_this))] {
|
||||
intrinsics::wrapping_sub(self, rhs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3076,7 +3106,13 @@ $EndFeature, "
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub const fn wrapping_mul(self, rhs: Self) -> Self {
|
||||
intrinsics::overflowing_mul(self, rhs)
|
||||
#[cfg(boostrap_stdarch_ignore_this)] {
|
||||
intrinsics::overflowing_mul(self, rhs)
|
||||
}
|
||||
|
||||
#[cfg(not(boostrap_stdarch_ignore_this))] {
|
||||
intrinsics::wrapping_mul(self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
doc_comment! {
|
||||
|
@ -46,20 +46,16 @@ pub use crate::option::Option::{self, Some, None};
|
||||
pub use crate::result::Result::{self, Ok, Err};
|
||||
|
||||
// Re-exported built-in macros
|
||||
#[cfg(not(bootstrap))]
|
||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||
#[doc(no_inline)]
|
||||
pub use crate::fmt::macros::Debug;
|
||||
#[cfg(not(bootstrap))]
|
||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||
#[doc(no_inline)]
|
||||
pub use crate::hash::macros::Hash;
|
||||
|
||||
#[cfg(not(bootstrap))]
|
||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||
#[doc(no_inline)]
|
||||
pub use crate::{
|
||||
__rust_unstable_column,
|
||||
asm,
|
||||
assert,
|
||||
cfg,
|
||||
@ -83,7 +79,6 @@ pub use crate::{
|
||||
trace_macros,
|
||||
};
|
||||
|
||||
#[cfg(not(bootstrap))]
|
||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||
#[allow(deprecated)]
|
||||
#[doc(no_inline)]
|
||||
|
@ -81,6 +81,34 @@ impl<T, E> Poll<Result<T, E>> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> Poll<Option<Result<T, E>>> {
|
||||
/// Changes the success value of this `Poll` with the closure provided.
|
||||
#[unstable(feature = "poll_map", issue = "63514")]
|
||||
pub fn map_ok<U, F>(self, f: F) -> Poll<Option<Result<U, E>>>
|
||||
where F: FnOnce(T) -> U
|
||||
{
|
||||
match self {
|
||||
Poll::Ready(Some(Ok(t))) => Poll::Ready(Some(Ok(f(t)))),
|
||||
Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(e))),
|
||||
Poll::Ready(None) => Poll::Ready(None),
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
|
||||
/// Changes the error value of this `Poll` with the closure provided.
|
||||
#[unstable(feature = "poll_map", issue = "63514")]
|
||||
pub fn map_err<U, F>(self, f: F) -> Poll<Option<Result<T, U>>>
|
||||
where F: FnOnce(E) -> U
|
||||
{
|
||||
match self {
|
||||
Poll::Ready(Some(Ok(t))) => Poll::Ready(Some(Ok(t))),
|
||||
Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(f(e)))),
|
||||
Poll::Ready(None) => Poll::Ready(None),
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "futures_api", since = "1.36.0")]
|
||||
impl<T> From<T> for Poll<T> {
|
||||
fn from(t: T) -> Poll<T> {
|
||||
|
@ -103,6 +103,22 @@ fn test_iterator_chain_nth() {
|
||||
assert_eq!(it.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_chain_nth_back() {
|
||||
let xs = [0, 1, 2, 3, 4, 5];
|
||||
let ys = [30, 40, 50, 60];
|
||||
let zs = [];
|
||||
let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60];
|
||||
for (i, x) in expected.iter().rev().enumerate() {
|
||||
assert_eq!(Some(x), xs.iter().chain(&ys).nth_back(i));
|
||||
}
|
||||
assert_eq!(zs.iter().chain(&xs).nth_back(0), Some(&5));
|
||||
|
||||
let mut it = xs.iter().chain(&zs);
|
||||
assert_eq!(it.nth_back(5), Some(&0));
|
||||
assert_eq!(it.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_chain_last() {
|
||||
let xs = [0, 1, 2, 3, 4, 5];
|
||||
@ -1136,6 +1152,18 @@ fn test_cycle() {
|
||||
assert_eq!(empty::<i32>().cycle().fold(0, |acc, x| acc + x), 0);
|
||||
|
||||
assert_eq!(once(1).cycle().skip(1).take(4).fold(0, |acc, x| acc + x), 4);
|
||||
|
||||
assert_eq!((0..10).cycle().take(5).sum::<i32>(), 10);
|
||||
assert_eq!((0..10).cycle().take(15).sum::<i32>(), 55);
|
||||
assert_eq!((0..10).cycle().take(25).sum::<i32>(), 100);
|
||||
|
||||
let mut iter = (0..10).cycle();
|
||||
iter.nth(14);
|
||||
assert_eq!(iter.take(8).sum::<i32>(), 38);
|
||||
|
||||
let mut iter = (0..10).cycle();
|
||||
iter.nth(9);
|
||||
assert_eq!(iter.take(3).sum::<i32>(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -136,7 +136,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
||||
}
|
||||
|
||||
PatKind::Struct(_, ref subpats, _) => {
|
||||
let pats_exit = self.pats_all(subpats.iter().map(|f| &f.node.pat), pred);
|
||||
let pats_exit = self.pats_all(subpats.iter().map(|f| &f.pat), pred);
|
||||
self.add_ast_node(pat.hir_id.local_id, &[pats_exit])
|
||||
}
|
||||
|
||||
|
@ -336,7 +336,7 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> {
|
||||
fn is_c_like_enum(item: &hir::Item) -> bool {
|
||||
if let hir::ItemKind::Enum(ref def, _) = item.node {
|
||||
for variant in &def.variants {
|
||||
match variant.node.data {
|
||||
match variant.data {
|
||||
hir::VariantData::Unit(..) => { /* continue */ }
|
||||
_ => { return false; }
|
||||
}
|
||||
|
@ -577,15 +577,15 @@ pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V,
|
||||
variant: &'v Variant,
|
||||
generics: &'v Generics,
|
||||
parent_item_id: HirId) {
|
||||
visitor.visit_ident(variant.node.ident);
|
||||
visitor.visit_id(variant.node.id);
|
||||
visitor.visit_variant_data(&variant.node.data,
|
||||
variant.node.ident.name,
|
||||
visitor.visit_ident(variant.ident);
|
||||
visitor.visit_id(variant.id);
|
||||
visitor.visit_variant_data(&variant.data,
|
||||
variant.ident.name,
|
||||
generics,
|
||||
parent_item_id,
|
||||
variant.span);
|
||||
walk_list!(visitor, visit_anon_const, &variant.node.disr_expr);
|
||||
walk_list!(visitor, visit_attribute, &variant.node.attrs);
|
||||
walk_list!(visitor, visit_anon_const, &variant.disr_expr);
|
||||
walk_list!(visitor, visit_attribute, &variant.attrs);
|
||||
}
|
||||
|
||||
pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
|
||||
@ -704,9 +704,9 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
|
||||
PatKind::Struct(ref qpath, ref fields, _) => {
|
||||
visitor.visit_qpath(qpath, pattern.hir_id, pattern.span);
|
||||
for field in fields {
|
||||
visitor.visit_id(field.node.hir_id);
|
||||
visitor.visit_ident(field.node.ident);
|
||||
visitor.visit_pat(&field.node.pat)
|
||||
visitor.visit_id(field.hir_id);
|
||||
visitor.visit_ident(field.ident);
|
||||
visitor.visit_pat(&field.pat)
|
||||
}
|
||||
}
|
||||
PatKind::Tuple(ref tuple_elements, _) => {
|
||||
|
@ -67,7 +67,7 @@ use syntax::errors;
|
||||
use syntax::ext::base::SpecialDerives;
|
||||
use syntax::ext::hygiene::ExpnId;
|
||||
use syntax::print::pprust;
|
||||
use syntax::source_map::{respan, ExpnInfo, ExpnKind, DesugaringKind, Spanned};
|
||||
use syntax::source_map::{respan, ExpnData, ExpnKind, DesugaringKind, Spanned};
|
||||
use syntax::symbol::{kw, sym, Symbol};
|
||||
use syntax::tokenstream::{TokenStream, TokenTree};
|
||||
use syntax::parse::token::{self, Token};
|
||||
@ -136,7 +136,10 @@ pub struct LoweringContext<'a> {
|
||||
/// When `is_collectin_in_band_lifetimes` is true, each lifetime is checked
|
||||
/// against this list to see if it is already in-scope, or if a definition
|
||||
/// needs to be created for it.
|
||||
in_scope_lifetimes: Vec<Ident>,
|
||||
///
|
||||
/// We always store a `modern()` version of the param-name in this
|
||||
/// vector.
|
||||
in_scope_lifetimes: Vec<ParamName>,
|
||||
|
||||
current_module: NodeId,
|
||||
|
||||
@ -337,49 +340,6 @@ enum AnonymousLifetimeMode {
|
||||
|
||||
/// Pass responsibility to `resolve_lifetime` code for all cases.
|
||||
PassThrough,
|
||||
|
||||
/// Used in the return types of `async fn` where there exists
|
||||
/// exactly one argument-position elided lifetime.
|
||||
///
|
||||
/// In `async fn`, we lower the arguments types using the `CreateParameter`
|
||||
/// mode, meaning that non-`dyn` elided lifetimes are assigned a fresh name.
|
||||
/// If any corresponding elided lifetimes appear in the output, we need to
|
||||
/// replace them with references to the fresh name assigned to the corresponding
|
||||
/// elided lifetime in the arguments.
|
||||
///
|
||||
/// For **Modern cases**, replace the anonymous parameter with a
|
||||
/// reference to a specific freshly-named lifetime that was
|
||||
/// introduced in argument
|
||||
///
|
||||
/// For **Dyn Bound** cases, pass responsibility to
|
||||
/// `resole_lifetime` code.
|
||||
Replace(LtReplacement),
|
||||
}
|
||||
|
||||
/// The type of elided lifetime replacement to perform on `async fn` return types.
|
||||
#[derive(Copy, Clone)]
|
||||
enum LtReplacement {
|
||||
/// Fresh name introduced by the single non-dyn elided lifetime
|
||||
/// in the arguments of the async fn.
|
||||
Some(ParamName),
|
||||
|
||||
/// There is no single non-dyn elided lifetime because no lifetimes
|
||||
/// appeared in the arguments.
|
||||
NoLifetimes,
|
||||
|
||||
/// There is no single non-dyn elided lifetime because multiple
|
||||
/// lifetimes appeared in the arguments.
|
||||
MultipleLifetimes,
|
||||
}
|
||||
|
||||
/// Calculates the `LtReplacement` to use for elided lifetimes in the return
|
||||
/// type based on the fresh elided lifetimes introduced in argument position.
|
||||
fn get_elided_lt_replacement(arg_position_lifetimes: &[(Span, ParamName)]) -> LtReplacement {
|
||||
match arg_position_lifetimes {
|
||||
[] => LtReplacement::NoLifetimes,
|
||||
[(_span, param)] => LtReplacement::Some(*param),
|
||||
_ => LtReplacement::MultipleLifetimes,
|
||||
}
|
||||
}
|
||||
|
||||
struct ImplTraitTypeIdVisitor<'a> { ids: &'a mut SmallVec<[NodeId; 1]> }
|
||||
@ -744,10 +704,9 @@ impl<'a> LoweringContext<'a> {
|
||||
span: Span,
|
||||
allow_internal_unstable: Option<Lrc<[Symbol]>>,
|
||||
) -> Span {
|
||||
span.fresh_expansion(ExpnId::root(), ExpnInfo {
|
||||
def_site: span,
|
||||
span.fresh_expansion(ExpnData {
|
||||
allow_internal_unstable,
|
||||
..ExpnInfo::default(ExpnKind::Desugaring(reason), span, self.sess.edition())
|
||||
..ExpnData::default(ExpnKind::Desugaring(reason), span, self.sess.edition())
|
||||
})
|
||||
}
|
||||
|
||||
@ -865,7 +824,7 @@ impl<'a> LoweringContext<'a> {
|
||||
return;
|
||||
}
|
||||
|
||||
if self.in_scope_lifetimes.contains(&ident.modern()) {
|
||||
if self.in_scope_lifetimes.contains(&ParamName::Plain(ident.modern())) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -899,7 +858,7 @@ impl<'a> LoweringContext<'a> {
|
||||
{
|
||||
let old_len = self.in_scope_lifetimes.len();
|
||||
let lt_def_names = params.iter().filter_map(|param| match param.kind {
|
||||
GenericParamKind::Lifetime { .. } => Some(param.ident.modern()),
|
||||
GenericParamKind::Lifetime { .. } => Some(ParamName::Plain(param.ident.modern())),
|
||||
_ => None,
|
||||
});
|
||||
self.in_scope_lifetimes.extend(lt_def_names);
|
||||
@ -1264,7 +1223,7 @@ impl<'a> LoweringContext<'a> {
|
||||
P(hir::Path {
|
||||
res,
|
||||
segments: hir_vec![hir::PathSegment::from_ident(
|
||||
Ident::with_empty_ctxt(kw::SelfUpper)
|
||||
Ident::with_dummy_span(kw::SelfUpper)
|
||||
)],
|
||||
span: t.span,
|
||||
}),
|
||||
@ -1598,7 +1557,7 @@ impl<'a> LoweringContext<'a> {
|
||||
|
||||
let (name, kind) = match name {
|
||||
hir::LifetimeName::Underscore => (
|
||||
hir::ParamName::Plain(Ident::with_empty_ctxt(kw::UnderscoreLifetime)),
|
||||
hir::ParamName::Plain(Ident::with_dummy_span(kw::UnderscoreLifetime)),
|
||||
hir::LifetimeParamKind::Elided,
|
||||
),
|
||||
hir::LifetimeName::Param(param_name) => (
|
||||
@ -1953,8 +1912,7 @@ impl<'a> LoweringContext<'a> {
|
||||
err.emit();
|
||||
}
|
||||
AnonymousLifetimeMode::PassThrough |
|
||||
AnonymousLifetimeMode::ReportError |
|
||||
AnonymousLifetimeMode::Replace(_) => {
|
||||
AnonymousLifetimeMode::ReportError => {
|
||||
self.sess.buffer_lint_with_diagnostic(
|
||||
ELIDED_LIFETIMES_IN_PATHS,
|
||||
CRATE_NODE_ID,
|
||||
@ -2043,7 +2001,7 @@ impl<'a> LoweringContext<'a> {
|
||||
bindings: hir_vec![
|
||||
hir::TypeBinding {
|
||||
hir_id: this.next_id(),
|
||||
ident: Ident::with_empty_ctxt(FN_OUTPUT_NAME),
|
||||
ident: Ident::with_dummy_span(FN_OUTPUT_NAME),
|
||||
kind: hir::TypeBindingKind::Equality {
|
||||
ty: output
|
||||
.as_ref()
|
||||
@ -2141,7 +2099,6 @@ impl<'a> LoweringContext<'a> {
|
||||
|
||||
// Remember how many lifetimes were already around so that we can
|
||||
// only look at the lifetime parameters introduced by the arguments.
|
||||
let lifetime_count_before_args = self.lifetimes_to_define.len();
|
||||
let inputs = self.with_anonymous_lifetime_mode(lt_mode, |this| {
|
||||
decl.inputs
|
||||
.iter()
|
||||
@ -2156,16 +2113,10 @@ impl<'a> LoweringContext<'a> {
|
||||
});
|
||||
|
||||
let output = if let Some(ret_id) = make_ret_async {
|
||||
// Calculate the `LtReplacement` to use for any return-position elided
|
||||
// lifetimes based on the elided lifetime parameters introduced in the args.
|
||||
let lt_replacement = get_elided_lt_replacement(
|
||||
&self.lifetimes_to_define[lifetime_count_before_args..]
|
||||
);
|
||||
self.lower_async_fn_ret_ty(
|
||||
&decl.output,
|
||||
in_band_ty_params.expect("`make_ret_async` but no `fn_def_id`").0,
|
||||
ret_id,
|
||||
lt_replacement,
|
||||
)
|
||||
} else {
|
||||
match decl.output {
|
||||
@ -2230,7 +2181,6 @@ impl<'a> LoweringContext<'a> {
|
||||
output: &FunctionRetTy,
|
||||
fn_def_id: DefId,
|
||||
opaque_ty_node_id: NodeId,
|
||||
elided_lt_replacement: LtReplacement,
|
||||
) -> hir::FunctionRetTy {
|
||||
let span = output.span();
|
||||
|
||||
@ -2248,9 +2198,65 @@ impl<'a> LoweringContext<'a> {
|
||||
|
||||
self.allocate_hir_id_counter(opaque_ty_node_id);
|
||||
|
||||
// When we create the opaque type for this async fn, it is going to have
|
||||
// to capture all the lifetimes involved in the signature (including in the
|
||||
// return type). This is done by introducing lifetime parameters for:
|
||||
//
|
||||
// - all the explicitly declared lifetimes from the impl and function itself;
|
||||
// - all the elided lifetimes in the fn arguments;
|
||||
// - all the elided lifetimes in the return type.
|
||||
//
|
||||
// So for example in this snippet:
|
||||
//
|
||||
// ```rust
|
||||
// impl<'a> Foo<'a> {
|
||||
// async fn bar<'b>(&self, x: &'b Vec<f64>, y: &str) -> &u32 {
|
||||
// // ^ '0 ^ '1 ^ '2
|
||||
// // elided lifetimes used below
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// we would create an opaque type like:
|
||||
//
|
||||
// ```
|
||||
// type Bar<'a, 'b, '0, '1, '2> = impl Future<Output = &'2 u32>;
|
||||
// ```
|
||||
//
|
||||
// and we would then desugar `bar` to the equivalent of:
|
||||
//
|
||||
// ```rust
|
||||
// impl<'a> Foo<'a> {
|
||||
// fn bar<'b, '0, '1>(&'0 self, x: &'b Vec<f64>, y: &'1 str) -> Bar<'a, 'b, '0, '1, '_>
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// Note that the final parameter to `Bar` is `'_`, not `'2` --
|
||||
// this is because the elided lifetimes from the return type
|
||||
// should be figured out using the ordinary elision rules, and
|
||||
// this desugaring achieves that.
|
||||
//
|
||||
// The variable `input_lifetimes_count` tracks the number of
|
||||
// lifetime parameters to the opaque type *not counting* those
|
||||
// lifetimes elided in the return type. This includes those
|
||||
// that are explicitly declared (`in_scope_lifetimes`) and
|
||||
// those elided lifetimes we found in the arguments (current
|
||||
// content of `lifetimes_to_define`). Next, we will process
|
||||
// the return type, which will cause `lifetimes_to_define` to
|
||||
// grow.
|
||||
let input_lifetimes_count = self.in_scope_lifetimes.len() + self.lifetimes_to_define.len();
|
||||
|
||||
let (opaque_ty_id, lifetime_params) = self.with_hir_id_owner(opaque_ty_node_id, |this| {
|
||||
// We have to be careful to get elision right here. The
|
||||
// idea is that we create a lifetime parameter for each
|
||||
// lifetime in the return type. So, given a return type
|
||||
// like `async fn foo(..) -> &[&u32]`, we lower to `impl
|
||||
// Future<Output = &'1 [ &'2 u32 ]>`.
|
||||
//
|
||||
// Then, we will create `fn foo(..) -> Foo<'_, '_>`, and
|
||||
// hence the elision takes place at the fn site.
|
||||
let future_bound = this.with_anonymous_lifetime_mode(
|
||||
AnonymousLifetimeMode::Replace(elided_lt_replacement),
|
||||
AnonymousLifetimeMode::CreateParameter,
|
||||
|this| this.lower_async_fn_output_type_to_future_bound(
|
||||
output,
|
||||
fn_def_id,
|
||||
@ -2267,10 +2273,14 @@ impl<'a> LoweringContext<'a> {
|
||||
let lifetime_params: Vec<(Span, ParamName)> =
|
||||
this.in_scope_lifetimes
|
||||
.iter().cloned()
|
||||
.map(|ident| (ident.span, ParamName::Plain(ident)))
|
||||
.map(|name| (name.ident().span, name))
|
||||
.chain(this.lifetimes_to_define.iter().cloned())
|
||||
.collect();
|
||||
|
||||
debug!("lower_async_fn_ret_ty: in_scope_lifetimes={:#?}", this.in_scope_lifetimes);
|
||||
debug!("lower_async_fn_ret_ty: lifetimes_to_define={:#?}", this.lifetimes_to_define);
|
||||
debug!("lower_async_fn_ret_ty: lifetime_params={:#?}", lifetime_params);
|
||||
|
||||
let generic_params =
|
||||
lifetime_params
|
||||
.iter().cloned()
|
||||
@ -2304,19 +2314,52 @@ impl<'a> LoweringContext<'a> {
|
||||
(opaque_ty_id, lifetime_params)
|
||||
});
|
||||
|
||||
let generic_args =
|
||||
lifetime_params
|
||||
.iter().cloned()
|
||||
.map(|(span, hir_name)| {
|
||||
GenericArg::Lifetime(hir::Lifetime {
|
||||
hir_id: self.next_id(),
|
||||
span,
|
||||
name: hir::LifetimeName::Param(hir_name),
|
||||
})
|
||||
// As documented above on the variable
|
||||
// `input_lifetimes_count`, we need to create the lifetime
|
||||
// arguments to our opaque type. Continuing with our example,
|
||||
// we're creating the type arguments for the return type:
|
||||
//
|
||||
// ```
|
||||
// Bar<'a, 'b, '0, '1, '_>
|
||||
// ```
|
||||
//
|
||||
// For the "input" lifetime parameters, we wish to create
|
||||
// references to the parameters themselves, including the
|
||||
// "implicit" ones created from parameter types (`'a`, `'b`,
|
||||
// '`0`, `'1`).
|
||||
//
|
||||
// For the "output" lifetime parameters, we just want to
|
||||
// generate `'_`.
|
||||
let mut generic_args: Vec<_> =
|
||||
lifetime_params[..input_lifetimes_count]
|
||||
.iter()
|
||||
.map(|&(span, hir_name)| {
|
||||
// Input lifetime like `'a` or `'1`:
|
||||
GenericArg::Lifetime(hir::Lifetime {
|
||||
hir_id: self.next_id(),
|
||||
span,
|
||||
name: hir::LifetimeName::Param(hir_name),
|
||||
})
|
||||
.collect();
|
||||
})
|
||||
.collect();
|
||||
generic_args.extend(
|
||||
lifetime_params[input_lifetimes_count..]
|
||||
.iter()
|
||||
.map(|&(span, _)| {
|
||||
// Output lifetime like `'_`.
|
||||
GenericArg::Lifetime(hir::Lifetime {
|
||||
hir_id: self.next_id(),
|
||||
span,
|
||||
name: hir::LifetimeName::Implicit,
|
||||
})
|
||||
})
|
||||
);
|
||||
|
||||
let opaque_ty_ref = hir::TyKind::Def(hir::ItemId { id: opaque_ty_id }, generic_args);
|
||||
// Create the `Foo<...>` refernece itself. Note that the `type
|
||||
// Foo = impl Trait` is, internally, created as a child of the
|
||||
// async fn, so the *type parameters* are inherited. It's
|
||||
// only the lifetime parameters that we must supply.
|
||||
let opaque_ty_ref = hir::TyKind::Def(hir::ItemId { id: opaque_ty_id }, generic_args.into());
|
||||
|
||||
hir::FunctionRetTy::Return(P(hir::Ty {
|
||||
node: opaque_ty_ref,
|
||||
@ -2350,7 +2393,7 @@ impl<'a> LoweringContext<'a> {
|
||||
let future_params = P(hir::GenericArgs {
|
||||
args: hir_vec![],
|
||||
bindings: hir_vec![hir::TypeBinding {
|
||||
ident: Ident::with_empty_ctxt(FN_OUTPUT_NAME),
|
||||
ident: Ident::with_dummy_span(FN_OUTPUT_NAME),
|
||||
kind: hir::TypeBindingKind::Equality {
|
||||
ty: output_ty,
|
||||
},
|
||||
@ -2412,11 +2455,6 @@ impl<'a> LoweringContext<'a> {
|
||||
}
|
||||
|
||||
AnonymousLifetimeMode::ReportError => self.new_error_lifetime(Some(l.id), span),
|
||||
|
||||
AnonymousLifetimeMode::Replace(replacement) => {
|
||||
let hir_id = self.lower_node_id(l.id);
|
||||
self.replace_elided_lifetime(hir_id, span, replacement)
|
||||
}
|
||||
},
|
||||
ident => {
|
||||
self.maybe_collect_in_band_lifetime(ident);
|
||||
@ -2439,39 +2477,6 @@ impl<'a> LoweringContext<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Replace a return-position elided lifetime with the elided lifetime
|
||||
/// from the arguments.
|
||||
fn replace_elided_lifetime(
|
||||
&mut self,
|
||||
hir_id: hir::HirId,
|
||||
span: Span,
|
||||
replacement: LtReplacement,
|
||||
) -> hir::Lifetime {
|
||||
let multiple_or_none = match replacement {
|
||||
LtReplacement::Some(name) => {
|
||||
return hir::Lifetime {
|
||||
hir_id,
|
||||
span,
|
||||
name: hir::LifetimeName::Param(name),
|
||||
};
|
||||
}
|
||||
LtReplacement::MultipleLifetimes => "multiple",
|
||||
LtReplacement::NoLifetimes => "none",
|
||||
};
|
||||
|
||||
let mut err = crate::middle::resolve_lifetime::report_missing_lifetime_specifiers(
|
||||
self.sess,
|
||||
span,
|
||||
1,
|
||||
);
|
||||
err.note(&format!(
|
||||
"return-position elided lifetimes require exactly one \
|
||||
input-position elided lifetime, found {}.", multiple_or_none));
|
||||
err.emit();
|
||||
|
||||
hir::Lifetime { hir_id, span, name: hir::LifetimeName::Error }
|
||||
}
|
||||
|
||||
fn lower_generic_params(
|
||||
&mut self,
|
||||
params: &[GenericParam],
|
||||
@ -2685,16 +2690,12 @@ impl<'a> LoweringContext<'a> {
|
||||
|
||||
let fs = fields
|
||||
.iter()
|
||||
.map(|f| {
|
||||
Spanned {
|
||||
span: f.span,
|
||||
node: hir::FieldPat {
|
||||
hir_id: self.next_id(),
|
||||
ident: f.node.ident,
|
||||
pat: self.lower_pat(&f.node.pat),
|
||||
is_shorthand: f.node.is_shorthand,
|
||||
},
|
||||
}
|
||||
.map(|f| hir::FieldPat {
|
||||
hir_id: self.next_id(),
|
||||
ident: f.ident,
|
||||
pat: self.lower_pat(&f.pat),
|
||||
is_shorthand: f.is_shorthand,
|
||||
span: f.span,
|
||||
})
|
||||
.collect();
|
||||
hir::PatKind::Struct(qpath, fs, etc)
|
||||
@ -3174,10 +3175,6 @@ impl<'a> LoweringContext<'a> {
|
||||
AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span),
|
||||
|
||||
AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span),
|
||||
|
||||
AnonymousLifetimeMode::Replace(replacement) => {
|
||||
self.new_replacement_lifetime(replacement, span)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3231,10 +3228,6 @@ impl<'a> LoweringContext<'a> {
|
||||
// This is the normal case.
|
||||
AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span),
|
||||
|
||||
AnonymousLifetimeMode::Replace(replacement) => {
|
||||
self.new_replacement_lifetime(replacement, span)
|
||||
}
|
||||
|
||||
AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span),
|
||||
}
|
||||
}
|
||||
@ -3266,25 +3259,11 @@ impl<'a> LoweringContext<'a> {
|
||||
|
||||
// This is the normal case.
|
||||
AnonymousLifetimeMode::PassThrough => {}
|
||||
|
||||
// We don't need to do any replacement here as this lifetime
|
||||
// doesn't refer to an elided lifetime elsewhere in the function
|
||||
// signature.
|
||||
AnonymousLifetimeMode::Replace(_) => {}
|
||||
}
|
||||
|
||||
self.new_implicit_lifetime(span)
|
||||
}
|
||||
|
||||
fn new_replacement_lifetime(
|
||||
&mut self,
|
||||
replacement: LtReplacement,
|
||||
span: Span,
|
||||
) -> hir::Lifetime {
|
||||
let hir_id = self.next_id();
|
||||
self.replace_elided_lifetime(hir_id, span, replacement)
|
||||
}
|
||||
|
||||
fn new_implicit_lifetime(&mut self, span: Span) -> hir::Lifetime {
|
||||
hir::Lifetime {
|
||||
hir_id: self.next_id(),
|
||||
|
@ -552,7 +552,7 @@ impl LoweringContext<'_> {
|
||||
|
||||
// let mut pinned = <expr>;
|
||||
let expr = P(self.lower_expr(expr));
|
||||
let pinned_ident = Ident::with_empty_ctxt(sym::pinned);
|
||||
let pinned_ident = Ident::with_dummy_span(sym::pinned);
|
||||
let (pinned_pat, pinned_pat_hid) = self.pat_ident_binding_mode(
|
||||
span,
|
||||
pinned_ident,
|
||||
@ -593,7 +593,7 @@ impl LoweringContext<'_> {
|
||||
let loop_node_id = self.sess.next_node_id();
|
||||
let loop_hir_id = self.lower_node_id(loop_node_id);
|
||||
let ready_arm = {
|
||||
let x_ident = Ident::with_empty_ctxt(sym::result);
|
||||
let x_ident = Ident::with_dummy_span(sym::result);
|
||||
let (x_pat, x_pat_hid) = self.pat_ident(span, x_ident);
|
||||
let x_expr = P(self.expr_ident(span, x_ident, x_pat_hid));
|
||||
let ready_pat = self.pat_std_enum(
|
||||
@ -677,6 +677,7 @@ impl LoweringContext<'_> {
|
||||
let fn_decl = self.lower_fn_decl(decl, None, false, None);
|
||||
|
||||
self.with_new_scopes(|this| {
|
||||
let prev = this.current_item;
|
||||
this.current_item = Some(fn_decl_span);
|
||||
let mut generator_kind = None;
|
||||
let body_id = this.lower_fn_body(decl, |this| {
|
||||
@ -690,8 +691,10 @@ impl LoweringContext<'_> {
|
||||
generator_kind,
|
||||
movability,
|
||||
);
|
||||
let capture_clause = this.lower_capture_clause(capture_clause);
|
||||
this.current_item = prev;
|
||||
hir::ExprKind::Closure(
|
||||
this.lower_capture_clause(capture_clause),
|
||||
capture_clause,
|
||||
fn_decl,
|
||||
body_id,
|
||||
fn_decl_span,
|
||||
@ -981,7 +984,6 @@ impl LoweringContext<'_> {
|
||||
volatile: asm.volatile,
|
||||
alignstack: asm.alignstack,
|
||||
dialect: asm.dialect,
|
||||
ctxt: asm.ctxt,
|
||||
};
|
||||
|
||||
let outputs = asm.outputs
|
||||
@ -1067,9 +1069,9 @@ impl LoweringContext<'_> {
|
||||
);
|
||||
head.span = desugared_span;
|
||||
|
||||
let iter = Ident::with_empty_ctxt(sym::iter);
|
||||
let iter = Ident::with_dummy_span(sym::iter);
|
||||
|
||||
let next_ident = Ident::with_empty_ctxt(sym::__next);
|
||||
let next_ident = Ident::with_dummy_span(sym::__next);
|
||||
let (next_pat, next_pat_hid) = self.pat_ident_binding_mode(
|
||||
desugared_span,
|
||||
next_ident,
|
||||
@ -1078,7 +1080,7 @@ impl LoweringContext<'_> {
|
||||
|
||||
// `::std::option::Option::Some(val) => __next = val`
|
||||
let pat_arm = {
|
||||
let val_ident = Ident::with_empty_ctxt(sym::val);
|
||||
let val_ident = Ident::with_dummy_span(sym::val);
|
||||
let (val_pat, val_pat_hid) = self.pat_ident(pat.span, val_ident);
|
||||
let val_expr = P(self.expr_ident(pat.span, val_ident, val_pat_hid));
|
||||
let next_expr = P(self.expr_ident(pat.span, next_ident, next_pat_hid));
|
||||
@ -1244,7 +1246,7 @@ impl LoweringContext<'_> {
|
||||
|
||||
// `Ok(val) => #[allow(unreachable_code)] val,`
|
||||
let ok_arm = {
|
||||
let val_ident = Ident::with_empty_ctxt(sym::val);
|
||||
let val_ident = Ident::with_dummy_span(sym::val);
|
||||
let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident);
|
||||
let val_expr = P(self.expr_ident_with_attrs(
|
||||
span,
|
||||
@ -1260,7 +1262,7 @@ impl LoweringContext<'_> {
|
||||
// `Err(err) => #[allow(unreachable_code)]
|
||||
// return Try::from_error(From::from(err)),`
|
||||
let err_arm = {
|
||||
let err_ident = Ident::with_empty_ctxt(sym::err);
|
||||
let err_ident = Ident::with_dummy_span(sym::err);
|
||||
let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident);
|
||||
let from_expr = {
|
||||
let from_path = &[sym::convert, sym::From, sym::from];
|
||||
|
@ -60,10 +60,12 @@ impl<'tcx, 'interner> Visitor<'tcx> for ItemLowerer<'tcx, 'interner> {
|
||||
fn visit_item(&mut self, item: &'tcx Item) {
|
||||
let mut item_hir_id = None;
|
||||
self.lctx.with_hir_id_owner(item.id, |lctx| {
|
||||
if let Some(hir_item) = lctx.lower_item(item) {
|
||||
item_hir_id = Some(hir_item.hir_id);
|
||||
lctx.insert_item(hir_item);
|
||||
}
|
||||
lctx.without_in_scope_lifetime_defs(|lctx| {
|
||||
if let Some(hir_item) = lctx.lower_item(item) {
|
||||
item_hir_id = Some(hir_item.hir_id);
|
||||
lctx.insert_item(hir_item);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
if let Some(hir_id) = item_hir_id {
|
||||
@ -123,7 +125,7 @@ impl LoweringContext<'_> {
|
||||
_ => &[],
|
||||
};
|
||||
let lt_def_names = parent_generics.iter().filter_map(|param| match param.kind {
|
||||
hir::GenericParamKind::Lifetime { .. } => Some(param.name.ident().modern()),
|
||||
hir::GenericParamKind::Lifetime { .. } => Some(param.name.modern()),
|
||||
_ => None,
|
||||
});
|
||||
self.in_scope_lifetimes.extend(lt_def_names);
|
||||
@ -134,6 +136,28 @@ impl LoweringContext<'_> {
|
||||
res
|
||||
}
|
||||
|
||||
// Clears (and restores) the `in_scope_lifetimes` field. Used when
|
||||
// visiting nested items, which never inherit in-scope lifetimes
|
||||
// from their surrounding environment.
|
||||
fn without_in_scope_lifetime_defs<T>(
|
||||
&mut self,
|
||||
f: impl FnOnce(&mut LoweringContext<'_>) -> T,
|
||||
) -> T {
|
||||
let old_in_scope_lifetimes = std::mem::replace(&mut self.in_scope_lifetimes, vec![]);
|
||||
|
||||
// this vector is only used when walking over impl headers,
|
||||
// input types, and the like, and should not be non-empty in
|
||||
// between items
|
||||
assert!(self.lifetimes_to_define.is_empty());
|
||||
|
||||
let res = f(self);
|
||||
|
||||
assert!(self.in_scope_lifetimes.is_empty());
|
||||
self.in_scope_lifetimes = old_in_scope_lifetimes;
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
pub(super) fn lower_mod(&mut self, m: &Mod) -> hir::Mod {
|
||||
hir::Mod {
|
||||
inner: m.inner,
|
||||
@ -726,21 +750,16 @@ impl LoweringContext<'_> {
|
||||
}
|
||||
|
||||
fn lower_global_asm(&mut self, ga: &GlobalAsm) -> P<hir::GlobalAsm> {
|
||||
P(hir::GlobalAsm {
|
||||
asm: ga.asm,
|
||||
ctxt: ga.ctxt,
|
||||
})
|
||||
P(hir::GlobalAsm { asm: ga.asm })
|
||||
}
|
||||
|
||||
fn lower_variant(&mut self, v: &Variant) -> hir::Variant {
|
||||
Spanned {
|
||||
node: hir::VariantKind {
|
||||
ident: v.node.ident,
|
||||
id: self.lower_node_id(v.node.id),
|
||||
attrs: self.lower_attrs(&v.node.attrs),
|
||||
data: self.lower_variant_data(&v.node.data),
|
||||
disr_expr: v.node.disr_expr.as_ref().map(|e| self.lower_anon_const(e)),
|
||||
},
|
||||
hir::Variant {
|
||||
attrs: self.lower_attrs(&v.attrs),
|
||||
data: self.lower_variant_data(&v.data),
|
||||
disr_expr: v.disr_expr.as_ref().map(|e| self.lower_anon_const(e)),
|
||||
id: self.lower_node_id(v.id),
|
||||
ident: v.ident,
|
||||
span: v.span,
|
||||
}
|
||||
}
|
||||
|
@ -544,11 +544,11 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
||||
}
|
||||
|
||||
fn visit_variant(&mut self, v: &'hir Variant, g: &'hir Generics, item_id: HirId) {
|
||||
self.insert(v.span, v.node.id, Node::Variant(v));
|
||||
self.with_parent(v.node.id, |this| {
|
||||
self.insert(v.span, v.id, Node::Variant(v));
|
||||
self.with_parent(v.id, |this| {
|
||||
// Register the constructor of this variant.
|
||||
if let Some(ctor_hir_id) = v.node.data.ctor_hir_id() {
|
||||
this.insert(v.span, ctor_hir_id, Node::Ctor(&v.node.data));
|
||||
if let Some(ctor_hir_id) = v.data.ctor_hir_id() {
|
||||
this.insert(v.span, ctor_hir_id, Node::Ctor(&v.data));
|
||||
}
|
||||
intravisit::walk_variant(this, v, g, item_id);
|
||||
});
|
||||
|
@ -155,11 +155,11 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
|
||||
}
|
||||
|
||||
fn visit_variant(&mut self, v: &'a Variant, g: &'a Generics, item_id: NodeId) {
|
||||
let def = self.create_def(v.node.id,
|
||||
DefPathData::TypeNs(v.node.ident.as_interned_str()),
|
||||
let def = self.create_def(v.id,
|
||||
DefPathData::TypeNs(v.ident.as_interned_str()),
|
||||
v.span);
|
||||
self.with_parent(def, |this| {
|
||||
if let Some(ctor_hir_id) = v.node.data.ctor_id() {
|
||||
if let Some(ctor_hir_id) = v.data.ctor_id() {
|
||||
this.create_def(ctor_hir_id, DefPathData::Ctor, v.span);
|
||||
}
|
||||
visit::walk_variant(this, v, g, item_id)
|
||||
|
@ -649,12 +649,34 @@ impl<'hir> Map<'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_const_scope(&self, hir_id: HirId) -> bool {
|
||||
self.walk_parent_nodes(hir_id, |node| match *node {
|
||||
Node::Item(Item { node: ItemKind::Const(_, _), .. }) => true,
|
||||
Node::Item(Item { node: ItemKind::Fn(_, header, _, _), .. }) => header.is_const(),
|
||||
/// Whether the expression pointed at by `hir_id` belongs to a `const` evaluation context.
|
||||
/// Used exclusively for diagnostics, to avoid suggestion function calls.
|
||||
pub fn is_const_context(&self, hir_id: HirId) -> bool {
|
||||
let parent_id = self.get_parent_item(hir_id);
|
||||
match self.get(parent_id) {
|
||||
Node::Item(&Item {
|
||||
node: ItemKind::Const(..),
|
||||
..
|
||||
})
|
||||
| Node::TraitItem(&TraitItem {
|
||||
node: TraitItemKind::Const(..),
|
||||
..
|
||||
})
|
||||
| Node::ImplItem(&ImplItem {
|
||||
node: ImplItemKind::Const(..),
|
||||
..
|
||||
})
|
||||
| Node::AnonConst(_)
|
||||
| Node::Item(&Item {
|
||||
node: ItemKind::Static(..),
|
||||
..
|
||||
}) => true,
|
||||
Node::Item(&Item {
|
||||
node: ItemKind::Fn(_, header, ..),
|
||||
..
|
||||
}) => header.constness == Constness::Const,
|
||||
_ => false,
|
||||
}, |_| false).map(|id| id != CRATE_HIR_ID).unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
/// If there is some error when walking the parents (e.g., a node does not
|
||||
@ -885,7 +907,7 @@ impl<'hir> Map<'hir> {
|
||||
_ => bug!("struct ID bound to non-struct {}", self.node_to_string(id))
|
||||
}
|
||||
}
|
||||
Some(Node::Variant(variant)) => &variant.node.data,
|
||||
Some(Node::Variant(variant)) => &variant.data,
|
||||
Some(Node::Ctor(data)) => data,
|
||||
_ => bug!("expected struct or variant, found {}", self.node_to_string(id))
|
||||
}
|
||||
@ -918,7 +940,7 @@ impl<'hir> Map<'hir> {
|
||||
Node::ForeignItem(fi) => fi.ident.name,
|
||||
Node::ImplItem(ii) => ii.ident.name,
|
||||
Node::TraitItem(ti) => ti.ident.name,
|
||||
Node::Variant(v) => v.node.ident.name,
|
||||
Node::Variant(v) => v.ident.name,
|
||||
Node::Field(f) => f.ident.name,
|
||||
Node::Lifetime(lt) => lt.name.ident().name,
|
||||
Node::GenericParam(param) => param.name.ident().name,
|
||||
@ -939,7 +961,7 @@ impl<'hir> Map<'hir> {
|
||||
Some(Node::ForeignItem(fi)) => Some(&fi.attrs[..]),
|
||||
Some(Node::TraitItem(ref ti)) => Some(&ti.attrs[..]),
|
||||
Some(Node::ImplItem(ref ii)) => Some(&ii.attrs[..]),
|
||||
Some(Node::Variant(ref v)) => Some(&v.node.attrs[..]),
|
||||
Some(Node::Variant(ref v)) => Some(&v.attrs[..]),
|
||||
Some(Node::Field(ref f)) => Some(&f.attrs[..]),
|
||||
Some(Node::Expr(ref e)) => Some(&*e.attrs),
|
||||
Some(Node::Stmt(ref s)) => Some(s.node.attrs()),
|
||||
@ -1133,7 +1155,7 @@ impl<T:Named> Named for Spanned<T> { fn name(&self) -> Name { self.node.name() }
|
||||
|
||||
impl Named for Item { fn name(&self) -> Name { self.ident.name } }
|
||||
impl Named for ForeignItem { fn name(&self) -> Name { self.ident.name } }
|
||||
impl Named for VariantKind { fn name(&self) -> Name { self.ident.name } }
|
||||
impl Named for Variant { fn name(&self) -> Name { self.ident.name } }
|
||||
impl Named for StructField { fn name(&self) -> Name { self.ident.name } }
|
||||
impl Named for TraitItem { fn name(&self) -> Name { self.ident.name } }
|
||||
impl Named for ImplItem { fn name(&self) -> Name { self.ident.name } }
|
||||
@ -1310,7 +1332,7 @@ fn hir_id_to_string(map: &Map<'_>, id: HirId, include_id: bool) -> String {
|
||||
}
|
||||
Some(Node::Variant(ref variant)) => {
|
||||
format!("variant {} in {}{}",
|
||||
variant.node.ident,
|
||||
variant.ident,
|
||||
path_str(), id_str)
|
||||
}
|
||||
Some(Node::Field(ref field)) => {
|
||||
|
@ -23,7 +23,6 @@ use rustc_target::spec::abi::Abi;
|
||||
use syntax::ast::{self, CrateSugar, Ident, Name, NodeId, AsmDialect};
|
||||
use syntax::ast::{Attribute, Label, LitKind, StrStyle, FloatTy, IntTy, UintTy};
|
||||
use syntax::attr::{InlineAttr, OptimizeAttr};
|
||||
use syntax::ext::hygiene::SyntaxContext;
|
||||
use syntax::symbol::{Symbol, kw};
|
||||
use syntax::tokenstream::TokenStream;
|
||||
use syntax::util::parser::ExprPrecedence;
|
||||
@ -202,7 +201,7 @@ impl ParamName {
|
||||
match *self {
|
||||
ParamName::Plain(ident) => ident,
|
||||
ParamName::Fresh(_) |
|
||||
ParamName::Error => Ident::with_empty_ctxt(kw::UnderscoreLifetime),
|
||||
ParamName::Error => Ident::with_dummy_span(kw::UnderscoreLifetime),
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,8 +236,8 @@ impl LifetimeName {
|
||||
pub fn ident(&self) -> Ident {
|
||||
match *self {
|
||||
LifetimeName::Implicit | LifetimeName::Error => Ident::invalid(),
|
||||
LifetimeName::Underscore => Ident::with_empty_ctxt(kw::UnderscoreLifetime),
|
||||
LifetimeName::Static => Ident::with_empty_ctxt(kw::StaticLifetime),
|
||||
LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime),
|
||||
LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime),
|
||||
LifetimeName::Param(param_name) => param_name.ident(),
|
||||
}
|
||||
}
|
||||
@ -877,7 +876,7 @@ impl Pat {
|
||||
match self.node {
|
||||
PatKind::Binding(.., Some(ref p)) => p.walk_(it),
|
||||
PatKind::Struct(_, ref fields, _) => {
|
||||
fields.iter().all(|field| field.node.pat.walk_(it))
|
||||
fields.iter().all(|field| field.pat.walk_(it))
|
||||
}
|
||||
PatKind::TupleStruct(_, ref s, _) | PatKind::Tuple(ref s, _) => {
|
||||
s.iter().all(|p| p.walk_(it))
|
||||
@ -923,6 +922,7 @@ pub struct FieldPat {
|
||||
/// The pattern the field is destructured to.
|
||||
pub pat: P<Pat>,
|
||||
pub is_shorthand: bool,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
/// Explicit binding annotations given in the HIR for a binding. Note
|
||||
@ -968,7 +968,7 @@ pub enum PatKind {
|
||||
|
||||
/// A struct or struct variant pattern (e.g., `Variant {x, y, ..}`).
|
||||
/// The `bool` is `true` in the presence of a `..`.
|
||||
Struct(QPath, HirVec<Spanned<FieldPat>>, bool),
|
||||
Struct(QPath, HirVec<FieldPat>, bool),
|
||||
|
||||
/// A tuple struct/variant pattern `Variant(x, y, .., z)`.
|
||||
/// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
|
||||
@ -1541,7 +1541,7 @@ pub enum ExprKind {
|
||||
Match(P<Expr>, HirVec<Arm>, MatchSource),
|
||||
/// A closure (e.g., `move |a, b, c| {a + b + c}`).
|
||||
///
|
||||
/// The final span is the span of the argument block `|...|`.
|
||||
/// The `Span` is the argument block `|...|`.
|
||||
///
|
||||
/// This may also be a generator literal or an `async block` as indicated by the
|
||||
/// `Option<GeneratorMovability>`.
|
||||
@ -2003,8 +2003,6 @@ pub struct InlineAsm {
|
||||
pub volatile: bool,
|
||||
pub alignstack: bool,
|
||||
pub dialect: AsmDialect,
|
||||
#[stable_hasher(ignore)] // This is used for error reporting
|
||||
pub ctxt: SyntaxContext,
|
||||
}
|
||||
|
||||
/// Represents an argument in a function header.
|
||||
@ -2183,8 +2181,6 @@ pub struct ForeignMod {
|
||||
#[derive(RustcEncodable, RustcDecodable, Debug, HashStable)]
|
||||
pub struct GlobalAsm {
|
||||
pub asm: Symbol,
|
||||
#[stable_hasher(ignore)] // This is used for error reporting
|
||||
pub ctxt: SyntaxContext,
|
||||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable, Debug, HashStable)]
|
||||
@ -2193,7 +2189,7 @@ pub struct EnumDef {
|
||||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable, Debug, HashStable)]
|
||||
pub struct VariantKind {
|
||||
pub struct Variant {
|
||||
/// Name of the variant.
|
||||
#[stable_hasher(project(name))]
|
||||
pub ident: Ident,
|
||||
@ -2205,10 +2201,10 @@ pub struct VariantKind {
|
||||
pub data: VariantData,
|
||||
/// Explicit discriminant (e.g., `Foo = 1`).
|
||||
pub disr_expr: Option<AnonConst>,
|
||||
/// Span
|
||||
pub span: Span
|
||||
}
|
||||
|
||||
pub type Variant = Spanned<VariantKind>;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable)]
|
||||
pub enum UseKind {
|
||||
/// One import, e.g., `use foo::bar` or `use foo::bar as baz`.
|
||||
|
@ -737,7 +737,7 @@ impl<'a> State<'a> {
|
||||
for v in variants {
|
||||
self.space_if_not_bol();
|
||||
self.maybe_print_comment(v.span.lo());
|
||||
self.print_outer_attributes(&v.node.attrs);
|
||||
self.print_outer_attributes(&v.attrs);
|
||||
self.ibox(INDENT_UNIT);
|
||||
self.print_variant(v);
|
||||
self.s.word(",");
|
||||
@ -829,8 +829,8 @@ impl<'a> State<'a> {
|
||||
pub fn print_variant(&mut self, v: &hir::Variant) {
|
||||
self.head("");
|
||||
let generics = hir::Generics::empty();
|
||||
self.print_struct(&v.node.data, &generics, v.node.ident.name, v.span, false);
|
||||
if let Some(ref d) = v.node.disr_expr {
|
||||
self.print_struct(&v.data, &generics, v.ident.name, v.span, false);
|
||||
if let Some(ref d) = v.disr_expr {
|
||||
self.s.space();
|
||||
self.word_space("=");
|
||||
self.print_anon_const(d);
|
||||
@ -1457,7 +1457,7 @@ impl<'a> State<'a> {
|
||||
}
|
||||
|
||||
pub fn print_name(&mut self, name: ast::Name) {
|
||||
self.print_ident(ast::Ident::with_empty_ctxt(name))
|
||||
self.print_ident(ast::Ident::with_dummy_span(name))
|
||||
}
|
||||
|
||||
pub fn print_for_decl(&mut self, loc: &hir::Local, coll: &hir::Expr) {
|
||||
@ -1670,14 +1670,14 @@ impl<'a> State<'a> {
|
||||
&fields[..],
|
||||
|s, f| {
|
||||
s.cbox(INDENT_UNIT);
|
||||
if !f.node.is_shorthand {
|
||||
s.print_ident(f.node.ident);
|
||||
if !f.is_shorthand {
|
||||
s.print_ident(f.ident);
|
||||
s.word_nbsp(":");
|
||||
}
|
||||
s.print_pat(&f.node.pat);
|
||||
s.print_pat(&f.pat);
|
||||
s.end()
|
||||
},
|
||||
|f| f.node.pat.span);
|
||||
|f| f.pat.span);
|
||||
if etc {
|
||||
if !fields.is_empty() {
|
||||
self.word_space(",");
|
||||
|
@ -350,7 +350,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for Span {
|
||||
let line_col_len = col | line | len;
|
||||
std_hash::Hash::hash(&line_col_len, hasher);
|
||||
|
||||
if span.ctxt == SyntaxContext::empty() {
|
||||
if span.ctxt == SyntaxContext::root() {
|
||||
TAG_NO_EXPANSION.hash_stable(hcx, hasher);
|
||||
} else {
|
||||
TAG_EXPANSION.hash_stable(hcx, hasher);
|
||||
@ -370,7 +370,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for Span {
|
||||
}
|
||||
|
||||
let mut hasher = StableHasher::new();
|
||||
expn_id.expn_info().hash_stable(hcx, &mut hasher);
|
||||
expn_id.expn_data().hash_stable(hcx, &mut hasher);
|
||||
let sub_hash: Fingerprint = hasher.finish();
|
||||
let sub_hash = sub_hash.to_smaller_hash();
|
||||
cache.borrow_mut().insert(expn_id, sub_hash);
|
||||
|
@ -153,8 +153,6 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::Ty {
|
||||
}
|
||||
}
|
||||
|
||||
impl_stable_hash_for_spanned!(hir::FieldPat);
|
||||
|
||||
impl_stable_hash_for_spanned!(hir::BinOpKind);
|
||||
|
||||
impl_stable_hash_for!(struct hir::Stmt {
|
||||
@ -187,8 +185,6 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::Expr {
|
||||
|
||||
impl_stable_hash_for_spanned!(usize);
|
||||
|
||||
impl_stable_hash_for_spanned!(ast::Ident);
|
||||
|
||||
impl_stable_hash_for!(struct ast::Ident {
|
||||
name,
|
||||
span,
|
||||
@ -304,7 +300,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::Mod {
|
||||
}
|
||||
}
|
||||
|
||||
impl_stable_hash_for_spanned!(hir::VariantKind);
|
||||
impl_stable_hash_for_spanned!(hir::Variant);
|
||||
|
||||
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for hir::Item {
|
||||
|
@ -397,9 +397,10 @@ impl_stable_hash_for!(enum ::syntax_pos::hygiene::Transparency {
|
||||
Opaque,
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnInfo {
|
||||
call_site,
|
||||
impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnData {
|
||||
kind,
|
||||
parent -> _,
|
||||
call_site,
|
||||
def_site,
|
||||
default_transparency,
|
||||
allow_internal_unstable,
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::hir::def::Namespace;
|
||||
use crate::hir::{self, Local, Pat, Body, HirId};
|
||||
use crate::hir::{self, Body, FunctionRetTy, Expr, ExprKind, HirId, Local, Pat};
|
||||
use crate::hir::intravisit::{self, Visitor, NestedVisitorMap};
|
||||
use crate::infer::InferCtxt;
|
||||
use crate::infer::type_variable::TypeVariableOriginKind;
|
||||
@ -7,7 +7,7 @@ use crate::ty::{self, Ty, Infer, TyVar};
|
||||
use crate::ty::print::Print;
|
||||
use syntax::source_map::DesugaringKind;
|
||||
use syntax_pos::Span;
|
||||
use errors::DiagnosticBuilder;
|
||||
use errors::{Applicability, DiagnosticBuilder};
|
||||
|
||||
struct FindLocalByTypeVisitor<'a, 'tcx> {
|
||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||
@ -16,9 +16,26 @@ struct FindLocalByTypeVisitor<'a, 'tcx> {
|
||||
found_local_pattern: Option<&'tcx Pat>,
|
||||
found_arg_pattern: Option<&'tcx Pat>,
|
||||
found_ty: Option<Ty<'tcx>>,
|
||||
found_closure: Option<&'tcx ExprKind>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> {
|
||||
fn new(
|
||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||
target_ty: Ty<'tcx>,
|
||||
hir_map: &'a hir::map::Map<'tcx>,
|
||||
) -> Self {
|
||||
Self {
|
||||
infcx,
|
||||
target_ty,
|
||||
hir_map,
|
||||
found_local_pattern: None,
|
||||
found_arg_pattern: None,
|
||||
found_ty: None,
|
||||
found_closure: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn node_matches_type(&mut self, hir_id: HirId) -> Option<Ty<'tcx>> {
|
||||
let ty_opt = self.infcx.in_progress_tables.and_then(|tables| {
|
||||
tables.borrow().node_type_opt(hir_id)
|
||||
@ -72,6 +89,60 @@ impl<'a, 'tcx> Visitor<'tcx> for FindLocalByTypeVisitor<'a, 'tcx> {
|
||||
}
|
||||
intravisit::walk_body(self, body);
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr) {
|
||||
if let (ExprKind::Closure(_, _fn_decl, _id, _sp, _), Some(_)) = (
|
||||
&expr.node,
|
||||
self.node_matches_type(expr.hir_id),
|
||||
) {
|
||||
self.found_closure = Some(&expr.node);
|
||||
}
|
||||
intravisit::walk_expr(self, expr);
|
||||
}
|
||||
}
|
||||
|
||||
/// Suggest giving an appropriate return type to a closure expression.
|
||||
fn closure_return_type_suggestion(
|
||||
span: Span,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
output: &FunctionRetTy,
|
||||
body: &Body,
|
||||
name: &str,
|
||||
ret: &str,
|
||||
) {
|
||||
let (arrow, post) = match output {
|
||||
FunctionRetTy::DefaultReturn(_) => ("-> ", " "),
|
||||
_ => ("", ""),
|
||||
};
|
||||
let suggestion = match body.value.node {
|
||||
ExprKind::Block(..) => {
|
||||
vec![(output.span(), format!("{}{}{}", arrow, ret, post))]
|
||||
}
|
||||
_ => {
|
||||
vec![
|
||||
(output.span(), format!("{}{}{}{{ ", arrow, ret, post)),
|
||||
(body.value.span.shrink_to_hi(), " }".to_string()),
|
||||
]
|
||||
}
|
||||
};
|
||||
err.multipart_suggestion(
|
||||
"give this closure an explicit return type without `_` placeholders",
|
||||
suggestion,
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
err.span_label(span, InferCtxt::missing_type_msg(&name));
|
||||
}
|
||||
|
||||
/// Given a closure signature, return a `String` containing a list of all its argument types.
|
||||
fn closure_args(fn_sig: &ty::PolyFnSig<'_>) -> String {
|
||||
fn_sig.inputs()
|
||||
.skip_binder()
|
||||
.iter()
|
||||
.next()
|
||||
.map(|args| args.tuple_fields()
|
||||
.map(|arg| arg.to_string())
|
||||
.collect::<Vec<_>>().join(", "))
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
@ -106,16 +177,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
let ty = self.resolve_vars_if_possible(&ty);
|
||||
let name = self.extract_type_name(&ty, None);
|
||||
|
||||
let mut err_span = span;
|
||||
|
||||
let mut local_visitor = FindLocalByTypeVisitor {
|
||||
infcx: &self,
|
||||
target_ty: ty,
|
||||
hir_map: &self.tcx.hir(),
|
||||
found_local_pattern: None,
|
||||
found_arg_pattern: None,
|
||||
found_ty: None,
|
||||
};
|
||||
let mut local_visitor = FindLocalByTypeVisitor::new(&self, ty, &self.tcx.hir());
|
||||
let ty_to_string = |ty: Ty<'tcx>| -> String {
|
||||
let mut s = String::new();
|
||||
let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
|
||||
@ -136,6 +198,31 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
let expr = self.tcx.hir().expect_expr(body_id.hir_id);
|
||||
local_visitor.visit_expr(expr);
|
||||
}
|
||||
let err_span = if let Some(pattern) = local_visitor.found_arg_pattern {
|
||||
pattern.span
|
||||
} else {
|
||||
span
|
||||
};
|
||||
|
||||
let is_named_and_not_impl_trait = |ty: Ty<'_>| {
|
||||
&ty.to_string() != "_" &&
|
||||
// FIXME: Remove this check after `impl_trait_in_bindings` is stabilized. #63527
|
||||
(!ty.is_impl_trait() || self.tcx.features().impl_trait_in_bindings)
|
||||
};
|
||||
|
||||
let ty_msg = match local_visitor.found_ty {
|
||||
Some(ty::TyS { sty: ty::Closure(def_id, substs), .. }) => {
|
||||
let fn_sig = substs.closure_sig(*def_id, self.tcx);
|
||||
let args = closure_args(&fn_sig);
|
||||
let ret = fn_sig.output().skip_binder().to_string();
|
||||
format!(" for the closure `fn({}) -> {}`", args, ret)
|
||||
}
|
||||
Some(ty) if is_named_and_not_impl_trait(ty) => {
|
||||
let ty = ty_to_string(ty);
|
||||
format!(" for `{}`", ty)
|
||||
}
|
||||
_ => String::new(),
|
||||
};
|
||||
|
||||
// When `name` corresponds to a type argument, show the path of the full type we're
|
||||
// trying to infer. In the following example, `ty_msg` contains
|
||||
@ -150,27 +237,58 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
// | consider giving `b` the explicit type `std::result::Result<i32, E>`, where
|
||||
// | the type parameter `E` is specified
|
||||
// ```
|
||||
let (ty_msg, suffix) = match &local_visitor.found_ty {
|
||||
Some(ty) if &ty.to_string() != "_" && name == "_" => {
|
||||
let ty = ty_to_string(ty);
|
||||
(format!(" for `{}`", ty),
|
||||
format!("the explicit type `{}`, with the type parameters specified", ty))
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
err_span,
|
||||
E0282,
|
||||
"type annotations needed{}",
|
||||
ty_msg,
|
||||
);
|
||||
|
||||
let suffix = match local_visitor.found_ty {
|
||||
Some(ty::TyS { sty: ty::Closure(def_id, substs), .. }) => {
|
||||
let fn_sig = substs.closure_sig(*def_id, self.tcx);
|
||||
let ret = fn_sig.output().skip_binder().to_string();
|
||||
|
||||
if let Some(ExprKind::Closure(_, decl, body_id, ..)) = local_visitor.found_closure {
|
||||
if let Some(body) = self.tcx.hir().krate().bodies.get(body_id) {
|
||||
closure_return_type_suggestion(
|
||||
span,
|
||||
&mut err,
|
||||
&decl.output,
|
||||
&body,
|
||||
&name,
|
||||
&ret,
|
||||
);
|
||||
// We don't want to give the other suggestions when the problem is the
|
||||
// closure return type.
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// This shouldn't be reachable, but just in case we leave a reasonable fallback.
|
||||
let args = closure_args(&fn_sig);
|
||||
// This suggestion is incomplete, as the user will get further type inference
|
||||
// errors due to the `_` placeholders and the introduction of `Box`, but it does
|
||||
// nudge them in the right direction.
|
||||
format!("a boxed closure type like `Box<dyn Fn({}) -> {}>`", args, ret)
|
||||
}
|
||||
Some(ty) if &ty.to_string() != "_" && ty.to_string() != name => {
|
||||
Some(ty) if is_named_and_not_impl_trait(ty) && name == "_" => {
|
||||
let ty = ty_to_string(ty);
|
||||
(format!(" for `{}`", ty),
|
||||
format!(
|
||||
"the explicit type `{}`, where the type parameter `{}` is specified",
|
||||
format!("the explicit type `{}`, with the type parameters specified", ty)
|
||||
}
|
||||
Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != name => {
|
||||
let ty = ty_to_string(ty);
|
||||
format!(
|
||||
"the explicit type `{}`, where the type parameter `{}` is specified",
|
||||
ty,
|
||||
name,
|
||||
))
|
||||
)
|
||||
}
|
||||
_ => (String::new(), "a type".to_owned()),
|
||||
_ => "a type".to_string(),
|
||||
};
|
||||
let mut labels = vec![(span, InferCtxt::missing_type_msg(&name))];
|
||||
|
||||
if let Some(pattern) = local_visitor.found_arg_pattern {
|
||||
err_span = pattern.span;
|
||||
// We don't want to show the default label for closures.
|
||||
//
|
||||
// So, before clearing, the output would look something like this:
|
||||
@ -187,39 +305,31 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
// ^ consider giving this closure parameter the type `[_; 0]`
|
||||
// with the type parameter `_` specified
|
||||
// ```
|
||||
labels.clear();
|
||||
labels.push((
|
||||
err.span_label(
|
||||
pattern.span,
|
||||
format!("consider giving this closure parameter {}", suffix),
|
||||
));
|
||||
);
|
||||
} else if let Some(pattern) = local_visitor.found_local_pattern {
|
||||
if let Some(simple_ident) = pattern.simple_ident() {
|
||||
let msg = if let Some(simple_ident) = pattern.simple_ident() {
|
||||
match pattern.span.desugaring_kind() {
|
||||
None => labels.push((
|
||||
pattern.span,
|
||||
format!("consider giving `{}` {}", simple_ident, suffix),
|
||||
)),
|
||||
Some(DesugaringKind::ForLoop) => labels.push((
|
||||
pattern.span,
|
||||
"the element type for this iterator is not specified".to_owned(),
|
||||
)),
|
||||
_ => {}
|
||||
None => {
|
||||
format!("consider giving `{}` {}", simple_ident, suffix)
|
||||
}
|
||||
Some(DesugaringKind::ForLoop) => {
|
||||
"the element type for this iterator is not specified".to_string()
|
||||
}
|
||||
_ => format!("this needs {}", suffix),
|
||||
}
|
||||
} else {
|
||||
labels.push((pattern.span, format!("consider giving this pattern {}", suffix)));
|
||||
}
|
||||
};
|
||||
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
err_span,
|
||||
E0282,
|
||||
"type annotations needed{}",
|
||||
ty_msg,
|
||||
);
|
||||
|
||||
for (target_span, label_message) in labels {
|
||||
err.span_label(target_span, label_message);
|
||||
format!("consider giving this pattern {}", suffix)
|
||||
};
|
||||
err.span_label(pattern.span, msg);
|
||||
}
|
||||
if !err.span.span_labels().iter().any(|span_label| {
|
||||
span_label.label.is_some() && span_label.span == span
|
||||
}) && local_visitor.found_arg_pattern.is_none()
|
||||
{ // Avoid multiple labels pointing at `span`.
|
||||
err.span_label(span, InferCtxt::missing_type_msg(&name));
|
||||
}
|
||||
|
||||
err
|
||||
|
@ -1060,7 +1060,7 @@ for LateContextAndPass<'a, 'tcx, T> {
|
||||
v: &'tcx hir::Variant,
|
||||
g: &'tcx hir::Generics,
|
||||
item_id: hir::HirId) {
|
||||
self.with_lint_attrs(v.node.id, &v.node.attrs, |cx| {
|
||||
self.with_lint_attrs(v.id, &v.attrs, |cx| {
|
||||
lint_callback!(cx, check_variant, v, g);
|
||||
hir_visit::walk_variant(cx, v, g, item_id);
|
||||
lint_callback!(cx, check_variant_post, v, g);
|
||||
@ -1236,7 +1236,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
|
||||
}
|
||||
|
||||
fn visit_variant(&mut self, v: &'a ast::Variant, g: &'a ast::Generics, item_id: ast::NodeId) {
|
||||
self.with_lint_attrs(item_id, &v.node.attrs, |cx| {
|
||||
self.with_lint_attrs(item_id, &v.attrs, |cx| {
|
||||
run_early_pass!(cx, check_variant, v, g);
|
||||
ast_visit::walk_variant(cx, v, g, item_id);
|
||||
run_early_pass!(cx, check_variant_post, v, g);
|
||||
@ -1345,7 +1345,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
|
||||
// part of `walk_mac`, and (b) we should be calling
|
||||
// `visit_path`, *but* that would require a `NodeId`, and I
|
||||
// want to get #53686 fixed quickly. -nmatsakis
|
||||
ast_visit::walk_path(self, &mac.node.path);
|
||||
ast_visit::walk_path(self, &mac.path);
|
||||
|
||||
run_early_pass!(self, check_mac, mac);
|
||||
}
|
||||
@ -1355,7 +1355,7 @@ struct LateLintPassObjects<'a> {
|
||||
lints: &'a mut [LateLintPassObject],
|
||||
}
|
||||
|
||||
#[cfg_attr(not(bootstrap), allow(rustc::lint_pass_impl_without_macro))]
|
||||
#[allow(rustc::lint_pass_impl_without_macro)]
|
||||
impl LintPass for LateLintPassObjects<'_> {
|
||||
fn name(&self) -> &'static str {
|
||||
panic!()
|
||||
@ -1525,7 +1525,7 @@ struct EarlyLintPassObjects<'a> {
|
||||
lints: &'a mut [EarlyLintPassObject],
|
||||
}
|
||||
|
||||
#[cfg_attr(not(bootstrap), allow(rustc::lint_pass_impl_without_macro))]
|
||||
#[allow(rustc::lint_pass_impl_without_macro)]
|
||||
impl LintPass for EarlyLintPassObjects<'_> {
|
||||
fn name(&self) -> &'static str {
|
||||
panic!()
|
||||
|
@ -9,7 +9,6 @@ use errors::Applicability;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use syntax::ast::{Ident, Item, ItemKind};
|
||||
use syntax::symbol::{sym, Symbol};
|
||||
use syntax_pos::ExpnInfo;
|
||||
|
||||
declare_tool_lint! {
|
||||
pub rustc::DEFAULT_HASH_TYPES,
|
||||
@ -23,7 +22,7 @@ pub struct DefaultHashTypes {
|
||||
|
||||
impl DefaultHashTypes {
|
||||
// we are allowed to use `HashMap` and `HashSet` as identifiers for implementing the lint itself
|
||||
#[cfg_attr(not(bootstrap), allow(rustc::default_hash_types))]
|
||||
#[allow(rustc::default_hash_types)]
|
||||
pub fn new() -> Self {
|
||||
let mut map = FxHashMap::default();
|
||||
map.insert(sym::HashMap, sym::FxHashMap);
|
||||
@ -108,7 +107,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TyTyKind {
|
||||
.help("try using `Ty` instead")
|
||||
.emit();
|
||||
} else {
|
||||
if ty.span.ctxt().outer_expn_info().is_some() {
|
||||
if ty.span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
if let Some(t) = is_ty_or_ty_ctxt(cx, ty) {
|
||||
@ -228,30 +227,20 @@ impl EarlyLintPass for LintPassImpl {
|
||||
if let ItemKind::Impl(_, _, _, _, Some(lint_pass), _, _) = &item.node {
|
||||
if let Some(last) = lint_pass.path.segments.last() {
|
||||
if last.ident.name == sym::LintPass {
|
||||
match &lint_pass.path.span.ctxt().outer_expn_info() {
|
||||
Some(info) if is_lint_pass_expansion(info) => {}
|
||||
_ => {
|
||||
cx.struct_span_lint(
|
||||
LINT_PASS_IMPL_WITHOUT_MACRO,
|
||||
lint_pass.path.span,
|
||||
"implementing `LintPass` by hand",
|
||||
)
|
||||
.help("try using `declare_lint_pass!` or `impl_lint_pass!` instead")
|
||||
.emit();
|
||||
}
|
||||
let expn_data = lint_pass.path.span.ctxt().outer_expn_data();
|
||||
let call_site = expn_data.call_site;
|
||||
if expn_data.kind.descr() != sym::impl_lint_pass &&
|
||||
call_site.ctxt().outer_expn_data().kind.descr() != sym::declare_lint_pass {
|
||||
cx.struct_span_lint(
|
||||
LINT_PASS_IMPL_WITHOUT_MACRO,
|
||||
lint_pass.path.span,
|
||||
"implementing `LintPass` by hand",
|
||||
)
|
||||
.help("try using `declare_lint_pass!` or `impl_lint_pass!` instead")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_lint_pass_expansion(expn_info: &ExpnInfo) -> bool {
|
||||
if expn_info.kind.descr() == sym::impl_lint_pass {
|
||||
true
|
||||
} else if let Some(info) = expn_info.call_site.ctxt().outer_expn_info() {
|
||||
info.kind.descr() == sym::declare_lint_pass
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
@ -846,7 +846,7 @@ impl intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> {
|
||||
v: &'tcx hir::Variant,
|
||||
g: &'tcx hir::Generics,
|
||||
item_id: hir::HirId) {
|
||||
self.with_lint_attrs(v.node.id, &v.node.attrs, |builder| {
|
||||
self.with_lint_attrs(v.id, &v.attrs, |builder| {
|
||||
intravisit::walk_variant(builder, v, g, item_id);
|
||||
})
|
||||
}
|
||||
@ -885,21 +885,16 @@ pub fn provide(providers: &mut Providers<'_>) {
|
||||
/// This is used to test whether a lint should not even begin to figure out whether it should
|
||||
/// be reported on the current node.
|
||||
pub fn in_external_macro(sess: &Session, span: Span) -> bool {
|
||||
let info = match span.ctxt().outer_expn_info() {
|
||||
Some(info) => info,
|
||||
// no ExpnInfo means this span doesn't come from a macro
|
||||
None => return false,
|
||||
};
|
||||
|
||||
match info.kind {
|
||||
let expn_data = span.ctxt().outer_expn_data();
|
||||
match expn_data.kind {
|
||||
ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) => false,
|
||||
ExpnKind::Desugaring(_) => true, // well, it's "external"
|
||||
ExpnKind::Macro(MacroKind::Bang, _) => {
|
||||
if info.def_site.is_dummy() {
|
||||
if expn_data.def_site.is_dummy() {
|
||||
// dummy span for the def_site means it's an external macro
|
||||
return true;
|
||||
}
|
||||
match sess.source_map().span_to_snippet(info.def_site) {
|
||||
match sess.source_map().span_to_snippet(expn_data.def_site) {
|
||||
Ok(code) => !code.starts_with("macro_rules"),
|
||||
// no snippet = external macro or compiler-builtin expansion
|
||||
Err(_) => true,
|
||||
@ -911,10 +906,8 @@ pub fn in_external_macro(sess: &Session, span: Span) -> bool {
|
||||
|
||||
/// Returns whether `span` originates in a derive macro's expansion
|
||||
pub fn in_derive_expansion(span: Span) -> bool {
|
||||
if let Some(info) = span.ctxt().outer_expn_info() {
|
||||
if let ExpnKind::Macro(MacroKind::Derive, _) = info.kind {
|
||||
return true;
|
||||
}
|
||||
if let ExpnKind::Macro(MacroKind::Derive, _) = span.ctxt().outer_expn_data().kind {
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
@ -178,8 +178,7 @@ pub trait MetadataLoader {
|
||||
-> Result<MetadataRef, String>;
|
||||
}
|
||||
|
||||
/// A store of Rust crates, through with their metadata
|
||||
/// can be accessed.
|
||||
/// A store of Rust crates, through which their metadata can be accessed.
|
||||
///
|
||||
/// Note that this trait should probably not be expanding today. All new
|
||||
/// functionality should be driven through queries instead!
|
||||
|
@ -17,8 +17,7 @@ use crate::util::nodemap::FxHashSet;
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
|
||||
use syntax::{ast, source_map};
|
||||
use syntax::attr;
|
||||
use syntax::{ast, attr};
|
||||
use syntax::symbol::sym;
|
||||
use syntax_pos;
|
||||
|
||||
@ -119,17 +118,16 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_field_pattern_match(&mut self, lhs: &hir::Pat, res: Res,
|
||||
pats: &[source_map::Spanned<hir::FieldPat>]) {
|
||||
fn handle_field_pattern_match(&mut self, lhs: &hir::Pat, res: Res, pats: &[hir::FieldPat]) {
|
||||
let variant = match self.tables.node_type(lhs.hir_id).sty {
|
||||
ty::Adt(adt, _) => adt.variant_of_res(res),
|
||||
_ => span_bug!(lhs.span, "non-ADT in struct pattern")
|
||||
};
|
||||
for pat in pats {
|
||||
if let PatKind::Wild = pat.node.pat.node {
|
||||
if let PatKind::Wild = pat.pat.node {
|
||||
continue;
|
||||
}
|
||||
let index = self.tcx.field_index(pat.node.hir_id, self.tables);
|
||||
let index = self.tcx.field_index(pat.hir_id, self.tables);
|
||||
self.insert_def_id(variant.fields[index].did);
|
||||
}
|
||||
}
|
||||
@ -366,12 +364,12 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> {
|
||||
match item.node {
|
||||
hir::ItemKind::Enum(ref enum_def, _) => {
|
||||
if allow_dead_code {
|
||||
self.worklist.extend(enum_def.variants.iter().map(|variant| variant.node.id));
|
||||
self.worklist.extend(enum_def.variants.iter().map(|variant| variant.id));
|
||||
}
|
||||
|
||||
for variant in &enum_def.variants {
|
||||
if let Some(ctor_hir_id) = variant.node.data.ctor_hir_id() {
|
||||
self.struct_constructors.insert(ctor_hir_id, variant.node.id);
|
||||
if let Some(ctor_hir_id) = variant.data.ctor_hir_id() {
|
||||
self.struct_constructors.insert(ctor_hir_id, variant.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -497,7 +495,7 @@ impl DeadVisitor<'tcx> {
|
||||
&& !has_allow_dead_code_or_lang_attr(self.tcx, field.hir_id, &field.attrs)
|
||||
}
|
||||
|
||||
fn should_warn_about_variant(&mut self, variant: &hir::VariantKind) -> bool {
|
||||
fn should_warn_about_variant(&mut self, variant: &hir::Variant) -> bool {
|
||||
!self.symbol_is_live(variant.id)
|
||||
&& !has_allow_dead_code_or_lang_attr(self.tcx,
|
||||
variant.id,
|
||||
@ -596,8 +594,8 @@ impl Visitor<'tcx> for DeadVisitor<'tcx> {
|
||||
variant: &'tcx hir::Variant,
|
||||
g: &'tcx hir::Generics,
|
||||
id: hir::HirId) {
|
||||
if self.should_warn_about_variant(&variant.node) {
|
||||
self.warn_dead_code(variant.node.id, variant.span, variant.node.ident.name,
|
||||
if self.should_warn_about_variant(&variant) {
|
||||
self.warn_dead_code(variant.id, variant.span, variant.ident.name,
|
||||
"variant", "constructed");
|
||||
} else {
|
||||
intravisit::walk_variant(self, variant, g, id);
|
||||
|
@ -418,8 +418,8 @@ fn add_from_pat<'tcx>(ir: &mut IrMaps<'tcx>, pat: &P<hir::Pat>) {
|
||||
}
|
||||
Struct(_, ref fields, _) => {
|
||||
for field in fields {
|
||||
if field.node.is_shorthand {
|
||||
shorthand_field_ids.insert(field.node.pat.hir_id);
|
||||
if field.is_shorthand {
|
||||
shorthand_field_ids.insert(field.pat.hir_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1282,11 +1282,11 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
|
||||
};
|
||||
|
||||
for fp in field_pats {
|
||||
let field_ty = self.pat_ty_adjusted(&fp.node.pat)?; // see (*2)
|
||||
let f_index = self.tcx.field_index(fp.node.hir_id, self.tables);
|
||||
let field_ty = self.pat_ty_adjusted(&fp.pat)?; // see (*2)
|
||||
let f_index = self.tcx.field_index(fp.hir_id, self.tables);
|
||||
let cmt_field = Rc::new(self.cat_field(pat, cmt.clone(), f_index,
|
||||
fp.node.ident, field_ty));
|
||||
self.cat_pattern_(cmt_field, &fp.node.pat, op)?;
|
||||
fp.ident, field_ty));
|
||||
self.cat_pattern_(cmt_field, &fp.pat, op)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,9 @@ fn item_might_be_inlined(tcx: TyCtxt<'tcx>, item: &hir::Item, attrs: CodegenFnAt
|
||||
}
|
||||
|
||||
match item.node {
|
||||
hir::ItemKind::Fn(_, header, ..) if header.is_const() => {
|
||||
return true;
|
||||
}
|
||||
hir::ItemKind::Impl(..) |
|
||||
hir::ItemKind::Fn(..) => {
|
||||
let generics = tcx.generics_of(tcx.hir().local_def_id(item.hir_id));
|
||||
@ -52,6 +55,11 @@ fn method_might_be_inlined(
|
||||
if codegen_fn_attrs.requests_inline() || generics.requires_monomorphization(tcx) {
|
||||
return true
|
||||
}
|
||||
if let hir::ImplItemKind::Method(method_sig, _) = &impl_item.node {
|
||||
if method_sig.header.is_const() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if let Some(impl_hir_id) = tcx.hir().as_local_hir_id(impl_src) {
|
||||
match tcx.hir().find(impl_hir_id) {
|
||||
Some(Node::Item(item)) =>
|
||||
|
@ -1207,7 +1207,7 @@ fn resolve_local<'tcx>(
|
||||
PatKind::Binding(hir::BindingAnnotation::RefMut, ..) => true,
|
||||
|
||||
PatKind::Struct(_, ref field_pats, _) => {
|
||||
field_pats.iter().any(|fp| is_binding_pat(&fp.node.pat))
|
||||
field_pats.iter().any(|fp| is_binding_pat(&fp.pat))
|
||||
}
|
||||
|
||||
PatKind::Slice(ref pats1, ref pats2, ref pats3) => {
|
||||
|
@ -290,10 +290,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
|
||||
}
|
||||
|
||||
fn visit_variant(&mut self, var: &'tcx Variant, g: &'tcx Generics, item_id: HirId) {
|
||||
self.annotate(var.node.id, &var.node.attrs, var.span, AnnotationKind::Required,
|
||||
self.annotate(var.id, &var.attrs, var.span, AnnotationKind::Required,
|
||||
|v| {
|
||||
if let Some(ctor_hir_id) = var.node.data.ctor_hir_id() {
|
||||
v.annotate(ctor_hir_id, &var.node.attrs, var.span, AnnotationKind::Required,
|
||||
if let Some(ctor_hir_id) = var.data.ctor_hir_id() {
|
||||
v.annotate(ctor_hir_id, &var.attrs, var.span, AnnotationKind::Required,
|
||||
|_| {});
|
||||
}
|
||||
|
||||
@ -372,7 +372,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'a, 'tcx> {
|
||||
}
|
||||
|
||||
fn visit_variant(&mut self, var: &'tcx Variant, g: &'tcx Generics, item_id: HirId) {
|
||||
self.check_missing_stability(var.node.id, var.span, "variant");
|
||||
self.check_missing_stability(var.id, var.span, "variant");
|
||||
intravisit::walk_variant(self, var, g, item_id);
|
||||
}
|
||||
|
||||
|
@ -189,8 +189,11 @@ impl<'tcx, Tag> Pointer<Tag> {
|
||||
Pointer { alloc_id: self.alloc_id, offset: self.offset, tag: () }
|
||||
}
|
||||
|
||||
/// Test if the pointer is "inbounds" of an allocation of the given size.
|
||||
/// A pointer is "inbounds" even if its offset is equal to the size; this is
|
||||
/// a "one-past-the-end" pointer.
|
||||
#[inline(always)]
|
||||
pub fn check_in_alloc(
|
||||
pub fn check_inbounds_alloc(
|
||||
self,
|
||||
allocation_size: Size,
|
||||
msg: CheckInAllocMsg,
|
||||
|
@ -2197,7 +2197,6 @@ impl<'tcx> Operand<'tcx> {
|
||||
let ty = tcx.type_of(def_id).subst(tcx, substs);
|
||||
Operand::Constant(box Constant {
|
||||
span,
|
||||
ty,
|
||||
user_ty: None,
|
||||
literal: ty::Const::zero_sized(tcx, ty),
|
||||
})
|
||||
@ -2476,7 +2475,6 @@ impl<'tcx> Debug for Rvalue<'tcx> {
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)]
|
||||
pub struct Constant<'tcx> {
|
||||
pub span: Span,
|
||||
pub ty: Ty<'tcx>,
|
||||
|
||||
/// Optional user-given type: for something like
|
||||
/// `collect::<Vec<_>>`, this would be present and would
|
||||
@ -3385,12 +3383,11 @@ impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
|
||||
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
|
||||
Constant {
|
||||
span: self.span.clone(),
|
||||
ty: self.ty.fold_with(folder),
|
||||
user_ty: self.user_ty.fold_with(folder),
|
||||
literal: self.literal.fold_with(folder),
|
||||
}
|
||||
}
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
self.ty.visit_with(visitor) || self.literal.visit_with(visitor)
|
||||
self.literal.visit_with(visitor)
|
||||
}
|
||||
}
|
||||
|
@ -252,7 +252,7 @@ impl<'tcx> Operand<'tcx> {
|
||||
match self {
|
||||
&Operand::Copy(ref l) |
|
||||
&Operand::Move(ref l) => l.ty(local_decls, tcx).ty,
|
||||
&Operand::Constant(ref c) => c.ty,
|
||||
&Operand::Constant(ref c) => c.literal.ty,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -782,13 +782,11 @@ macro_rules! make_mir_visitor {
|
||||
location: Location) {
|
||||
let Constant {
|
||||
span,
|
||||
ty,
|
||||
user_ty,
|
||||
literal,
|
||||
} = constant;
|
||||
|
||||
self.visit_span(span);
|
||||
self.visit_ty(ty, TyContext::Location(location));
|
||||
drop(user_ty); // no visit method for this
|
||||
self.visit_const(literal, location);
|
||||
}
|
||||
|
@ -395,7 +395,7 @@ top_level_options!(
|
||||
output_types: OutputTypes [TRACKED],
|
||||
search_paths: Vec<SearchPath> [UNTRACKED],
|
||||
libs: Vec<(String, Option<String>, Option<cstore::NativeLibraryKind>)> [TRACKED],
|
||||
maybe_sysroot: Option<PathBuf> [TRACKED],
|
||||
maybe_sysroot: Option<PathBuf> [UNTRACKED],
|
||||
|
||||
target_triple: TargetTriple [TRACKED],
|
||||
|
||||
|
@ -36,7 +36,7 @@ use errors::{Applicability, DiagnosticBuilder};
|
||||
use std::fmt;
|
||||
use syntax::ast;
|
||||
use syntax::symbol::sym;
|
||||
use syntax_pos::{DUMMY_SP, Span, ExpnInfo, ExpnKind};
|
||||
use syntax_pos::{DUMMY_SP, Span, ExpnKind};
|
||||
|
||||
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
pub fn report_fulfillment_errors(&self,
|
||||
@ -61,9 +61,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
// We want to ignore desugarings here: spans are equivalent even
|
||||
// if one is the result of a desugaring and the other is not.
|
||||
let mut span = error.obligation.cause.span;
|
||||
if let Some(ExpnInfo { kind: ExpnKind::Desugaring(_), def_site, .. })
|
||||
= span.ctxt().outer_expn_info() {
|
||||
span = def_site;
|
||||
let expn_data = span.ctxt().outer_expn_data();
|
||||
if let ExpnKind::Desugaring(_) = expn_data.kind {
|
||||
span = expn_data.call_site;
|
||||
}
|
||||
|
||||
error_map.entry(span).or_default().push(
|
||||
|
@ -1417,7 +1417,7 @@ fn confirm_callable_candidate<'cx, 'tcx>(
|
||||
projection_ty: ty::ProjectionTy::from_ref_and_name(
|
||||
tcx,
|
||||
trait_ref,
|
||||
Ident::with_empty_ctxt(FN_OUTPUT_NAME),
|
||||
Ident::with_dummy_span(FN_OUTPUT_NAME),
|
||||
),
|
||||
ty: ret_type
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user