+++ /dev/null
----
-name: Diagnostic issue
-about: Create a bug report or feature request for a change to `rustc`'s error output
-labels: A-diagnostics, T-compiler
----
-<!--
-Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
-along with any information you feel relevant to replicating the bug.
-
-If you cannot produce a minimal reproduction case (something that would work in
-isolation), please provide the steps or even link to a repository that causes
-the problematic output to occur.
--->
-
-Given the following code: <!-- Please provide a link to play.rust-lang.org -->
-
-```rust
-<code>
-```
-
-The current output is:
-
-```
-<rustc output>
-```
-
-<!-- The following is not always necessary. -->
-Ideally the output should look like:
-
-```
-<proposed output>
-```
-
-<!--
-If the problem is not self-explanatory, please provide a rationale for the
-change.
--->
-
-<!--
-If dramatically different output is caused by small changes, consider also
-adding them here.
-
-If you're using the stable version of the compiler, you should also check if the
-bug also exists in the beta or nightly versions. The output might also be
-different depending on the Edition.
--->
--- /dev/null
+name: Diagnostic issue
+description: Create a bug report or feature request for a change to `rustc`'s error output
+labels: ["A-diagnostics", "T-compiler"]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ Thank you for filing a diagnostics bug report! 🐛
+
+ Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug.
+
+ If you cannot produce a minimal reproduction case (something that would work in isolation), please provide the steps or even link to a repository that causes the problematic output to occur.
+ - type: textarea
+ id: code
+ attributes:
+ label: Code
+ description: Please provide code that can reproduce the problem
+ placeholder: code
+ render: Rust
+ validations:
+ required: true
+ - type: textarea
+ id: output
+ attributes:
+ label: Current output
+ description: Please provide the `rustc` output you see
+ placeholder: rustc output
+ render: Shell
+ validations:
+ required: true
+ - type: textarea
+ id: desired-output
+ attributes:
+ label: Desired output
+ description: Please provide what the output *should* be
+ placeholder: proposed output
+ render: Shell
+ validations:
+ required: false
+ - type: textarea
+ id: rationale
+ attributes:
+ label: Rationale and extra context
+ description: If the problem is not self-explanatory, please provide a rationale for the change.
+ validations:
+ required: false
+ - type: textarea
+ id: other-output
+ attributes:
+ label: Other cases
+ description: If dramatically different output is caused by small changes, consider also adding them here.
+ render: Rust
+ validations:
+ required: false
+ - type: markdown
+ attributes:
+ value: |
+ If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. The output might also be different depending on the Edition.
+ - type: textarea
+ id: extra
+ attributes:
+ label: Anything else?
+ description: If you have more details you want to give us to reproduce this issue, please add it here
+ validations:
+ required: false
\ No newline at end of file
+++ /dev/null
----
-name: Documentation problem
-about: Create a report for a documentation problem.
-labels: A-docs
----
-<!--
-
-Thank you for finding a documentation problem! 📚
-
-Documentation problems might be grammatical issues, typos, or unclear wording, please provide details regarding the documentation including where it is present.
-
-Note: If your issue is for one of these, please use their dedicated issue tracker instead:
-
-- The Rust Book: https://github.com/rust-lang/book/issues
-- Rust by Example: https://github.com/rust-lang/rust-by-example/issues
-- The Edition Guide: https://github.com/rust-lang/edition-guide/issues
-- The Cargo Book: https://github.com/rust-lang/cargo/issues
-- The Clippy Book: https://github.com/rust-lang/rust-clippy/issues
-- The Reference: https://github.com/rust-lang/reference/issues
-- The Rustonomicon: https://github.com/rust-lang/nomicon/issues
-- The Embedded Book: https://github.com/rust-embedded/book/issues
-
-All other documentation issues should be filed here.
-
-Or, if you find an issue related to rustdoc (e.g. doctest, rustdoc UI), please use the bug report or blank issue template instead.
-
--->
-
-### Location
-
-### Summary
--- /dev/null
+name: Documentation problem
+description: Create a report for a documentation problem.
+labels: ["A-docs"]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ Thank you for finding a documentation problem! 📚
+
+ Documentation problems might be grammatical issues, typos, or unclear wording, please provide details regarding the documentation including where it is present.
+
+ Note: If your issue is for one of these, please use their dedicated issue tracker instead:
+ - [The Rust Book](https://github.com/rust-lang/book/issues)
+ - [Rust by Example](https://github.com/rust-lang/rust-by-example/issues)
+ - [The Edition Guide](https://github.com/rust-lang/edition-guide/issues)
+ - [The Cargo Book](https://github.com/rust-lang/cargo/issues)
+ - [The Clippy Book](https://github.com/rust-lang/rust-clippy/issues)
+ - [The Reference](https://github.com/rust-lang/reference/issues)
+ - [The Rustonomicon](https://github.com/rust-lang/nomicon/issues)
+ - [The Embedded Book](https://github.com/rust-embedded/book/issues)
+
+ All other documentation issues should be filed here.
+
+ Or, if you find an issue related to rustdoc (e.g. doctest, rustdoc UI), please use the bug report or blank issue template instead.
+
+ - type: textarea
+ id: location
+ attributes:
+ label: Location
+ validations:
+ required: true
+
+ - type: textarea
+ id: summary
+ attributes:
+ label: Summary
+ validations:
+ required: true
\ No newline at end of file
+++ /dev/null
----
-name: Internal Compiler Error
-about: Create a report for an internal compiler error in rustc.
-labels: C-bug, I-ICE, T-compiler
----
-<!--
-Thank you for finding an Internal Compiler Error! 🧊 If possible, try to provide
-a minimal verifiable example. You can read "Rust Bug Minimization Patterns" for
-how to create smaller examples.
-
-http://blog.pnkfx.org/blog/2019/11/18/rust-bug-minimization-patterns/
-
--->
-
-### Code
-
-```Rust
-<code>
-```
-
-
-### Meta
-<!--
-If you're using the stable version of the compiler, you should also check if the
-bug also exists in the beta or nightly versions.
--->
-
-`rustc --version --verbose`:
-```
-<version>
-```
-
-### Error output
-
-```
-<output>
-```
-
-<!--
-Include a backtrace in the code block by setting `RUST_BACKTRACE=1` in your
-environment. E.g. `RUST_BACKTRACE=1 cargo build`.
--->
-<details><summary><strong>Backtrace</strong></summary>
-<p>
-
-```
-<backtrace>
-```
-
-</p>
-</details>
-
--- /dev/null
+name: Internal Compiler Error
+description: Create a report for an internal compiler error in `rustc`
+labels: ["C-bug", "I-ICE", "T-compiler"]
+title: "[ICE]: "
+body:
+ - type: markdown
+ attributes:
+ value: |
+ Thank you for finding an Internal Compiler Error! 🧊
+
+ If possible, try to provide a minimal verifiable example.
+
+ You can read "[Rust Bug Minimization Patterns](http://blog.pnkfx.org/blog/2019/11/18/rust-bug-minimization-patterns/)" for how to create smaller examples.
+
+ - type: textarea
+ id: code
+ attributes:
+ label: Code
+ description: Please provide code or a link to a repository that can reproduce the problem
+ placeholder: code
+ render: Rust
+ validations:
+ required: false
+
+ - type: checkboxes
+ attributes:
+ label: Affected release channels
+ description: If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions
+ options:
+ - label: Previous Stable
+ required: false
+ - label: Current Stable
+ required: false
+ - label: Current Beta
+ required: false
+ - label: Current Nightly
+ required: false
+
+ - type: textarea
+ id: version
+ attributes:
+ label: Rust Version
+ description: Please provide the `rustc` version, `rustc --version --verbose`
+ placeholder: |
+ $ rustc --version --verbose
+ rustc 1.XX.Y (SHORTHASH DATE)
+ binary: rustc
+ commit-hash: LONGHASHVALUE
+ commit-date: DATE
+ host: PLATFORMTRIPLE
+ release: 1.XX.Y
+ LLVM version: XX.YY.ZZ
+ render: Shell
+ validations:
+ required: true
+
+ - type: textarea
+ id: output
+ attributes:
+ label: Current error output
+ description: Please provide the `rustc` output you see
+ placeholder: output
+ render: Shell
+ validations:
+ required: false
+
+ - type: textarea
+ id: backtrace
+ attributes:
+ label: Backtrace
+ description: Include a backtrace in the code block by setting `RUST_BACKTRACE=full` in your environment, e.g. `RUST_BACKTRACE=full cargo build`
+ render: Shell
+ validations:
+ required: true
+
+ - type: textarea
+ id: extra
+ attributes:
+ label: Anything else?
+ description: If you have more details you want to give us to reproduce this issue, please add it here
+ validations:
+ required: false
\ No newline at end of file
"version_check",
]
+[[package]]
+name = "ahash"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf6ccdb167abbf410dcb915cabd428929d7f6a04980b54a11f26a39f1c7f7107"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "version_check",
+]
+
[[package]]
name = "aho-corasick"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "276881980556fdadeb88aa1ffc667e4d2e8fe72531dfabcb7a82bb3c9ea9ba31"
dependencies = [
- "object",
+ "object 0.29.0",
]
[[package]]
"cfg-if",
"libc",
"miniz_oxide",
- "object",
+ "object 0.29.0",
"rustc-demangle",
]
"cargo-test-macro",
"cargo-test-support",
"cargo-util",
- "clap 4.0.15",
+ "clap 4.0.32",
"crates-io",
"curl",
"curl-sys",
[[package]]
name = "clap"
-version = "4.0.15"
+version = "4.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6bf8832993da70a4c6d13c581f4463c2bdda27b9bf1c5498dc4365543abe6d6f"
+checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39"
dependencies = [
- "atty",
"bitflags",
- "clap_derive 4.0.13",
+ "clap_derive 4.0.21",
"clap_lex 0.3.0",
+ "is-terminal",
"once_cell",
"strsim",
"termcolor",
+ "terminal_size",
]
[[package]]
name = "clap_complete"
-version = "3.1.1"
+version = "4.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df6f3613c0a3cddfd78b41b10203eb322cb29b600cbdf808a7d3db95691b8e25"
+checksum = "10861370d2ba66b0f5989f83ebf35db6421713fd92351790e7fdd6c36774c56b"
dependencies = [
- "clap 3.2.20",
+ "clap 4.0.32",
]
[[package]]
[[package]]
name = "clap_derive"
-version = "4.0.13"
+version = "4.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c42f169caba89a7d512b5418b09864543eeb4d497416c917d7137863bd2076ad"
+checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014"
dependencies = [
"heck",
"proc-macro-error",
[[package]]
name = "gimli"
-version = "0.26.1"
+version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
+checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
dependencies = [
"compiler_builtins",
"fallible-iterator",
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
dependencies = [
- "ahash",
+ "ahash 0.7.4",
"compiler_builtins",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
]
+[[package]]
+name = "hashbrown"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33ff8ae62cd3a9102e5637afc8452c55acf3844001bd5374e0b0bd7b6616c038"
+dependencies = [
+ "ahash 0.8.2",
+]
+
[[package]]
name = "heck"
version = "0.4.0"
[[package]]
name = "indexmap"
-version = "1.9.1"
+version = "1.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
+checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
dependencies = [
"autocfg",
- "hashbrown",
+ "hashbrown 0.12.3",
"rustc-rayon",
"serde",
]
version = "0.1.0"
dependencies = [
"anyhow",
- "clap 4.0.15",
+ "clap 4.0.32",
"fs-err",
"rustdoc-json-types",
"serde",
[[package]]
name = "mdbook"
-version = "0.4.21"
+version = "0.4.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23f3e133c6d515528745ffd3b9f0c7d975ae039f0b6abb099f2168daa2afb4f9"
+checksum = "d1ed28d5903dde77bd5182645078a37ee57014cac6ccb2d54e1d6496386648e4"
dependencies = [
"ammonia",
"anyhow",
"chrono",
- "clap 3.2.20",
+ "clap 4.0.32",
"clap_complete",
"elasticlunr-rs",
- "env_logger 0.9.0",
+ "env_logger 0.10.0",
"handlebars 4.3.3",
- "lazy_static",
"log",
"memchr",
+ "once_cell",
"opener",
"pulldown-cmark 0.9.2",
"regex",
checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
dependencies = [
"compiler_builtins",
+ "memchr",
+ "rustc-std-workspace-alloc",
+ "rustc-std-workspace-core",
+]
+
+[[package]]
+name = "object"
+version = "0.30.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d864c91689fdc196779b98dba0aceac6118594c2df6ee5d943eb6a8df4d107a"
+dependencies = [
"crc32fast",
"flate2",
- "hashbrown",
+ "hashbrown 0.13.1",
"indexmap",
"memchr",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
]
[[package]]
[[package]]
name = "pest"
-version = "2.3.0"
+version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b0560d531d1febc25a3c9398a62a71256c0178f2e3443baedd9ad4bb8c9deb4"
+checksum = "0f6e86fb9e7026527a0d46bc308b841d73170ef8f443e1807f6ef88526a816d4"
dependencies = [
"thiserror",
"ucd-trie",
[[package]]
name = "pest_derive"
-version = "2.3.0"
+version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "905708f7f674518498c1f8d644481440f476d39ca6ecae83319bba7c6c12da91"
+checksum = "96504449aa860c8dcde14f9fba5c58dc6658688ca1fe363589d6327b8662c603"
dependencies = [
"pest",
"pest_generator",
[[package]]
name = "pest_generator"
-version = "2.3.0"
+version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5803d8284a629cc999094ecd630f55e91b561a1d1ba75e233b00ae13b91a69ad"
+checksum = "798e0220d1111ae63d66cb66a5dcb3fc2d986d520b98e49e1852bfdb11d7c5e7"
dependencies = [
"pest",
"pest_meta",
[[package]]
name = "pest_meta"
-version = "2.3.0"
+version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1538eb784f07615c6d9a8ab061089c6c54a344c5b4301db51990ca1c241e8c04"
+checksum = "984298b75898e30a843e278a9f2452c31e349a073a0ce6fd950a12a74464e065"
dependencies = [
"once_cell",
"pest",
- "sha-1",
+ "sha1",
]
[[package]]
name = "rustbook"
version = "0.1.0"
dependencies = [
- "clap 3.2.20",
+ "clap 4.0.32",
"env_logger 0.7.1",
"mdbook",
]
"cstr",
"libc",
"measureme",
- "object",
+ "object 0.30.1",
"rustc-demangle",
"rustc_ast",
"rustc_attr",
"itertools",
"jobserver",
"libc",
- "object",
+ "object 0.30.1",
"pathdiff",
"regex",
"rustc_arena",
dependencies = [
"rustc_span",
"tracing",
+ "tracing-core",
"tracing-subscriber",
"tracing-tree",
]
"rustc_macros",
"rustc_serialize",
"scoped-tls",
- "sha-1",
+ "sha1",
"sha2",
"tracing",
"unicode-width",
"serde",
]
-[[package]]
-name = "sha-1"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f"
-dependencies = [
- "cfg-if",
- "cpufeatures",
- "digest",
-]
-
[[package]]
name = "sha1"
version = "0.10.5"
"core",
"dlmalloc",
"fortanix-sgx-abi",
- "hashbrown",
+ "hashbrown 0.12.3",
"hermit-abi 0.2.6",
"libc",
"miniz_oxide",
- "object",
+ "object 0.29.0",
"panic_abort",
"panic_unwind",
"profiler_builtins",
"winapi-util",
]
+[[package]]
+name = "terminal_size"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb20089a8ba2b69debd491f8d2d023761cbf196e999218c591fa1e7e15a21907"
+dependencies = [
+ "rustix",
+ "windows-sys",
+]
+
[[package]]
name = "termize"
version = "0.1.1"
[[package]]
name = "thiserror"
-version = "1.0.33"
+version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d0a539a918745651435ac7db7a18761589a94cd7e94cd56999f828bf73c8a57"
+checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.33"
+version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c251e90f708e16c49a16f4917dc2131e75222b72edfa9cb7f7c58ae56aae0c09"
+checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
dependencies = [
"proc-macro2",
"quote",
[[package]]
name = "thorin-dwp"
-version = "0.3.0"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6cb0c7868d7f90407531108ab03263d9452a8811b7cdd87675343a40d4aa254"
+checksum = "da8fbf660a019b6bf11ea95762041464aa9099cc293b6a66d77cea5107619671"
dependencies = [
"gimli",
- "hashbrown",
- "object",
+ "hashbrown 0.12.3",
+ "object 0.30.1",
"tracing",
]
name = "tidy"
version = "0.1.0"
dependencies = [
+ "cargo-platform 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"cargo_metadata 0.14.0",
"ignore",
"lazy_static",
[[package]]
name = "topological-sort"
-version = "0.1.0"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa7c7f42dea4b1b99439786f5633aeb9c14c1b53f75e282803c2ec2ad545873c"
+checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d"
[[package]]
name = "tracing"
[[package]]
name = "ucd-trie"
-version = "0.1.3"
+version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
+checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81"
[[package]]
name = "ui_test"
[[package]]
name = "version_check"
-version = "0.9.3"
+version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "vte"
/// named `inverse_memory_index`.
///
// FIXME(eddyb) build a better abstraction for permutations, if possible.
- // FIXME(camlorn) also consider small vector optimization here.
+ // FIXME(camlorn) also consider small vector optimization here.
memory_index: Vec<u32>,
},
}
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
};
use rustc_hir as hir;
+use rustc_hir::def::Res;
use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, LangItem};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
use rustc_span::def_id::LocalDefId;
use rustc_span::hygiene::DesugaringKind;
-use rustc_span::symbol::sym;
+use rustc_span::symbol::{kw, sym};
use rustc_span::{BytePos, Span, Symbol};
use rustc_trait_selection::infer::InferCtxtExt;
use crate::diagnostics::conflict_errors::StorageDeadOrDrop::LocalStorageDead;
use crate::diagnostics::find_all_local_uses;
+use crate::diagnostics::mutability_errors::mut_borrow_of_mutable_ref;
use crate::{
borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind,
if let Some(hir::Node::Item(hir::Item {
kind: hir::ItemKind::Fn(_, _, body_id),
..
- })) = hir.find(hir.local_def_id_to_hir_id(self.mir_def_id()))
+ })) = hir.find(self.mir_hir_id())
&& let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id)
{
let place = &self.move_data.move_paths[mpi].place;
let tcx = self.infcx.tcx;
// Find out if the predicates show that the type is a Fn or FnMut
- let find_fn_kind_from_did = |predicates: ty::EarlyBinder<
- &[(ty::Predicate<'tcx>, Span)],
- >,
- substs| {
- predicates.0.iter().find_map(|(pred, _)| {
- let pred = if let Some(substs) = substs {
- predicates.rebind(*pred).subst(tcx, substs).kind().skip_binder()
- } else {
- pred.kind().skip_binder()
- };
- if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = pred && pred.self_ty() == ty {
- if Some(pred.def_id()) == tcx.lang_items().fn_trait() {
- return Some(hir::Mutability::Not);
- } else if Some(pred.def_id()) == tcx.lang_items().fn_mut_trait() {
- return Some(hir::Mutability::Mut);
- }
+ let find_fn_kind_from_did = |(pred, _): (ty::Predicate<'tcx>, _)| {
+ if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = pred.kind().skip_binder()
+ && pred.self_ty() == ty
+ {
+ if Some(pred.def_id()) == tcx.lang_items().fn_trait() {
+ return Some(hir::Mutability::Not);
+ } else if Some(pred.def_id()) == tcx.lang_items().fn_mut_trait() {
+ return Some(hir::Mutability::Mut);
}
- None
- })
+ }
+ None
};
// If the type is opaque/param/closure, and it is Fn or FnMut, let's suggest (mutably)
// borrowing the type, since `&mut F: FnMut` iff `F: FnMut` and similarly for `Fn`.
// These types seem reasonably opaque enough that they could be substituted with their
// borrowed variants in a function body when we see a move error.
- let borrow_level = match ty.kind() {
- ty::Param(_) => find_fn_kind_from_did(
- tcx.bound_explicit_predicates_of(self.mir_def_id().to_def_id())
- .map_bound(|p| p.predicates),
- None,
- ),
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
- find_fn_kind_from_did(tcx.bound_explicit_item_bounds(*def_id), Some(*substs))
- }
+ let borrow_level = match *ty.kind() {
+ ty::Param(_) => tcx
+ .explicit_predicates_of(self.mir_def_id().to_def_id())
+ .predicates
+ .iter()
+ .copied()
+ .find_map(find_fn_kind_from_did),
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => tcx
+ .bound_explicit_item_bounds(def_id)
+ .subst_iter_copied(tcx, substs)
+ .find_map(find_fn_kind_from_did),
ty::Closure(_, substs) => match substs.as_closure().kind() {
ty::ClosureKind::Fn => Some(hir::Mutability::Not),
ty::ClosureKind::FnMut => Some(hir::Mutability::Mut),
}
(BorrowKind::Mut { .. }, BorrowKind::Shared) => {
first_borrow_desc = "immutable ";
- self.cannot_reborrow_already_borrowed(
+ let mut err = self.cannot_reborrow_already_borrowed(
span,
&desc_place,
&msg_place,
"immutable",
&msg_borrow,
None,
- )
+ );
+ self.suggest_binding_for_closure_capture_self(
+ &mut err,
+ issued_borrow.borrowed_place,
+ &issued_spans,
+ );
+ err
}
(BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => {
}
}
+ fn suggest_binding_for_closure_capture_self(
+ &self,
+ err: &mut Diagnostic,
+ borrowed_place: Place<'tcx>,
+ issued_spans: &UseSpans<'tcx>,
+ ) {
+ let UseSpans::ClosureUse { capture_kind_span, .. } = issued_spans else { return };
+ let hir = self.infcx.tcx.hir();
+
+ // check whether the borrowed place is capturing `self` by mut reference
+ let local = borrowed_place.local;
+ let Some(_) = self
+ .body
+ .local_decls
+ .get(local)
+ .map(|l| mut_borrow_of_mutable_ref(l, self.local_names[local])) else { return };
+
+ struct ExpressionFinder<'hir> {
+ capture_span: Span,
+ closure_change_spans: Vec<Span>,
+ closure_arg_span: Option<Span>,
+ in_closure: bool,
+ suggest_arg: String,
+ hir: rustc_middle::hir::map::Map<'hir>,
+ closure_local_id: Option<hir::HirId>,
+ closure_call_changes: Vec<(Span, String)>,
+ }
+ impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> {
+ fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
+ if e.span.contains(self.capture_span) {
+ if let hir::ExprKind::Closure(&hir::Closure {
+ movability: None,
+ body,
+ fn_arg_span,
+ fn_decl: hir::FnDecl{ inputs, .. },
+ ..
+ }) = e.kind &&
+ let Some(hir::Node::Expr(body )) = self.hir.find(body.hir_id) {
+ self.suggest_arg = "this: &Self".to_string();
+ if inputs.len() > 0 {
+ self.suggest_arg.push_str(", ");
+ }
+ self.in_closure = true;
+ self.closure_arg_span = fn_arg_span;
+ self.visit_expr(body);
+ self.in_closure = false;
+ }
+ }
+ if let hir::Expr { kind: hir::ExprKind::Path(path), .. } = e {
+ if let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path &&
+ seg.ident.name == kw::SelfLower && self.in_closure {
+ self.closure_change_spans.push(e.span);
+ }
+ }
+ hir::intravisit::walk_expr(self, e);
+ }
+
+ fn visit_local(&mut self, local: &'hir hir::Local<'hir>) {
+ if let hir::Pat { kind: hir::PatKind::Binding(_, hir_id, _ident, _), .. } = local.pat &&
+ let Some(init) = local.init
+ {
+ if let hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure {
+ movability: None,
+ ..
+ }), .. } = init &&
+ init.span.contains(self.capture_span) {
+ self.closure_local_id = Some(*hir_id);
+ }
+ }
+ hir::intravisit::walk_local(self, local);
+ }
+
+ fn visit_stmt(&mut self, s: &'hir hir::Stmt<'hir>) {
+ if let hir::StmtKind::Semi(e) = s.kind &&
+ let hir::ExprKind::Call(hir::Expr { kind: hir::ExprKind::Path(path), ..}, args) = e.kind &&
+ let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path &&
+ let Res::Local(hir_id) = seg.res &&
+ Some(hir_id) == self.closure_local_id {
+ let (span, arg_str) = if args.len() > 0 {
+ (args[0].span.shrink_to_lo(), "self, ".to_string())
+ } else {
+ let span = e.span.trim_start(seg.ident.span).unwrap_or(e.span);
+ (span, "(self)".to_string())
+ };
+ self.closure_call_changes.push((span, arg_str));
+ }
+ hir::intravisit::walk_stmt(self, s);
+ }
+ }
+
+ if let Some(hir::Node::ImplItem(
+ hir::ImplItem { kind: hir::ImplItemKind::Fn(_fn_sig, body_id), .. }
+ )) = hir.find(self.mir_hir_id()) &&
+ let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id) {
+ let mut finder = ExpressionFinder {
+ capture_span: *capture_kind_span,
+ closure_change_spans: vec![],
+ closure_arg_span: None,
+ in_closure: false,
+ suggest_arg: String::new(),
+ closure_local_id: None,
+ closure_call_changes: vec![],
+ hir,
+ };
+ finder.visit_expr(expr);
+
+ if finder.closure_change_spans.is_empty() || finder.closure_call_changes.is_empty() {
+ return;
+ }
+
+ let mut sugg = vec![];
+ let sm = self.infcx.tcx.sess.source_map();
+
+ if let Some(span) = finder.closure_arg_span {
+ sugg.push((sm.next_point(span.shrink_to_lo()).shrink_to_hi(), finder.suggest_arg));
+ }
+ for span in finder.closure_change_spans {
+ sugg.push((span, "this".to_string()));
+ }
+
+ for (span, suggest) in finder.closure_call_changes {
+ sugg.push((span, suggest));
+ }
+
+ err.multipart_suggestion_verbose(
+ "try explicitly pass `&Self` into the Closure as an argument",
+ sugg,
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+
/// Returns the description of the root place for a conflicting borrow and the full
/// descriptions of the places that caused the conflict.
///
}
}
-fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {
+pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {
debug!("local_info: {:?}, ty.kind(): {:?}", local_decl.local_info, local_decl.ty.kind());
match local_decl.local_info.as_deref() {
match (elem, &base_ty.kind(), access) {
(_, _, Shallow(Some(ArtificialField::ArrayLength)))
| (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => {
- // The array length is like additional fields on the
+ // The array length is like additional fields on the
// type; it does not overlap any existing data there.
// Furthermore, if cannot actually be a prefix of any
// borrowed place (at least in MIR as it is currently.)
/// # Parameters
///
/// - `def_id`, the `impl Trait` type
- /// - `substs`, the substs used to instantiate this opaque type
+ /// - `substs`, the substs used to instantiate this opaque type
/// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of
/// `opaque_defn.concrete_ty`
#[instrument(level = "debug", skip(self))]
instantiated_predicates: ty::InstantiatedPredicates<'tcx>,
locations: Locations,
) {
- for (predicate, span) in instantiated_predicates
- .predicates
- .into_iter()
- .zip(instantiated_predicates.spans.into_iter())
- {
+ for (predicate, span) in instantiated_predicates {
debug!(?predicate);
let category = ConstraintCategory::Predicate(span);
let predicate = self.normalize_with_category(predicate, locations, category);
cstr = "0.2"
libc = "0.2"
measureme = "10.0.0"
-object = { version = "0.29.0", default-features = false, features = ["std", "read"] }
+object = { version = "0.30.1", default-features = false, features = [
+ "std",
+ "read",
+] }
tracing = "0.1"
rustc_middle = { path = "../rustc_middle" }
rustc-demangle = "0.1.21"
libc = "0.2.50"
jobserver = "0.1.22"
tempfile = "3.2"
-thorin-dwp = "0.3"
+thorin-dwp = "0.4"
pathdiff = "0.2.0"
serde_json = "1.0.59"
snap = "1"
rustc_const_eval = { path = "../rustc_const_eval" }
[dependencies.object]
-version = "0.29.0"
+version = "0.30.1"
default-features = false
features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"]
sess.emit_fatal(errors::LinkerFileStem);
});
+ // Remove any version postfix.
+ let stem = stem
+ .rsplit_once('-')
+ .and_then(|(lhs, rhs)| rhs.chars().all(char::is_numeric).then_some(lhs))
+ .unwrap_or(stem);
+
+ // GCC can have an optional target prefix.
let flavor = if stem == "emcc" {
LinkerFlavor::EmCc
} else if stem == "gcc"
|| stem.ends_with("-gcc")
+ || stem == "g++"
+ || stem.ends_with("-g++")
|| stem == "clang"
- || stem.ends_with("-clang")
+ || stem == "clang++"
{
LinkerFlavor::from_cli(LinkerFlavorCli::Gcc, &sess.target)
} else if stem == "wasm-ld" || stem.ends_with("-wasm-ld") {
};
let architecture = match &sess.target.arch[..] {
"arm" => Architecture::Arm,
- "aarch64" => Architecture::Aarch64,
+ "aarch64" => {
+ if sess.target.pointer_width == 32 {
+ Architecture::Aarch64_Ilp32
+ } else {
+ Architecture::Aarch64
+ }
+ }
"x86" => Architecture::I386,
"s390x" => Architecture::S390x,
"mips" => Architecture::Mips,
};
e_flags
}
- Architecture::Riscv64 if sess.target.options.features.contains("+d") => {
- // copied from `riscv64-linux-gnu-gcc foo.c -c`, note though
- // that the `+d` target feature represents whether the double
- // float abi is enabled.
- let e_flags = elf::EF_RISCV_RVC | elf::EF_RISCV_FLOAT_ABI_DOUBLE;
+ Architecture::Riscv32 | Architecture::Riscv64 => {
+ // Source: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/079772828bd10933d34121117a222b4cc0ee2200/riscv-elf.adoc
+ let mut e_flags: u32 = 0x0;
+ let features = &sess.target.options.features;
+ // Check if compressed is enabled
+ if features.contains("+c") {
+ e_flags |= elf::EF_RISCV_RVC;
+ }
+
+ // Select the appropriate floating-point ABI
+ if features.contains("+d") {
+ e_flags |= elf::EF_RISCV_FLOAT_ABI_DOUBLE;
+ } else if features.contains("+f") {
+ e_flags |= elf::EF_RISCV_FLOAT_ABI_SINGLE;
+ } else {
+ e_flags |= elf::EF_RISCV_FLOAT_ABI_SOFT;
+ }
e_flags
}
_ => 0,
registry: diagnostics_registry(),
};
+ if !tracing::dispatcher::has_been_set() {
+ init_rustc_env_logger_with_backtrace_option(&config.opts.unstable_opts.log_backtrace);
+ }
+
match make_input(config.opts.error_format, &matches.free) {
Err(reported) => return Err(reported),
Ok(Some((input, input_file_path))) => {
/// This allows tools to enable rust logging without having to magically match rustc's
/// tracing crate version.
pub fn init_rustc_env_logger() {
- if let Err(error) = rustc_log::init_rustc_env_logger() {
+ init_rustc_env_logger_with_backtrace_option(&None);
+}
+
+/// This allows tools to enable rust logging without having to magically match rustc's
+/// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to
+/// choose a target module you wish to show backtraces along with its logging.
+pub fn init_rustc_env_logger_with_backtrace_option(backtrace_target: &Option<String>) {
+ if let Err(error) = rustc_log::init_rustc_env_logger_with_backtrace_option(backtrace_target) {
early_error(ErrorOutputType::default(), &error.to_string());
}
}
pub fn main() -> ! {
let start_time = Instant::now();
let start_rss = get_resident_set_size();
- init_rustc_env_logger();
signal_handler::install();
let mut callbacks = TimePassesCallbacks::default();
install_ice_hook();
interface_failed_writing_file =
failed to write file {$path}: {$error}"
+
+interface_proc_macro_crate_panic_abort =
+ building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic
use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId};
use rustc_span::source_map::SourceMap;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{BytePos, FileName, RealFileName, Span, DUMMY_SP};
+use rustc_span::{BytePos, FileName, Span, DUMMY_SP};
use smallvec::{smallvec, SmallVec};
use std::iter;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
use std::rc::Rc;
pub(crate) use rustc_span::hygiene::MacroKind;
if let [variant] = &*enum_def.variants {
if variant.ident.name == sym::Input {
let filename = sess.source_map().span_to_filename(item.ident.span);
- if let FileName::Real(RealFileName::LocalPath(path)) = filename {
- if let Some(c) = path
+ if let FileName::Real(real) = filename {
+ if let Some(c) = real
+ .local_path()
+ .unwrap_or(Path::new(""))
.components()
.flat_map(|c| c.as_os_str().to_str())
.find(|c| c.starts_with("rental") || c.starts_with("allsorts-rental"))
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{walk_generics, Visitor as _};
use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
+use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::middle::stability::AllowUnstable;
use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
use rustc_middle::ty::GenericParamDefKind;
return tcx.const_error(ty).into();
}
if !infer_args && has_default {
- tcx.bound_const_param_default(param.def_id)
- .subst(tcx, substs.unwrap())
- .into()
+ tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into()
} else {
if infer_args {
self.astconv.ct_infer(ty, Some(param), self.span).into()
fn report_ambiguous_associated_type(
&self,
span: Span,
- type_str: &str,
- trait_str: &str,
+ types: &[String],
+ traits: &[String],
name: Symbol,
) -> ErrorGuaranteed {
let mut err = struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type");
.keys()
.any(|full_span| full_span.contains(span))
{
- err.span_suggestion(
+ err.span_suggestion_verbose(
span.shrink_to_lo(),
"you are looking for the module in `std`, not the primitive type",
"std::",
Applicability::MachineApplicable,
);
} else {
- err.span_suggestion(
- span,
- "use fully-qualified syntax",
- format!("<{} as {}>::{}", type_str, trait_str, name),
- Applicability::HasPlaceholders,
- );
+ match (types, traits) {
+ ([], []) => {
+ err.span_suggestion_verbose(
+ span,
+ &format!(
+ "if there were a type named `Type` that implements a trait named \
+ `Trait` with associated type `{name}`, you could use the \
+ fully-qualified path",
+ ),
+ format!("<Type as Trait>::{name}"),
+ Applicability::HasPlaceholders,
+ );
+ }
+ ([], [trait_str]) => {
+ err.span_suggestion_verbose(
+ span,
+ &format!(
+ "if there were a type named `Example` that implemented `{trait_str}`, \
+ you could use the fully-qualified path",
+ ),
+ format!("<Example as {trait_str}>::{name}"),
+ Applicability::HasPlaceholders,
+ );
+ }
+ ([], traits) => {
+ err.span_suggestions(
+ span,
+ &format!(
+ "if there were a type named `Example` that implemented one of the \
+ traits with associated type `{name}`, you could use the \
+ fully-qualified path",
+ ),
+ traits
+ .iter()
+ .map(|trait_str| format!("<Example as {trait_str}>::{name}"))
+ .collect::<Vec<_>>(),
+ Applicability::HasPlaceholders,
+ );
+ }
+ ([type_str], []) => {
+ err.span_suggestion_verbose(
+ span,
+ &format!(
+ "if there were a trait named `Example` with associated type `{name}` \
+ implemented for `{type_str}`, you could use the fully-qualified path",
+ ),
+ format!("<{type_str} as Example>::{name}"),
+ Applicability::HasPlaceholders,
+ );
+ }
+ (types, []) => {
+ err.span_suggestions(
+ span,
+ &format!(
+ "if there were a trait named `Example` with associated type `{name}` \
+ implemented for one of the types, you could use the fully-qualified \
+ path",
+ ),
+ types
+ .into_iter()
+ .map(|type_str| format!("<{type_str} as Example>::{name}")),
+ Applicability::HasPlaceholders,
+ );
+ }
+ (types, traits) => {
+ let mut suggestions = vec![];
+ for type_str in types {
+ for trait_str in traits {
+ suggestions.push(format!("<{type_str} as {trait_str}>::{name}"));
+ }
+ }
+ err.span_suggestions(
+ span,
+ "use the fully-qualified path",
+ suggestions,
+ Applicability::MachineApplicable,
+ );
+ }
+ }
}
err.emit()
}
};
self.one_bound_for_assoc_type(
- || traits::supertraits(tcx, ty::Binder::dummy(trait_ref)),
+ || traits::supertraits(tcx, ty::Binder::dummy(trait_ref.subst_identity())),
|| "Self".to_string(),
assoc_ident,
span,
err.emit()
} else if let Err(reported) = qself_ty.error_reported() {
reported
+ } else if let ty::Alias(ty::Opaque, alias_ty) = qself_ty.kind() {
+ // `<impl Trait as OtherTrait>::Assoc` makes no sense.
+ struct_span_err!(
+ tcx.sess,
+ tcx.def_span(alias_ty.def_id),
+ E0667,
+ "`impl Trait` is not allowed in path parameters"
+ )
+ .emit() // Already reported in an earlier stage.
} else {
+ // Find all the `impl`s that `qself_ty` has for any trait that has the
+ // associated type, so that we suggest the right one.
+ let infcx = tcx.infer_ctxt().build();
+ // We create a fresh `ty::ParamEnv` instead of the one for `self.item_def_id()`
+ // to avoid a cycle error in `src/test/ui/resolve/issue-102946.rs`.
+ let param_env = ty::ParamEnv::empty();
+ let traits: Vec<_> = self
+ .tcx()
+ .all_traits()
+ .filter(|trait_def_id| {
+ // Consider only traits with the associated type
+ tcx.associated_items(*trait_def_id)
+ .in_definition_order()
+ .any(|i| {
+ i.kind.namespace() == Namespace::TypeNS
+ && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
+ && matches!(i.kind, ty::AssocKind::Type)
+ })
+ // Consider only accessible traits
+ && tcx.visibility(*trait_def_id)
+ .is_accessible_from(self.item_def_id(), tcx)
+ && tcx.all_impls(*trait_def_id)
+ .any(|impl_def_id| {
+ let trait_ref = tcx.impl_trait_ref(impl_def_id);
+ trait_ref.map_or(false, |trait_ref| {
+ let impl_ = trait_ref.subst(
+ tcx,
+ infcx.fresh_substs_for_item(span, impl_def_id),
+ );
+ infcx
+ .can_eq(
+ param_env,
+ tcx.erase_regions(impl_.self_ty()),
+ tcx.erase_regions(qself_ty),
+ )
+ .is_ok()
+ })
+ && tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
+ })
+ })
+ .map(|trait_def_id| tcx.def_path_str(trait_def_id))
+ .collect();
+
// Don't print `TyErr` to the user.
self.report_ambiguous_associated_type(
span,
- &qself_ty.to_string(),
- "Trait",
+ &[qself_ty.to_string()],
+ &traits,
assoc_ident.name,
)
};
let is_part_of_self_trait_constraints = def_id == trait_def_id;
let is_part_of_fn_in_self_trait = parent_def_id == Some(trait_def_id);
- let type_name = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
- "Self"
+ let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
+ vec!["Self".to_string()]
} else {
- "Type"
+ // Find all the types that have an `impl` for the trait.
+ tcx.all_impls(trait_def_id)
+ .filter(|impl_def_id| {
+ // Consider only accessible traits
+ tcx.visibility(*impl_def_id).is_accessible_from(self.item_def_id(), tcx)
+ && tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
+ })
+ .filter_map(|impl_def_id| tcx.impl_trait_ref(impl_def_id))
+ .map(|impl_| impl_.subst_identity().self_ty())
+ // We don't care about blanket impls.
+ .filter(|self_ty| !self_ty.has_non_region_param())
+ .map(|self_ty| tcx.erase_regions(self_ty).to_string())
+ .collect()
};
-
+ // FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that
+ // references the trait. Relevant for the first case in
+ // `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs`
let reported = self.report_ambiguous_associated_type(
span,
- type_name,
- &path_str,
+ &type_names,
+ &[path_str],
item_segment.ident.name,
);
return tcx.ty_error_with_guaranteed(reported)
let label = "add `dyn` keyword before this trait";
let mut diag =
rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg);
- diag.multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable);
+ if self_ty.span.can_be_used_for_suggestions() {
+ diag.multipart_suggestion_verbose(
+ label,
+ sugg,
+ Applicability::MachineApplicable,
+ );
+ }
// check if the impl trait that we are considering is a impl of a local trait
self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
diag.emit();
tcx,
it.span,
it.owner_id.def_id,
- impl_trait_ref,
+ impl_trait_ref.subst_identity(),
&impl_.items,
);
check_on_unimplemented(tcx, it);
use crate::errors::LifetimesOrBoundsMismatchOnTrait;
use hir::def_id::{DefId, LocalDefId};
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
-use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed};
+use rustc_errors::{
+ pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed, MultiSpan,
+};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit;
//
// We then register the obligations from the impl_m and check to see
// if all constraints hold.
- hybrid_preds
- .predicates
- .extend(trait_m_predicates.instantiate_own(tcx, trait_to_placeholder_substs).predicates);
+ hybrid_preds.predicates.extend(
+ trait_m_predicates
+ .instantiate_own(tcx, trait_to_placeholder_substs)
+ .map(|(predicate, _)| predicate),
+ );
// Construct trait parameter environment and then shift it into the placeholder viewpoint.
// The key step here is to update the caller_bounds's predicates to be
debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds());
let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs);
- for (predicate, span) in iter::zip(impl_m_own_bounds.predicates, impl_m_own_bounds.spans) {
+ for (predicate, span) in impl_m_own_bounds {
let normalize_cause = traits::ObligationCause::misc(span, impl_m_hir_id);
let predicate = ocx.normalize(&normalize_cause, param_env, predicate);
ty::Binder::dummy(ty::PredicateKind::WellFormed(unnormalized_impl_fty.into())),
));
}
- let emit_implied_wf_lint = || {
- infcx.tcx.struct_span_lint_hir(
- rustc_session::lint::builtin::IMPLIED_BOUNDS_ENTAILMENT,
- impl_m_hir_id,
- infcx.tcx.def_span(impl_m.def_id),
- "impl method assumes more implied bounds than the corresponding trait method",
- |lint| lint,
- );
- };
// Check that all obligations are satisfied by the implementation's
// version.
)
.map(|()| {
// If the skip-mode was successful, emit a lint.
- emit_implied_wf_lint();
+ emit_implied_wf_lint(infcx.tcx, impl_m, impl_m_hir_id, vec![]);
});
}
CheckImpliedWfMode::Skip => {
CheckImpliedWfMode::Skip,
)
.map(|()| {
+ let bad_args = extract_bad_args_for_implies_lint(
+ tcx,
+ &errors,
+ (trait_m, trait_sig),
+ // Unnormalized impl sig corresponds to the HIR types written
+ (impl_m, unnormalized_impl_sig),
+ impl_m_hir_id,
+ );
// If the skip-mode was successful, emit a lint.
- emit_implied_wf_lint();
+ emit_implied_wf_lint(tcx, impl_m, impl_m_hir_id, bad_args);
});
}
CheckImpliedWfMode::Skip => {
Ok(())
}
+fn extract_bad_args_for_implies_lint<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ errors: &[infer::RegionResolutionError<'tcx>],
+ (trait_m, trait_sig): (&ty::AssocItem, ty::FnSig<'tcx>),
+ (impl_m, impl_sig): (&ty::AssocItem, ty::FnSig<'tcx>),
+ hir_id: hir::HirId,
+) -> Vec<(Span, Option<String>)> {
+ let mut blame_generics = vec![];
+ for error in errors {
+ // Look for the subregion origin that contains an input/output type
+ let origin = match error {
+ infer::RegionResolutionError::ConcreteFailure(o, ..) => o,
+ infer::RegionResolutionError::GenericBoundFailure(o, ..) => o,
+ infer::RegionResolutionError::SubSupConflict(_, _, o, ..) => o,
+ infer::RegionResolutionError::UpperBoundUniverseConflict(.., o, _) => o,
+ };
+ // Extract (possible) input/output types from origin
+ match origin {
+ infer::SubregionOrigin::Subtype(trace) => {
+ if let Some((a, b)) = trace.values.ty() {
+ blame_generics.extend([a, b]);
+ }
+ }
+ infer::SubregionOrigin::RelateParamBound(_, ty, _) => blame_generics.push(*ty),
+ infer::SubregionOrigin::ReferenceOutlivesReferent(ty, _) => blame_generics.push(*ty),
+ _ => {}
+ }
+ }
+
+ let fn_decl = tcx.hir().fn_decl_by_hir_id(hir_id).unwrap();
+ let opt_ret_ty = match fn_decl.output {
+ hir::FnRetTy::DefaultReturn(_) => None,
+ hir::FnRetTy::Return(ty) => Some(ty),
+ };
+
+ // Map late-bound regions from trait to impl, so the names are right.
+ let mapping = std::iter::zip(
+ tcx.fn_sig(trait_m.def_id).bound_vars(),
+ tcx.fn_sig(impl_m.def_id).bound_vars(),
+ )
+ .filter_map(|(impl_bv, trait_bv)| {
+ if let ty::BoundVariableKind::Region(impl_bv) = impl_bv
+ && let ty::BoundVariableKind::Region(trait_bv) = trait_bv
+ {
+ Some((impl_bv, trait_bv))
+ } else {
+ None
+ }
+ })
+ .collect();
+
+ // For each arg, see if it was in the "blame" of any of the region errors.
+ // If so, then try to produce a suggestion to replace the argument type with
+ // one from the trait.
+ let mut bad_args = vec![];
+ for (idx, (ty, hir_ty)) in
+ std::iter::zip(impl_sig.inputs_and_output, fn_decl.inputs.iter().chain(opt_ret_ty))
+ .enumerate()
+ {
+ let expected_ty = trait_sig.inputs_and_output[idx]
+ .fold_with(&mut RemapLateBound { tcx, mapping: &mapping });
+ if blame_generics.iter().any(|blame| ty.contains(*blame)) {
+ let expected_ty_sugg = expected_ty.to_string();
+ bad_args.push((
+ hir_ty.span,
+ // Only suggest something if it actually changed.
+ (expected_ty_sugg != ty.to_string()).then_some(expected_ty_sugg),
+ ));
+ }
+ }
+
+ bad_args
+}
+
+struct RemapLateBound<'a, 'tcx> {
+ tcx: TyCtxt<'tcx>,
+ mapping: &'a FxHashMap<ty::BoundRegionKind, ty::BoundRegionKind>,
+}
+
+impl<'tcx> TypeFolder<'tcx> for RemapLateBound<'_, 'tcx> {
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ if let ty::ReFree(fr) = *r {
+ self.tcx.mk_region(ty::ReFree(ty::FreeRegion {
+ bound_region: self
+ .mapping
+ .get(&fr.bound_region)
+ .copied()
+ .unwrap_or(fr.bound_region),
+ ..fr
+ }))
+ } else {
+ r
+ }
+ }
+}
+
+fn emit_implied_wf_lint<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ impl_m: &ty::AssocItem,
+ hir_id: hir::HirId,
+ bad_args: Vec<(Span, Option<String>)>,
+) {
+ let span: MultiSpan = if bad_args.is_empty() {
+ tcx.def_span(impl_m.def_id).into()
+ } else {
+ bad_args.iter().map(|(span, _)| *span).collect::<Vec<_>>().into()
+ };
+ tcx.struct_span_lint_hir(
+ rustc_session::lint::builtin::IMPLIED_BOUNDS_ENTAILMENT,
+ hir_id,
+ span,
+ "impl method assumes more implied bounds than the corresponding trait method",
+ |lint| {
+ let bad_args: Vec<_> =
+ bad_args.into_iter().filter_map(|(span, sugg)| Some((span, sugg?))).collect();
+ if !bad_args.is_empty() {
+ lint.multipart_suggestion(
+ format!(
+ "replace {} type{} to make the impl signature compatible",
+ pluralize!("this", bad_args.len()),
+ pluralize!(bad_args.len())
+ ),
+ bad_args,
+ Applicability::MaybeIncorrect,
+ );
+ }
+ lint
+ },
+ );
+}
+
#[derive(Debug, PartialEq, Eq)]
enum CheckImpliedWfMode {
/// Checks implied well-formedness of the impl method. If it fails, we will
) -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed> {
let impl_m = tcx.opt_associated_item(def_id).unwrap();
let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap();
- let impl_trait_ref = tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap();
+ let impl_trait_ref =
+ tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap().subst_identity();
let param_env = tcx.param_env(def_id);
// First, check a few of the same things as `compare_impl_method`,
) -> Result<(), ErrorGuaranteed> {
let impl_const_item = tcx.associated_item(impl_const_item_def);
let trait_const_item = tcx.associated_item(trait_const_item_def);
- let impl_trait_ref = tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap();
+ let impl_trait_ref =
+ tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap().subst_identity();
debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
let impl_c_span = tcx.def_span(impl_const_item_def.to_def_id());
check_region_bounds_on_impl_item(tcx, impl_ty, trait_ty, false)?;
let impl_ty_own_bounds = impl_ty_predicates.instantiate_own(tcx, impl_substs);
-
- if impl_ty_own_bounds.is_empty() {
+ if impl_ty_own_bounds.len() == 0 {
// Nothing to check.
return Ok(());
}
// associated type in the trait are assumed.
let impl_predicates = tcx.predicates_of(impl_ty_predicates.parent.unwrap());
let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
- hybrid_preds
- .predicates
- .extend(trait_ty_predicates.instantiate_own(tcx, trait_to_impl_substs).predicates);
+ hybrid_preds.predicates.extend(
+ trait_ty_predicates
+ .instantiate_own(tcx, trait_to_impl_substs)
+ .map(|(predicate, _)| predicate),
+ );
debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds);
debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds());
- assert_eq!(impl_ty_own_bounds.predicates.len(), impl_ty_own_bounds.spans.len());
- for (span, predicate) in std::iter::zip(impl_ty_own_bounds.spans, impl_ty_own_bounds.predicates)
- {
+ for (predicate, span) in impl_ty_own_bounds {
let cause = ObligationCause::misc(span, impl_ty_hir_id);
let predicate = ocx.normalize(&cause, param_env, predicate);
};
use std::cell::LazyCell;
-use std::iter;
use std::ops::{ControlFlow, Deref};
pub(super) struct WfCheckingCtxt<'a, 'tcx> {
hir::ItemKind::Impl(ref impl_) => {
let is_auto = tcx
.impl_trait_ref(def_id)
- .map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.def_id));
+ .map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.skip_binder().def_id));
if let (hir::Defaultness::Default { .. }, true) = (impl_.defaultness, is_auto) {
let sp = impl_.of_trait.as_ref().map_or(item.span, |t| t.path.span);
let mut err =
// `#[rustc_reservation_impl]` impls are not real impls and
// therefore don't need to be WF (the trait's `Self: Trait` predicate
// won't hold).
- let trait_ref = tcx.impl_trait_ref(item.owner_id).unwrap();
+ let trait_ref = tcx.impl_trait_ref(item.owner_id).unwrap().subst_identity();
let trait_ref = wfcx.normalize(
ast_trait_ref.path.span,
Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
let infcx = wfcx.infcx;
let tcx = wfcx.tcx();
- let predicates = tcx.bound_predicates_of(def_id.to_def_id());
+ let predicates = tcx.predicates_of(def_id.to_def_id());
let generics = tcx.generics_of(def_id);
let is_our_default = |def: &ty::GenericParamDef| match def.kind {
// is incorrect when dealing with unused substs, for example
// for `struct Foo<const N: usize, const M: usize = { 1 - 2 }>`
// we should eagerly error.
- let default_ct = tcx.const_param_default(param.def_id);
+ let default_ct = tcx.const_param_default(param.def_id).subst_identity();
if !default_ct.needs_subst() {
wfcx.register_wf_obligation(
tcx.def_span(param.def_id),
GenericParamDefKind::Const { .. } => {
// If the param has a default, ...
if is_our_default(param) {
- let default_ct = tcx.const_param_default(param.def_id);
+ let default_ct = tcx.const_param_default(param.def_id).subst_identity();
// ... and it's not a dependent default, ...
if !default_ct.needs_subst() {
// ... then substitute it with the default.
// Now we build the substituted predicates.
let default_obligations = predicates
- .0
.predicates
.iter()
.flat_map(|&(pred, sp)| {
}
let mut param_count = CountParams::default();
let has_region = pred.visit_with(&mut param_count).is_break();
- let substituted_pred = predicates.rebind(pred).subst(tcx, substs);
+ let substituted_pred = ty::EarlyBinder(pred).subst(tcx, substs);
// Don't check non-defaulted params, dependent defaults (including lifetimes)
// or preds with multiple params.
if substituted_pred.has_non_region_param() || param_count.params.len() > 1 || has_region
{
None
- } else if predicates.0.predicates.iter().any(|&(p, _)| p == substituted_pred) {
+ } else if predicates.predicates.iter().any(|&(p, _)| p == substituted_pred) {
// Avoid duplication of predicates that contain no parameters, for example.
None
} else {
traits::Obligation::new(tcx, cause, wfcx.param_env, pred)
});
- let predicates = predicates.0.instantiate_identity(tcx);
+ let predicates = predicates.instantiate_identity(tcx);
let predicates = wfcx.normalize(span, None, predicates);
debug!(?predicates.predicates);
assert_eq!(predicates.predicates.len(), predicates.spans.len());
- let wf_obligations =
- iter::zip(&predicates.predicates, &predicates.spans).flat_map(|(&p, &sp)| {
- traits::wf::predicate_obligations(
- infcx,
- wfcx.param_env.without_const(),
- wfcx.body_id,
- p,
- sp,
- )
- });
+ let wf_obligations = predicates.into_iter().flat_map(|(p, sp)| {
+ traits::wf::predicate_obligations(
+ infcx,
+ wfcx.param_env.without_const(),
+ wfcx.body_id,
+ p,
+ sp,
+ )
+ });
let obligations: Vec<_> = wf_obligations.chain(default_obligations).collect();
wfcx.register_obligations(obligations);
let source = tcx.type_of(impl_did);
assert!(!source.has_escaping_bound_vars());
let target = {
- let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
+ let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().subst_identity();
assert_eq!(trait_ref.def_id, dispatch_from_dyn_trait);
trait_ref.substs.type_at(1)
});
let source = tcx.type_of(impl_did);
- let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
+ let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().subst_identity();
assert_eq!(trait_ref.def_id, coerce_unsized_trait);
let target = trait_ref.substs.type_at(1);
debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target);
let impls = tcx.hir().trait_impls(def_id);
for &impl_def_id in impls {
- let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+ let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity();
check_impl(tcx, impl_def_id, trait_ref);
check_object_overlap(tcx, impl_def_id, trait_ref);
tcx: TyCtxt<'_>,
impl_def_id: LocalDefId,
) -> Result<(), ErrorGuaranteed> {
- let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+ let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity();
trait_ref.error_reported()?;
let ret = do_orphan_check_impl(tcx, trait_ref, impl_def_id);
let hir::ItemKind::Impl(ref impl_) = item.kind else { bug!() };
if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) {
+ let trait_ref = trait_ref.subst_identity();
let trait_def = tcx.trait_def(trait_ref.def_id);
let unsafe_attr =
impl_.generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle");
None
}
-fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::TraitRef<'_>> {
+fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::EarlyBinder<ty::TraitRef<'_>>> {
let icx = ItemCtxt::new(tcx, def_id);
let item = tcx.hir().expect_item(def_id.expect_local());
match item.kind {
- hir::ItemKind::Impl(ref impl_) => impl_.of_trait.as_ref().map(|ast_trait_ref| {
- let selfty = tcx.type_of(def_id);
- icx.astconv().instantiate_mono_trait_ref(
- ast_trait_ref,
- selfty,
- check_impl_constness(tcx, impl_.constness, ast_trait_ref),
- )
- }),
+ hir::ItemKind::Impl(ref impl_) => impl_
+ .of_trait
+ .as_ref()
+ .map(|ast_trait_ref| {
+ let selfty = tcx.type_of(def_id);
+ icx.astconv().instantiate_mono_trait_ref(
+ ast_trait_ref,
+ selfty,
+ check_impl_constness(tcx, impl_.constness, ast_trait_ref),
+ )
+ })
+ .map(ty::EarlyBinder),
_ => bug!(),
}
}
Node::Item(item) => match item.kind {
ItemKind::Impl(ref impl_) => {
if impl_.defaultness.is_default() {
- is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy);
+ is_default_impl_trait =
+ tcx.impl_trait_ref(def_id).map(|t| ty::Binder::dummy(t.subst_identity()));
}
&impl_.generics
}
// for details.
if let Node::Item(&Item { kind: ItemKind::Impl { .. }, .. }) = node {
let self_ty = tcx.type_of(def_id);
- let trait_ref = tcx.impl_trait_ref(def_id);
+ let trait_ref = tcx.impl_trait_ref(def_id).map(ty::EarlyBinder::subst_identity);
cgp::setup_constraining_predicates(
tcx,
&mut predicates,
}
let impl_generics = tcx.generics_of(impl_def_id);
let impl_predicates = tcx.predicates_of(impl_def_id);
- let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
+ let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).map(ty::EarlyBinder::subst_identity);
let mut input_parameters = cgp::parameters_for_impl(impl_self_ty, impl_trait_ref);
cgp::identify_constrained_generic_params(
fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Option<Node> {
let trait_ref = tcx.impl_trait_ref(impl1_def_id)?;
- let trait_def = tcx.trait_def(trait_ref.def_id);
+ let trait_def = tcx.trait_def(trait_ref.skip_binder().def_id);
let impl2_node = trait_def.ancestors(tcx, impl1_def_id.to_def_id()).ok()?.nth(1)?;
let impl_generic_predicates = tcx.predicates_of(impl_def_id);
let mut unconstrained_parameters = FxHashSet::default();
let mut constrained_params = FxHashSet::default();
- let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
+ let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).map(ty::EarlyBinder::subst_identity);
// Unfortunately the functions in `constrained_generic_parameters` don't do
// what we want here. We want only a list of constrained parameters while
});
// Include the well-formed predicates of the type parameters of the impl.
- for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().substs {
+ for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().subst_identity().substs {
let infcx = &tcx.infer_ctxt().build();
let obligations = wf::obligations(
infcx,
if self.tcx.has_attr(def_id, sym::rustc_evaluate_where_clauses) {
let predicates = self.tcx.predicates_of(def_id);
let predicates = predicates.instantiate(self.tcx, subst);
- for (predicate, predicate_span) in
- predicates.predicates.iter().zip(&predicates.spans)
- {
+ for (predicate, predicate_span) in predicates {
let obligation = Obligation::new(
self.tcx,
ObligationCause::dummy_with_span(callee_expr.span),
self.param_env,
- *predicate,
+ predicate,
);
let result = self.evaluate_obligation(&obligation);
self.tcx
callee_expr.span,
&format!("evaluate({:?}) = {:?}", predicate, result),
)
- .span_label(*predicate_span, "predicate")
+ .span_label(predicate_span, "predicate")
.emit();
}
}
};
if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) {
- if let Some((maybe_def, output_ty, _)) =
- self.extract_callable_info(callee_expr, callee_ty)
+ if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_ty)
&& !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span)
{
let descr = match maybe_def {
use super::FnCtxt;
use crate::type_error_struct;
-use rustc_errors::{struct_span_err, Applicability, DelayDm, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_errors::{
+ struct_span_err, Applicability, DelayDm, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
+};
use rustc_hir as hir;
use rustc_macros::{TypeFoldable, TypeVisitable};
use rustc_middle::mir::Mutability;
}
));
}
+
+ self.try_suggest_collection_to_bool(fcx, &mut err);
+
err.emit();
}
CastError::NeedViaInt => {
} else {
err.span_label(self.span, "invalid cast");
}
+
+ self.try_suggest_collection_to_bool(fcx, &mut err);
+
err.emit();
}
CastError::SizedUnsizedCast => {
},
);
}
+
+ /// Attempt to suggest using `.is_empty` when trying to cast from a
+ /// collection type to a boolean.
+ fn try_suggest_collection_to_bool(&self, fcx: &FnCtxt<'a, 'tcx>, err: &mut Diagnostic) {
+ if self.cast_ty.is_bool() {
+ let derefed = fcx
+ .autoderef(self.expr_span, self.expr_ty)
+ .silence_errors()
+ .find(|t| matches!(t.0.kind(), ty::Str | ty::Slice(..)));
+
+ if let Some((deref_ty, _)) = derefed {
+ // Give a note about what the expr derefs to.
+ if deref_ty != self.expr_ty.peel_refs() {
+ err.span_note(
+ self.expr_span,
+ format!(
+ "this expression `Deref`s to `{}` which implements `is_empty`",
+ fcx.ty_to_string(deref_ty)
+ ),
+ );
+ }
+
+ // Create a multipart suggestion: add `!` and `.is_empty()` in
+ // place of the cast.
+ let suggestion = vec![
+ (self.expr_span.shrink_to_lo(), "!".to_string()),
+ (self.span.with_lo(self.expr_span.hi()), ".is_empty()".to_string()),
+ ];
+
+ err.multipart_suggestion_verbose(format!(
+ "consider using the `is_empty` method on `{}` to determine if it contains anything",
+ fcx.ty_to_string(self.expr_ty),
+ ), suggestion, Applicability::MaybeIncorrect);
+ }
+ }
+ }
}
self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
self.check_for_range_as_method_call(err, expr, expr_ty, expected);
self.check_for_binding_assigned_block_without_tail_expression(err, expr, expr_ty, expected);
+ self.check_wrong_return_type_due_to_generic_arg(err, expr, expr_ty);
}
/// Requires that the two types unify, and prints an error message if
err.span_label(block.span, "this block is missing a tail expression");
}
}
+
+ fn check_wrong_return_type_due_to_generic_arg(
+ &self,
+ err: &mut Diagnostic,
+ expr: &hir::Expr<'_>,
+ checked_ty: Ty<'tcx>,
+ ) {
+ let Some(hir::Node::Expr(parent_expr)) = self.tcx.hir().find_parent(expr.hir_id) else { return; };
+ enum CallableKind {
+ Function,
+ Method,
+ Constructor,
+ }
+ let mut maybe_emit_help = |def_id: hir::def_id::DefId,
+ callable: rustc_span::symbol::Ident,
+ args: &[hir::Expr<'_>],
+ kind: CallableKind| {
+ let arg_idx = args.iter().position(|a| a.hir_id == expr.hir_id).unwrap();
+ let fn_ty = self.tcx.bound_type_of(def_id).0;
+ if !fn_ty.is_fn() {
+ return;
+ }
+ let fn_sig = fn_ty.fn_sig(self.tcx).skip_binder();
+ let Some(&arg) = fn_sig.inputs().get(arg_idx + if matches!(kind, CallableKind::Method) { 1 } else { 0 }) else { return; };
+ if matches!(arg.kind(), ty::Param(_))
+ && fn_sig.output().contains(arg)
+ && self.node_ty(args[arg_idx].hir_id) == checked_ty
+ {
+ let mut multi_span: MultiSpan = parent_expr.span.into();
+ multi_span.push_span_label(
+ args[arg_idx].span,
+ format!(
+ "this argument influences the {} of `{}`",
+ if matches!(kind, CallableKind::Constructor) {
+ "type"
+ } else {
+ "return type"
+ },
+ callable
+ ),
+ );
+ err.span_help(
+ multi_span,
+ format!(
+ "the {} `{}` due to the type of the argument passed",
+ match kind {
+ CallableKind::Function => "return type of this call is",
+ CallableKind::Method => "return type of this call is",
+ CallableKind::Constructor => "type constructed contains",
+ },
+ checked_ty
+ ),
+ );
+ }
+ };
+ match parent_expr.kind {
+ hir::ExprKind::Call(fun, args) => {
+ let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = fun.kind else { return; };
+ let hir::def::Res::Def(kind, def_id) = path.res else { return; };
+ let callable_kind = if matches!(kind, hir::def::DefKind::Ctor(_, _)) {
+ CallableKind::Constructor
+ } else {
+ CallableKind::Function
+ };
+ maybe_emit_help(def_id, path.segments[0].ident, args, callable_kind);
+ }
+ hir::ExprKind::MethodCall(method, _receiver, args, _span) => {
+ let Some(def_id) = self.typeck_results.borrow().type_dependent_def_id(parent_expr.hir_id) else { return; };
+ maybe_emit_help(def_id, method.ident, args, CallableKind::Method)
+ }
+ _ => return,
+ }
+ }
}
// Named constants have to be equated with the value
// being matched, so that's a read of the value being matched.
//
- // FIXME: We don't actually reads for ZSTs.
+ // FIXME: We don't actually reads for ZSTs.
needs_to_be_read = true;
}
_ => {
}
GenericParamDefKind::Const { has_default } => {
if !infer_args && has_default {
- tcx.bound_const_param_default(param.def_id)
- .subst(tcx, substs.unwrap())
- .into()
+ tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into()
} else {
self.fcx.var_for_def(self.span, param)
}
// FIXME(compiler-errors): This could be problematic if something has two
// fn-like predicates with different args, but callable types really never
// do that, so it's OK.
- for (predicate, span) in
- std::iter::zip(instantiated.predicates, instantiated.spans)
+ for (predicate, span) in instantiated
{
if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = predicate.kind().skip_binder()
&& pred.self_ty().peel_refs() == callee_ty
Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
};
use rustc_hir_analysis::astconv::AstConv;
-use rustc_infer::infer;
use rustc_infer::traits::{self, StatementAsExpression};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{
use rustc_span::symbol::{sym, Ident};
use rustc_span::{Span, Symbol};
use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
use rustc_trait_selection::traits::error_reporting::DefIdOrName;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
-use rustc_trait_selection::traits::NormalizeExt;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(crate) fn body_fn_sig(&self) -> Option<ty::FnSig<'tcx>> {
found: Ty<'tcx>,
can_satisfy: impl FnOnce(Ty<'tcx>) -> bool,
) -> bool {
- let Some((def_id_or_name, output, inputs)) = self.extract_callable_info(expr, found)
+ let Some((def_id_or_name, output, inputs)) = self.extract_callable_info(found)
else { return false; };
if can_satisfy(output) {
let (sugg_call, mut applicability) = match inputs.len() {
/// because the callable type must also be well-formed to be called.
pub(in super::super) fn extract_callable_info(
&self,
- expr: &Expr<'_>,
- found: Ty<'tcx>,
+ ty: Ty<'tcx>,
) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> {
- // Autoderef is useful here because sometimes we box callables, etc.
- let Some((def_id_or_name, output, inputs)) = self.autoderef(expr.span, found).silence_errors().find_map(|(found, _)| {
- match *found.kind() {
- ty::FnPtr(fn_sig) =>
- Some((DefIdOrName::Name("function pointer"), fn_sig.output(), fn_sig.inputs())),
- ty::FnDef(def_id, _) => {
- let fn_sig = found.fn_sig(self.tcx);
- Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs()))
- }
- ty::Closure(def_id, substs) => {
- let fn_sig = substs.as_closure().sig();
- Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs().map_bound(|inputs| &inputs[1..])))
- }
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
- self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
- if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
- && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
- // args tuple will always be substs[1]
- && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
- {
- Some((
- DefIdOrName::DefId(def_id),
- pred.kind().rebind(proj.term.ty().unwrap()),
- pred.kind().rebind(args.as_slice()),
- ))
- } else {
- None
- }
- })
- }
- ty::Dynamic(data, _, ty::Dyn) => {
- data.iter().find_map(|pred| {
- if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
- && Some(proj.def_id) == self.tcx.lang_items().fn_once_output()
- // for existential projection, substs are shifted over by 1
- && let ty::Tuple(args) = proj.substs.type_at(0).kind()
- {
- Some((
- DefIdOrName::Name("trait object"),
- pred.rebind(proj.term.ty().unwrap()),
- pred.rebind(args.as_slice()),
- ))
- } else {
- None
- }
- })
- }
- ty::Param(param) => {
- let def_id = self.tcx.generics_of(self.body_id.owner).type_param(¶m, self.tcx).def_id;
- self.tcx.predicates_of(self.body_id.owner).predicates.iter().find_map(|(pred, _)| {
- if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
- && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
- && proj.projection_ty.self_ty() == found
- // args tuple will always be substs[1]
- && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
- {
- Some((
- DefIdOrName::DefId(def_id),
- pred.kind().rebind(proj.term.ty().unwrap()),
- pred.kind().rebind(args.as_slice()),
- ))
- } else {
- None
- }
- })
- }
- _ => None,
- }
- }) else { return None; };
-
- let output = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, output);
- let inputs = inputs
- .skip_binder()
- .iter()
- .map(|ty| {
- self.replace_bound_vars_with_fresh_vars(
- expr.span,
- infer::FnCall,
- inputs.rebind(*ty),
- )
- })
- .collect();
-
- // We don't want to register any extra obligations, which should be
- // implied by wf, but also because that would possibly result in
- // erroneous errors later on.
- let infer::InferOk { value: output, obligations: _ } =
- self.at(&self.misc(expr.span), self.param_env).normalize(output);
-
- if output.is_ty_var() { None } else { Some((def_id_or_name, output, inputs)) }
+ self.err_ctxt().extract_callable_info(self.body_id, self.param_env, ty)
}
pub fn suggest_two_fn_call(
rhs_ty: Ty<'tcx>,
can_satisfy: impl FnOnce(Ty<'tcx>, Ty<'tcx>) -> bool,
) -> bool {
- let Some((_, lhs_output_ty, lhs_inputs)) = self.extract_callable_info(lhs_expr, lhs_ty)
+ let Some((_, lhs_output_ty, lhs_inputs)) = self.extract_callable_info(lhs_ty)
else { return false; };
- let Some((_, rhs_output_ty, rhs_inputs)) = self.extract_callable_info(rhs_expr, rhs_ty)
+ let Some((_, rhs_output_ty, rhs_inputs)) = self.extract_callable_info(rhs_ty)
else { return false; };
if can_satisfy(lhs_output_ty, rhs_output_ty) {
use rustc_span::{Span, DUMMY_SP};
use rustc_trait_selection::traits;
-use std::iter;
use std::ops::Deref;
struct ConfirmContext<'a, 'tcx> {
let filler_substs = rcvr_substs
.extend_to(self.tcx, pick.item.def_id, |def, _| self.tcx.mk_param_from_def(def));
let illegal_sized_bound = self.predicates_require_illegal_sized_bound(
- &self.tcx.predicates_of(pick.item.def_id).instantiate(self.tcx, filler_substs),
+ self.tcx.predicates_of(pick.item.def_id).instantiate(self.tcx, filler_substs),
);
// Unify the (adjusted) self type with what the method expects.
fn predicates_require_illegal_sized_bound(
&self,
- predicates: &ty::InstantiatedPredicates<'tcx>,
+ predicates: ty::InstantiatedPredicates<'tcx>,
) -> Option<Span> {
let sized_def_id = self.tcx.lang_items().sized_trait()?;
ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred))
if trait_pred.def_id() == sized_def_id =>
{
- let span = iter::zip(&predicates.predicates, &predicates.spans)
+ let span = predicates
+ .iter()
.find_map(
|(p, span)| {
- if *p == obligation.predicate { Some(*span) } else { None }
+ if p == obligation.predicate { Some(span) } else { None }
},
)
.unwrap_or(rustc_span::DUMMY_SP);
pub enum Mode {
// An expression of the form `receiver.method_name(...)`.
// Autoderefs are performed on `receiver`, lookup is done based on the
- // `self` argument of the method, and static methods aren't considered.
+ // `self` argument of the method, and static methods aren't considered.
MethodCall,
// An expression of the form `Type::item` or `<T>::item`.
// No autoderefs are performed, lookup is done based on the type each
let o = self.resolve_vars_if_possible(o);
if !self.predicate_may_hold(&o) {
result = ProbeResult::NoMatch;
- possibly_unsatisfied_predicates.push((
- o.predicate,
- None,
- Some(o.cause),
- ));
+ let parent_o = o.clone();
+ let implied_obligations =
+ traits::elaborate_obligations(self.tcx, vec![o]);
+ for o in implied_obligations {
+ let parent = if o == parent_o {
+ None
+ } else {
+ if o.predicate.to_opt_poly_trait_pred().map(|p| p.def_id())
+ == self.tcx.lang_items().sized_trait()
+ {
+ // We don't care to talk about implicit `Sized` bounds.
+ continue;
+ }
+ Some(parent_o.predicate)
+ };
+ if !self.predicate_may_hold(&o) {
+ possibly_unsatisfied_predicates.push((
+ o.predicate,
+ parent,
+ Some(o.cause),
+ ));
+ }
+ }
}
}
}
}
_ => None,
};
- if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
- if let Some(g) = kind.generics() {
- let key = (
- g.tail_span_for_predicate_suggestion(),
- g.add_where_or_trailing_comma(),
- );
- type_params
- .entry(key)
- .or_insert_with(FxHashSet::default)
- .insert(obligation.to_owned());
- }
+ if let Some(hir::Node::Item(hir::Item { kind, .. })) = node
+ && let Some(g) = kind.generics()
+ {
+ let key = (
+ g.tail_span_for_predicate_suggestion(),
+ g.add_where_or_trailing_comma(),
+ );
+ type_params
+ .entry(key)
+ .or_insert_with(FxHashSet::default)
+ .insert(obligation.to_owned());
+ return true;
}
}
+ false
};
let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
let msg = format!(
"auto trait is invoked with no method error, but no error reported?",
);
}
- Some(_) => unreachable!(),
+ Some(Node::Item(hir::Item {
+ ident, kind: hir::ItemKind::Trait(..), ..
+ })) => {
+ skip_list.insert(p);
+ let entry = spanned_predicates.entry(ident.span);
+ let entry = entry.or_insert_with(|| {
+ (FxHashSet::default(), FxHashSet::default(), Vec::new())
+ });
+ entry.0.insert(cause.span);
+ entry.1.insert((ident.span, ""));
+ entry.1.insert((cause.span, "unsatisfied trait bound introduced here"));
+ entry.2.push(p);
+ }
+ Some(node) => unreachable!("encountered `{node:?}`"),
None => (),
}
}
unsatisfied_bounds = true;
}
+ let mut suggested_bounds = FxHashSet::default();
// The requirements that didn't have an `impl` span to show.
let mut bound_list = unsatisfied_predicates
.iter()
.filter_map(|(pred, parent_pred, _cause)| {
+ let mut suggested = false;
format_pred(*pred).map(|(p, self_ty)| {
- collect_type_param_suggestions(self_ty, *pred, &p);
+ if let Some(parent) = parent_pred && suggested_bounds.contains(parent) {
+ // We don't suggest `PartialEq` when we already suggest `Eq`.
+ } else if !suggested_bounds.contains(pred) {
+ if collect_type_param_suggestions(self_ty, *pred, &p) {
+ suggested = true;
+ suggested_bounds.insert(pred);
+ }
+ }
(
match parent_pred {
None => format!("`{}`", &p),
Some(parent_pred) => match format_pred(*parent_pred) {
None => format!("`{}`", &p),
Some((parent_p, _)) => {
- collect_type_param_suggestions(self_ty, *parent_pred, &p);
+ if !suggested
+ && !suggested_bounds.contains(pred)
+ && !suggested_bounds.contains(parent_pred)
+ {
+ if collect_type_param_suggestions(
+ self_ty,
+ *parent_pred,
+ &p,
+ ) {
+ suggested_bounds.insert(pred);
+ }
+ }
format!("`{}`\nwhich is required by `{}`", p, parent_p)
}
},
// the impl, if local to crate (item may be defaulted), else nothing.
let Some(item) = self.associated_value(impl_did, item_name).or_else(|| {
let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
- self.associated_value(impl_trait_ref.def_id, item_name)
+ self.associated_value(impl_trait_ref.skip_binder().def_id, item_name)
}) else {
continue;
};
let insertion = match self.tcx.impl_trait_ref(impl_did) {
None => String::new(),
Some(trait_ref) => {
- format!(" of the trait `{}`", self.tcx.def_path_str(trait_ref.def_id))
+ format!(
+ " of the trait `{}`",
+ self.tcx.def_path_str(trait_ref.skip_binder().def_id)
+ )
}
};
}
if let Some(sugg_span) = sugg_span
&& let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
- let path = self.tcx.def_path_str(trait_ref.def_id);
+ let path = self.tcx.def_path_str(trait_ref.skip_binder().def_id);
let ty = match item.kind {
ty::AssocKind::Const | ty::AssocKind::Type => rcvr_ty,
self.tcx.impl_polarity(*imp_did) == ty::ImplPolarity::Negative
})
.any(|imp_did| {
- let imp = self.tcx.impl_trait_ref(imp_did).unwrap();
+ let imp = self.tcx.impl_trait_ref(imp_did).unwrap().subst_identity();
let imp_simp =
simplify_type(self.tcx, imp.self_ty(), TreatParams::AsPlaceholder);
imp_simp.map_or(false, |s| s == simp_rcvr_ty)
found: Ty<'tcx>,
expected: Ty<'tcx>,
) -> bool {
- let Some((_def_id_or_name, output, _inputs)) = self.extract_callable_info(expr, found)
- else { return false; };
+ let Some((_def_id_or_name, output, _inputs)) =
+ self.extract_callable_info(found) else {
+ return false;
+ };
if !self.can_coerce(output, expected) {
return false;
(ty::Tuple(fields), _) => {
self.emit_tuple_wrap_err(&mut err, span, found, fields)
}
+ // If a byte was expected and the found expression is a char literal
+ // containing a single ASCII character, perhaps the user meant to write `b'c'` to
+ // specify a byte literal
+ (ty::Uint(ty::UintTy::U8), ty::Char) => {
+ if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
+ && let Some(code) = code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
+ && code.chars().next().map_or(false, |c| c.is_ascii())
+ {
+ err.span_suggestion(
+ span,
+ "if you meant to write a byte literal, prefix with `b`",
+ format!("b'{}'", escape_literal(code)),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
// If a character was expected and the found expression is a string literal
// containing a single character, perhaps the user meant to write `'c'` to
// specify a character literal (issue #92479)
.impl_trait_ref(impl_def_id)
else { return; };
let trait_substs = trait_ref
+ .subst_identity()
// Replace the explicit self type with `Self` for better suggestion rendering
.with_self_ty(self.tcx, self.tcx.mk_ty_param(0, kw::SelfUpper))
.substs;
let Ok(trait_predicates) = self
.tcx
- .bound_explicit_predicates_of(trait_item_def_id)
- .map_bound(|p| p.predicates)
- .subst_iter_copied(self.tcx, trait_item_substs)
+ .explicit_predicates_of(trait_item_def_id)
+ .instantiate_own(self.tcx, trait_item_substs)
.map(|(pred, _)| {
if pred.is_suggestable(self.tcx, false) {
Ok(pred.to_string())
use smallvec::smallvec;
use crate::infer::outlives::components::{push_outlives_components, Component};
-use crate::traits::{Obligation, ObligationCause, PredicateObligation};
+use crate::traits::{self, Obligation, ObligationCause, PredicateObligation};
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_middle::ty::{self, ToPredicate, TyCtxt};
use rustc_span::symbol::Ident;
// Get predicates declared on the trait.
let predicates = tcx.super_predicates_of(data.def_id());
- let obligations = predicates.predicates.iter().map(|&(mut pred, _)| {
+ let obligations = predicates.predicates.iter().map(|&(mut pred, span)| {
// when parent predicate is non-const, elaborate it to non-const predicates.
if data.constness == ty::BoundConstness::NotConst {
pred = pred.without_const(tcx);
}
+ let cause = obligation.cause.clone().derived_cause(
+ bound_predicate.rebind(data),
+ |derived| {
+ traits::ImplDerivedObligation(Box::new(
+ traits::ImplDerivedObligationCause {
+ derived,
+ impl_def_id: data.def_id(),
+ span,
+ },
+ ))
+ },
+ );
predicate_obligation(
pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)),
obligation.param_env,
- obligation.cause.clone(),
+ cause,
)
});
debug!(?data, ?obligations, "super_predicates");
rustc_privacy = { path = "../rustc_privacy" }
rustc_query_impl = { path = "../rustc_query_impl" }
rustc_resolve = { path = "../rustc_resolve" }
+rustc_target = { path = "../rustc_target" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
rustc_ty_utils = { path = "../rustc_ty_utils" }
pub path: &'a Path,
pub error: io::Error,
}
+
+#[derive(Diagnostic)]
+#[diag(interface_proc_macro_crate_panic_abort)]
+pub struct ProcMacroCratePanicAbort;
use crate::errors::{
CantEmitMIR, EmojiIdentifier, ErrorWritingDependencies, FerrisIdentifier,
GeneratedFileConflictsWithDirectory, InputFileWouldBeOverWritten, MixedBinCrate,
- MixedProcMacroCrate, OutDirError, ProcMacroDocWithoutArg, TempsDirError,
+ MixedProcMacroCrate, OutDirError, ProcMacroCratePanicAbort, ProcMacroDocWithoutArg,
+ TempsDirError,
};
use crate::interface::{Compiler, Result};
use crate::proc_macro_decls;
use rustc_session::{Limit, Session};
use rustc_span::symbol::{sym, Symbol};
use rustc_span::FileName;
+use rustc_target::spec::PanicStrategy;
use rustc_trait_selection::traits;
use std::any::Any;
}
}
+ if is_proc_macro_crate && sess.panic_strategy() == PanicStrategy::Abort {
+ sess.emit_warning(ProcMacroCratePanicAbort);
+ }
+
// For backwards compatibility, we don't try to run proc macro injection
// if rustdoc is run on a proc macro crate without '--crate-type proc-macro' being
// specified. This should only affect users who manually invoke 'rustdoc', as
tracked!(link_only, true);
tracked!(llvm_plugins, vec![String::from("plugin_name")]);
tracked!(location_detail, LocationDetail { file: true, line: false, column: false });
+ tracked!(log_backtrace, Some("filter".to_string()));
tracked!(maximal_hir_to_mir_coverage, true);
tracked!(merge_functions, Some(MergeFunctions::Disabled));
tracked!(mir_emit_retag, true);
},
None => cx.emit_spanned_lint(USAGE_OF_TY_TYKIND, path.span, TykindDiag),
}
- } else if !ty.span.from_expansion() && path.segments.len() > 1 && let Some(t) = is_ty_or_ty_ctxt(cx, &path) {
+ } else if !ty.span.from_expansion() && path.segments.len() > 1 && let Some(ty) = is_ty_or_ty_ctxt(cx, &path) {
cx.emit_spanned_lint(USAGE_OF_QUALIFIED_TY, path.span, TyQualified {
- ty: t.clone(),
+ ty,
suggestion: path.span,
});
}
cx.emit_spanned_lint(
PASS_BY_VALUE,
ty.span,
- PassByValueDiag { ty: t.clone(), suggestion: ty.span },
+ PassByValueDiag { ty: t, suggestion: ty.span },
);
}
}
// ```
// - the block has no attribute and was not created inside a macro
// - if the block is an `anon_const`, the inner expr must be a literal
- // (do not lint `struct A<const N: usize>; let _: A<{ 2 + 3 }>;`)
- //
+ // not created by a macro, i.e. do not lint on:
+ // ```
+ // struct A<const N: usize>;
+ // let _: A<{ 2 + 3 }>;
+ // let _: A<{produces_literal!()}>;
+ // ```
// FIXME(const_generics): handle paths when #67075 is fixed.
if let [stmt] = inner.stmts.as_slice() {
if let ast::StmtKind::Expr(ref expr) = stmt.kind {
if !Self::is_expr_delims_necessary(expr, followed_by_block, false)
&& (ctx != UnusedDelimsCtx::AnonConst
- || matches!(expr.kind, ast::ExprKind::Lit(_)))
+ || (matches!(expr.kind, ast::ExprKind::Lit(_))
+ && !expr.span.from_expansion()))
&& !cx.sess().source_map().is_multiline(value.span)
&& value.attrs.is_empty()
&& !value.span.from_expansion()
///
/// This can be used to implement an unsound API if used incorrectly.
pub IMPLIED_BOUNDS_ENTAILMENT,
- Warn,
+ Deny,
"impl method assumes more implied bounds than its corresponding trait method",
@future_incompatible = FutureIncompatibleInfo {
reference: "issue #105572 <https://github.com/rust-lang/rust/issues/105572>",
- reason: FutureIncompatibilityReason::FutureReleaseError,
+ reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
};
}
tracing = "0.1.28"
tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
tracing-tree = "0.2.0"
+tracing-core = "0.1.28"
[dev-dependencies]
rustc_span = { path = "../rustc_span" }
use std::env::{self, VarError};
use std::fmt::{self, Display};
use std::io::{self, IsTerminal};
+use tracing_core::{Event, Subscriber};
use tracing_subscriber::filter::{Directive, EnvFilter, LevelFilter};
+use tracing_subscriber::fmt::{
+ format::{self, FormatEvent, FormatFields},
+ FmtContext,
+};
use tracing_subscriber::layer::SubscriberExt;
pub fn init_rustc_env_logger() -> Result<(), Error> {
- init_env_logger("RUSTC_LOG")
+ init_rustc_env_logger_with_backtrace_option(&None)
+}
+
+pub fn init_rustc_env_logger_with_backtrace_option(
+ backtrace_target: &Option<String>,
+) -> Result<(), Error> {
+ init_env_logger_with_backtrace_option("RUSTC_LOG", backtrace_target)
}
/// In contrast to `init_rustc_env_logger` this allows you to choose an env var
/// other than `RUSTC_LOG`.
pub fn init_env_logger(env: &str) -> Result<(), Error> {
+ init_env_logger_with_backtrace_option(env, &None)
+}
+
+pub fn init_env_logger_with_backtrace_option(
+ env: &str,
+ backtrace_target: &Option<String>,
+) -> Result<(), Error> {
let filter = match env::var(env) {
Ok(env) => EnvFilter::new(env),
_ => EnvFilter::default().add_directive(Directive::from(LevelFilter::WARN)),
let layer = layer.with_thread_ids(true).with_thread_names(true);
let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer);
- tracing::subscriber::set_global_default(subscriber).unwrap();
+ match backtrace_target {
+ Some(str) => {
+ let fmt_layer = tracing_subscriber::fmt::layer()
+ .with_writer(io::stderr)
+ .without_time()
+ .event_format(BacktraceFormatter { backtrace_target: str.to_string() });
+ let subscriber = subscriber.with(fmt_layer);
+ tracing::subscriber::set_global_default(subscriber).unwrap();
+ }
+ None => {
+ tracing::subscriber::set_global_default(subscriber).unwrap();
+ }
+ };
Ok(())
}
+struct BacktraceFormatter {
+ backtrace_target: String,
+}
+
+impl<S, N> FormatEvent<S, N> for BacktraceFormatter
+where
+ S: Subscriber + for<'a> tracing_subscriber::registry::LookupSpan<'a>,
+ N: for<'a> FormatFields<'a> + 'static,
+{
+ fn format_event(
+ &self,
+ _ctx: &FmtContext<'_, S, N>,
+ mut writer: format::Writer<'_>,
+ event: &Event<'_>,
+ ) -> fmt::Result {
+ let target = event.metadata().target();
+ if !target.contains(&self.backtrace_target) {
+ return Ok(());
+ }
+ let backtrace = std::backtrace::Backtrace::capture();
+ writeln!(writer, "stack backtrace: \n{:?}", backtrace)
+ }
+}
+
pub fn stdout_isatty() -> bool {
io::stdout().is_terminal()
}
self.tables.impl_defaultness.set(def_id.index, *defaultness);
self.tables.constness.set(def_id.index, *constness);
- let trait_ref = self.tcx.impl_trait_ref(def_id);
+ let trait_ref = self.tcx.impl_trait_ref(def_id).map(ty::EarlyBinder::skip_binder);
if let Some(trait_ref) = trait_ref {
let trait_def = self.tcx.trait_def(trait_ref.def_id);
if let Ok(mut an) = trait_def.ancestors(self.tcx, def_id) {
for id in tcx.hir().items() {
if matches!(tcx.def_kind(id.owner_id), DefKind::Impl) {
if let Some(trait_ref) = tcx.impl_trait_ref(id.owner_id) {
+ let trait_ref = trait_ref.subst_identity();
+
let simplified_self_ty = fast_reject::simplify_type(
self.tcx,
trait_ref.self_ty(),
variances_of: Table<DefIndex, LazyArray<ty::Variance>>,
fn_sig: Table<DefIndex, LazyValue<ty::PolyFnSig<'static>>>,
codegen_fn_attrs: Table<DefIndex, LazyValue<CodegenFnAttrs>>,
- impl_trait_ref: Table<DefIndex, LazyValue<ty::TraitRef<'static>>>,
- const_param_default: Table<DefIndex, LazyValue<rustc_middle::ty::Const<'static>>>,
+ impl_trait_ref: Table<DefIndex, LazyValue<ty::EarlyBinder<ty::TraitRef<'static>>>>,
+ const_param_default: Table<DefIndex, LazyValue<ty::EarlyBinder<rustc_middle::ty::Const<'static>>>>,
object_lifetime_default: Table<DefIndex, LazyValue<ObjectLifetimeDefault>>,
optimized_mir: Table<DefIndex, LazyValue<mir::Body<'static>>>,
mir_for_ctfe: Table<DefIndex, LazyValue<mir::Body<'static>>>,
pub fn impl_subject(self, def_id: DefId) -> ImplSubject<'tcx> {
self.impl_trait_ref(def_id)
+ .map(|t| t.subst_identity())
.map(ImplSubject::Trait)
.unwrap_or_else(|| ImplSubject::Inherent(self.type_of(def_id)))
}
/// Given the def_id of a const-generic parameter, computes the associated default const
/// parameter. e.g. `fn example<const N: usize=3>` called on `N` would return `3`.
- query const_param_default(param: DefId) -> ty::Const<'tcx> {
+ query const_param_default(param: DefId) -> ty::EarlyBinder<ty::Const<'tcx>> {
desc { |tcx| "computing const default for a given parameter `{}`", tcx.def_path_str(param) }
cache_on_disk_if { param.is_local() }
separate_provide_extern
/// Given an `impl_id`, return the trait it implements.
/// Return `None` if this is an inherent impl.
- query impl_trait_ref(impl_id: DefId) -> Option<ty::TraitRef<'tcx>> {
+ query impl_trait_ref(impl_id: DefId) -> Option<ty::EarlyBinder<ty::TraitRef<'tcx>>> {
desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(impl_id) }
cache_on_disk_if { impl_id.is_local() }
separate_provide_extern
}
}
-pub fn const_param_default(tcx: TyCtxt<'_>, def_id: DefId) -> Const<'_> {
+pub fn const_param_default(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Const<'_>> {
let default_def_id = match tcx.hir().get_by_def_id(def_id.expect_local()) {
hir::Node::GenericParam(hir::GenericParam {
kind: hir::GenericParamKind::Const { default: Some(ac), .. },
"`const_param_default` expected a generic parameter with a constant"
),
};
- Const::from_anon_const(tcx, default_def_id)
+ ty::EarlyBinder(Const::from_anon_const(tcx, default_def_id))
}
Some(tcx.bound_type_of(self.def_id).map_bound(|t| t.into()))
}
GenericParamDefKind::Const { has_default } if has_default => {
- Some(tcx.bound_const_param_default(self.def_id).map_bound(|c| c.into()))
+ Some(tcx.const_param_default(self.def_id).map_bound(|c| c.into()))
}
_ => None,
}
&self,
tcx: TyCtxt<'tcx>,
substs: SubstsRef<'tcx>,
- ) -> InstantiatedPredicates<'tcx> {
- InstantiatedPredicates {
- predicates: self
- .predicates
- .iter()
- .map(|(p, _)| EarlyBinder(*p).subst(tcx, substs))
- .collect(),
- spans: self.predicates.iter().map(|(_, sp)| *sp).collect(),
- }
+ ) -> impl Iterator<Item = (Predicate<'tcx>, Span)> + DoubleEndedIterator + ExactSizeIterator
+ {
+ EarlyBinder(self.predicates).subst_iter_copied(tcx, substs)
}
#[instrument(level = "debug", skip(self, tcx))]
pub fn is_empty(&self) -> bool {
self.predicates.is_empty()
}
+
+ pub fn iter(&self) -> <&Self as IntoIterator>::IntoIter {
+ (&self).into_iter()
+ }
+}
+
+impl<'tcx> IntoIterator for InstantiatedPredicates<'tcx> {
+ type Item = (Predicate<'tcx>, Span);
+
+ type IntoIter = std::iter::Zip<std::vec::IntoIter<Predicate<'tcx>>, std::vec::IntoIter<Span>>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ debug_assert_eq!(self.predicates.len(), self.spans.len());
+ std::iter::zip(self.predicates, self.spans)
+ }
+}
+
+impl<'a, 'tcx> IntoIterator for &'a InstantiatedPredicates<'tcx> {
+ type Item = (Predicate<'tcx>, Span);
+
+ type IntoIter = std::iter::Zip<
+ std::iter::Copied<std::slice::Iter<'a, Predicate<'tcx>>>,
+ std::iter::Copied<std::slice::Iter<'a, Span>>,
+ >;
+
+ fn into_iter(self) -> Self::IntoIter {
+ debug_assert_eq!(self.predicates.len(), self.spans.len());
+ std::iter::zip(self.predicates.iter().copied(), self.spans.iter().copied())
+ }
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable, Lift)]
) -> Option<ImplOverlapKind> {
// If either trait impl references an error, they're allowed to overlap,
// as one of them essentially doesn't exist.
- if self.impl_trait_ref(def_id1).map_or(false, |tr| tr.references_error())
- || self.impl_trait_ref(def_id2).map_or(false, |tr| tr.references_error())
+ if self.impl_trait_ref(def_id1).map_or(false, |tr| tr.subst_identity().references_error())
+ || self
+ .impl_trait_ref(def_id2)
+ .map_or(false, |tr| tr.subst_identity().references_error())
{
return Some(ImplOverlapKind::Permitted { marker: false });
}
let is_marker_overlap = {
let is_marker_impl = |def_id: DefId| -> bool {
let trait_ref = self.impl_trait_ref(def_id);
- trait_ref.map_or(false, |tr| self.trait_def(tr.def_id).is_marker)
+ trait_ref.map_or(false, |tr| self.trait_def(tr.skip_binder().def_id).is_marker)
};
is_marker_impl(def_id1) && is_marker_impl(def_id2)
};
/// Given the `DefId` of an impl, returns the `DefId` of the trait it implements.
/// If it implements no trait, returns `None`.
pub fn trait_id_of_impl(self, def_id: DefId) -> Option<DefId> {
- self.impl_trait_ref(def_id).map(|tr| tr.def_id)
+ self.impl_trait_ref(def_id).map(|tr| tr.skip_binder().def_id)
}
/// If the given `DefId` describes an item belonging to a trait,
type Value<'tcx> = ty::Binder<'tcx, T::Value<'tcx>>;
}
+impl<T: ParameterizedOverTcx> ParameterizedOverTcx for ty::EarlyBinder<T> {
+ type Value<'tcx> = ty::EarlyBinder<T::Value<'tcx>>;
+}
+
#[macro_export]
macro_rules! trivially_parameterized_over_tcx {
($($ty:ty),+ $(,)?) => {
DefPathData::Impl => {
let generics = self.tcx().generics_of(def_id);
let self_ty = self.tcx().bound_type_of(def_id);
- let impl_trait_ref = self.tcx().bound_impl_trait_ref(def_id);
+ let impl_trait_ref = self.tcx().impl_trait_ref(def_id);
let (self_ty, impl_trait_ref) = if substs.len() >= generics.count() {
(
self_ty.subst(self.tcx(), substs),
use crate::ty::visit::ValidateBoundVars;
use crate::ty::InferTy::*;
use crate::ty::{
- self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable,
- TypeVisitor,
+ self, AdtDef, DefIdTree, Discr, FallibleTypeFolder, Term, Ty, TyCtxt, TypeFlags, TypeFoldable,
+ TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor,
};
use crate::ty::{List, ParamEnv};
use hir::def::DefKind;
if self.0.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) }
}
+ pub fn no_bound_vars_ignoring_escaping(self, tcx: TyCtxt<'tcx>) -> Option<T>
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ if !self.0.has_escaping_bound_vars() {
+ Some(self.skip_binder())
+ } else {
+ self.0.try_fold_with(&mut SkipBindersAt { index: ty::INNERMOST, tcx }).ok()
+ }
+ }
+
/// Splits the contents into two things that share the same binder
/// level as the original, returning two distinct binders.
///
}
}
+struct SkipBindersAt<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ index: ty::DebruijnIndex,
+}
+
+impl<'tcx> FallibleTypeFolder<'tcx> for SkipBindersAt<'tcx> {
+ type Error = ();
+
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, Self::Error>
+ where
+ T: ty::TypeFoldable<'tcx>,
+ {
+ self.index.shift_in(1);
+ let value = t.try_map_bound(|t| t.try_fold_with(self));
+ self.index.shift_out(1);
+ value
+ }
+
+ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ if !ty.has_escaping_bound_vars() {
+ Ok(ty)
+ } else if let ty::Bound(index, bv) = *ty.kind() {
+ if index == self.index {
+ Err(())
+ } else {
+ Ok(self.tcx().mk_ty(ty::Bound(index.shifted_out(1), bv)))
+ }
+ } else {
+ ty.try_super_fold_with(self)
+ }
+ }
+
+ fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ if !r.has_escaping_bound_vars() {
+ Ok(r)
+ } else if let ty::ReLateBound(index, bv) = r.kind() {
+ if index == self.index {
+ Err(())
+ } else {
+ Ok(self.tcx().mk_region(ty::ReLateBound(index.shifted_out(1), bv)))
+ }
+ } else {
+ r.try_super_fold_with(self)
+ }
+ }
+
+ fn try_fold_const(&mut self, ct: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
+ if !ct.has_escaping_bound_vars() {
+ Ok(ct)
+ } else if let ty::ConstKind::Bound(index, bv) = ct.kind() {
+ if index == self.index {
+ Err(())
+ } else {
+ Ok(self.tcx().mk_const(
+ ty::ConstKind::Bound(index.shifted_out(1), bv),
+ ct.ty().try_fold_with(self)?,
+ ))
+ }
+ } else {
+ ct.try_super_fold_with(self)
+ }
+ }
+
+ fn try_fold_predicate(
+ &mut self,
+ p: ty::Predicate<'tcx>,
+ ) -> Result<ty::Predicate<'tcx>, Self::Error> {
+ if !p.has_escaping_bound_vars() { Ok(p) } else { p.try_super_fold_with(self) }
+ }
+}
+
/// Represents the projection of an associated type.
///
/// For a projection, this would be `<Ty as Trait<...>>::N`.
}
}
+impl<'tcx, I: IntoIterator> ExactSizeIterator for SubstIter<'_, 'tcx, I>
+where
+ I::IntoIter: ExactSizeIterator,
+ I::Item: TypeFoldable<'tcx>,
+{
+}
+
impl<'tcx, 's, I: IntoIterator> EarlyBinder<I>
where
I::Item: Deref,
}
}
+impl<'tcx, I: IntoIterator> ExactSizeIterator for SubstIterCopied<'_, 'tcx, I>
+where
+ I::IntoIter: ExactSizeIterator,
+ I::Item: Deref,
+ <I::Item as Deref>::Target: Copy + TypeFoldable<'tcx>,
+{
+}
+
pub struct EarlyBinderIter<T> {
t: T,
}
let mut folder = SubstFolder { tcx, substs, binders_passed: 0 };
self.0.fold_with(&mut folder)
}
+
+ pub fn subst_identity(self) -> T {
+ self.0
+ }
}
///////////////////////////////////////////////////////////////////////////
pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
/// We sometimes treat byte string literals (which are of type `&[u8; N]`)
- /// as `&[u8]`, depending on the pattern in which they are used.
+ /// as `&[u8]`, depending on the pattern in which they are used.
/// This hashset records all instances where we behave
/// like this to allow `const_to_pat` to reliably handle this situation.
pub treat_byte_string_as_slice: ItemLocalSet,
ty::EarlyBinder(self.fn_sig(def_id))
}
- pub fn bound_impl_trait_ref(
- self,
- def_id: DefId,
- ) -> Option<ty::EarlyBinder<ty::TraitRef<'tcx>>> {
- self.impl_trait_ref(def_id).map(|i| ty::EarlyBinder(i))
- }
-
pub fn bound_explicit_item_bounds(
self,
def_id: DefId,
ty::EarlyBinder(self.item_bounds(def_id))
}
- pub fn bound_const_param_default(self, def_id: DefId) -> ty::EarlyBinder<ty::Const<'tcx>> {
- ty::EarlyBinder(self.const_param_default(def_id))
- }
-
- pub fn bound_predicates_of(
- self,
- def_id: DefId,
- ) -> ty::EarlyBinder<ty::generics::GenericPredicates<'tcx>> {
- ty::EarlyBinder(self.predicates_of(def_id))
- }
-
- pub fn bound_explicit_predicates_of(
- self,
- def_id: DefId,
- ) -> ty::EarlyBinder<ty::generics::GenericPredicates<'tcx>> {
- ty::EarlyBinder(self.explicit_predicates_of(def_id))
- }
-
pub fn bound_impl_subject(self, def_id: DefId) -> ty::EarlyBinder<ty::ImplSubject<'tcx>> {
ty::EarlyBinder(self.impl_subject(def_id))
}
}
}
+impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<Ty<'_>> {
+ fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self {
+ ty::EarlyBinder(Ty::from_cycle_error(tcx, cycle))
+ }
+}
+
+impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>> {
+ fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self {
+ ty::EarlyBinder(ty::Binder::from_cycle_error(tcx, cycle))
+ }
+}
+
// item_and_field_ids should form a cycle where each field contains the
// type in the next element in the list
pub fn recursive_type_error(
destination
};
+ // Always create a local to hold the destination, as `RETURN_PLACE` may appear
+ // where a full `Place` is not allowed.
+ let (remap_destination, destination_local) = if let Some(d) = dest.as_local() {
+ (false, d)
+ } else {
+ (
+ true,
+ self.new_call_temp(
+ caller_body,
+ &callsite,
+ destination.ty(caller_body, self.tcx).ty,
+ ),
+ )
+ };
+
// Copy the arguments if needed.
let args: Vec<_> = self.make_call_args(args, &callsite, caller_body, &callee_body);
new_locals: Local::new(caller_body.local_decls.len())..,
new_scopes: SourceScope::new(caller_body.source_scopes.len())..,
new_blocks: BasicBlock::new(caller_body.basic_blocks.len())..,
- destination: dest,
+ destination: destination_local,
callsite_scope: caller_body.source_scopes[callsite.source_info.scope].clone(),
callsite,
cleanup_block: cleanup,
// To avoid repeated O(n) insert, push any new statements to the end and rotate
// the slice once.
let mut n = 0;
+ if remap_destination {
+ caller_body[block].statements.push(Statement {
+ source_info: callsite.source_info,
+ kind: StatementKind::Assign(Box::new((
+ dest,
+ Rvalue::Use(Operand::Move(destination_local.into())),
+ ))),
+ });
+ n += 1;
+ }
for local in callee_body.vars_and_temps_iter().rev() {
if !callee_body.local_decls[local].internal
&& integrator.always_live_locals.contains(local)
new_locals: RangeFrom<Local>,
new_scopes: RangeFrom<SourceScope>,
new_blocks: RangeFrom<BasicBlock>,
- destination: Place<'tcx>,
+ destination: Local,
callsite_scope: SourceScopeData<'tcx>,
callsite: &'a CallSite<'tcx>,
cleanup_block: Option<BasicBlock>,
impl Integrator<'_, '_> {
fn map_local(&self, local: Local) -> Local {
let new = if local == RETURN_PLACE {
- self.destination.local
+ self.destination
} else {
let idx = local.index() - 1;
if idx < self.args.len() {
*span = span.fresh_expansion(self.expn_data);
}
- fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
- for elem in place.projection {
- // FIXME: Make sure that return place is not used in an indexing projection, since it
- // won't be rebased as it is supposed to be.
- assert_ne!(ProjectionElem::Index(RETURN_PLACE), elem);
- }
-
- // If this is the `RETURN_PLACE`, we need to rebase any projections onto it.
- let dest_proj_len = self.destination.projection.len();
- if place.local == RETURN_PLACE && dest_proj_len > 0 {
- let mut projs = Vec::with_capacity(dest_proj_len + place.projection.len());
- projs.extend(self.destination.projection);
- projs.extend(place.projection);
-
- place.projection = self.tcx.intern_place_elems(&*projs);
- }
- // Handles integrating any locals that occur in the base
- // or projections
- self.super_place(place, context, location)
- }
-
fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
self.in_cleanup_block = data.is_cleanup;
self.super_basic_block_data(block, data);
);
if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) {
+ let trait_ref = trait_ref.subst_identity();
+
let param_env = ty::ParamEnv::reveal_all();
let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref);
let overridden_methods = tcx.impl_item_implementor_ids(item.owner_id);
}
let cursor = Cursor::new(src);
- let string_reader =
- StringReader { sess, start_pos, pos: start_pos, src, cursor, override_span };
+ let string_reader = StringReader {
+ sess,
+ start_pos,
+ pos: start_pos,
+ src,
+ cursor,
+ override_span,
+ nbsp_is_whitespace: false,
+ };
tokentrees::TokenTreesReader::parse_all_token_trees(string_reader)
}
/// Cursor for getting lexer tokens.
cursor: Cursor<'a>,
override_span: Option<Span>,
+ /// When a "unknown start of token: \u{a0}" has already been emitted earlier
+ /// in this file, it's safe to treat further occurrences of the non-breaking
+ /// space character as whitespace.
+ nbsp_is_whitespace: bool,
}
impl<'a> StringReader<'a> {
/// preceded by whitespace.
fn next_token(&mut self) -> (Token, bool) {
let mut preceded_by_whitespace = false;
-
+ let mut swallow_next_invalid = 0;
// Skip trivial (whitespace & comments) tokens
loop {
let token = self.cursor.advance_token();
rustc_lexer::TokenKind::Percent => token::BinOp(token::Percent),
rustc_lexer::TokenKind::Unknown | rustc_lexer::TokenKind::InvalidIdent => {
- let c = self.str_from(start).chars().next().unwrap();
+ // Don't emit diagnostics for sequences of the same invalid token
+ if swallow_next_invalid > 0 {
+ swallow_next_invalid -= 1;
+ continue;
+ }
+ let mut it = self.str_from_to_end(start).chars();
+ let c = it.next().unwrap();
+ if c == '\u{00a0}' {
+ // If an error has already been reported on non-breaking
+ // space characters earlier in the file, treat all
+ // subsequent occurrences as whitespace.
+ if self.nbsp_is_whitespace {
+ preceded_by_whitespace = true;
+ continue;
+ }
+ self.nbsp_is_whitespace = true;
+ }
+ let repeats = it.take_while(|c1| *c1 == c).count();
let mut err =
- self.struct_err_span_char(start, self.pos, "unknown start of token", c);
+ self.struct_err_span_char(start, self.pos + Pos::from_usize(repeats * c.len_utf8()), "unknown start of token", c);
// FIXME: the lexer could be used to turn the ASCII version of unicode
// homoglyphs, instead of keeping a table in `check_for_substitution`into the
// token. Ideally, this should be inside `rustc_lexer`. However, we should
// first remove compound tokens like `<<` from `rustc_lexer`, and then add
// fancier error recovery to it, as there will be less overall work to do this
// way.
- let token = unicode_chars::check_for_substitution(self, start, c, &mut err);
+ let token = unicode_chars::check_for_substitution(self, start, c, &mut err, repeats+1);
if c == '\x00' {
err.help("source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used");
}
+ if repeats > 0 {
+ if repeats == 1 {
+ err.note(format!("character appears once more"));
+ } else {
+ err.note(format!("character appears {repeats} more times"));
+ }
+ swallow_next_invalid = repeats;
+ }
err.emit();
if let Some(token) = token {
token
/// Slice of the source text from `start` up to but excluding `self.pos`,
/// meaning the slice does not include the character `self.ch`.
- fn str_from(&self, start: BytePos) -> &str {
+ fn str_from(&self, start: BytePos) -> &'a str {
self.str_from_to(start, self.pos)
}
}
/// Slice of the source text spanning from `start` up to but excluding `end`.
- fn str_from_to(&self, start: BytePos, end: BytePos) -> &str {
+ fn str_from_to(&self, start: BytePos, end: BytePos) -> &'a str {
&self.src[self.src_index(start)..self.src_index(end)]
}
+ /// Slice of the source text spanning from `start` until the end
+ fn str_from_to_end(&self, start: BytePos) -> &'a str {
+ &self.src[self.src_index(start)..]
+ }
+
fn report_raw_str_error(&self, start: BytePos, prefix_len: u32) -> ! {
match rustc_lexer::validate_raw_str(self.str_from(start), prefix_len) {
Err(RawStrError::InvalidStarter { bad_char }) => {
pos: BytePos,
ch: char,
err: &mut Diagnostic,
+ count: usize,
) -> Option<token::TokenKind> {
let &(_u_char, u_name, ascii_char) = UNICODE_ARRAY.iter().find(|&&(c, _, _)| c == ch)?;
- let span = Span::with_root_ctxt(pos, pos + Pos::from_usize(ch.len_utf8()));
+ let span = Span::with_root_ctxt(pos, pos + Pos::from_usize(ch.len_utf8() * count));
let Some((_ascii_char, ascii_name, token)) = ASCII_ARRAY.iter().find(|&&(c, _, _)| c == ascii_char) else {
let msg = format!("substitution character not found for '{}'", ch);
"Unicode character '{}' ({}) looks like '{}' ({}), but it is not",
ch, u_name, ascii_char, ascii_name
);
- err.span_suggestion(span, &msg, ascii_char, Applicability::MaybeIncorrect);
+ err.span_suggestion(
+ span,
+ &msg,
+ ascii_char.to_string().repeat(count),
+ Applicability::MaybeIncorrect,
+ );
}
token.clone()
}
pub(super) enum LhsExpr {
NotYetParsed,
AttributesParsed(AttrWrapper),
- AlreadyParsed(P<Expr>, bool), // (expr, starts_statement)
+ AlreadyParsed { expr: P<Expr>, starts_statement: bool },
}
impl From<Option<AttrWrapper>> for LhsExpr {
}
impl From<P<Expr>> for LhsExpr {
- /// Converts the `expr: P<Expr>` into `LhsExpr::AlreadyParsed(expr)`.
+ /// Converts the `expr: P<Expr>` into `LhsExpr::AlreadyParsed { expr, starts_statement: false }`.
///
/// This conversion does not allocate.
fn from(expr: P<Expr>) -> Self {
- LhsExpr::AlreadyParsed(expr, false)
+ LhsExpr::AlreadyParsed { expr, starts_statement: false }
}
}
lhs: LhsExpr,
) -> PResult<'a, P<Expr>> {
let mut starts_stmt = false;
- let mut lhs = if let LhsExpr::AlreadyParsed(expr, starts_statement) = lhs {
+ let mut lhs = if let LhsExpr::AlreadyParsed { expr, starts_statement } = lhs {
starts_stmt = starts_statement;
expr
} else {
// Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr()
match this.token.uninterpolate().kind {
- token::Not => make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Not)), // `!expr`
- token::Tilde => make_it!(this, attrs, |this, _| this.recover_tilde_expr(lo)), // `~expr`
+ // `!expr`
+ token::Not => make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Not)),
+ // `~expr`
+ token::Tilde => make_it!(this, attrs, |this, _| this.recover_tilde_expr(lo)),
+ // `-expr`
token::BinOp(token::Minus) => {
make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Neg))
- } // `-expr`
+ }
+ // `*expr`
token::BinOp(token::Star) => {
make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Deref))
- } // `*expr`
+ }
+ // `&expr` and `&&expr`
token::BinOp(token::And) | token::AndAnd => {
make_it!(this, attrs, |this, _| this.parse_borrow_expr(lo))
}
+ // `+lit`
token::BinOp(token::Plus) if this.look_ahead(1, |tok| tok.is_numeric_lit()) => {
let mut err =
LeadingPlusNotSupported { span: lo, remove_plus: None, add_parentheses: None };
this.bump();
this.parse_prefix_expr(None)
- } // `+expr`
+ }
// Recover from `++x`:
token::BinOp(token::Plus)
if this.look_ahead(1, |t| *t == token::BinOp(token::Plus)) =>
Ok((span, self.mk_unary(op, expr)))
}
- // Recover on `!` suggesting for bitwise negation instead.
+ /// Recover on `~expr` in favor of `!expr`.
fn recover_tilde_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
self.sess.emit_err(TildeAsUnaryOperator(lo));
/// Recover on `not expr` in favor of `!expr`.
fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
- // Emit the error...
let negated_token = self.look_ahead(1, |t| t.clone());
let sub_diag = if negated_token.is_numeric_lit() {
),
});
- // ...and recover!
self.parse_unary_expr(lo, UnOp::Not)
}
} else if self.eat(&token::Comma) {
// Vector with two or more elements.
let sep = SeqSep::trailing_allowed(token::Comma);
- let (remaining_exprs, _) = self.parse_seq_to_end(close, sep, |p| p.parse_expr())?;
- let mut exprs = vec![first_expr];
- exprs.extend(remaining_exprs);
+ let (mut exprs, _) = self.parse_seq_to_end(close, sep, |p| p.parse_expr())?;
+ exprs.insert(0, first_expr);
ExprKind::Array(exprs)
} else {
// Vector with one element
vis.0
};
- // Suggestion involves adding a (as of time of writing this, unstable) labeled block.
+ // Suggestion involves adding a labeled block.
//
// If there are no breaks that may use this label, suggest removing the label and
// recover to the unmodified expression.
/// Try to recover the more general form `intersect ::= $pat_lhs @ $pat_rhs`.
///
/// Allowed binding patterns generated by `binding ::= ref? mut? $ident @ $pat_rhs`
- /// should already have been parsed by now at this point,
+ /// should already have been parsed by now at this point,
/// if the next token is `@` then we can try to parse the more general form.
///
/// Consult `parse_pat_ident` for the `binding` grammar.
// Perform this outside of the `collect_tokens_trailing_token` closure,
// since our outer attributes do not apply to this part of the expression
let expr = self.with_res(Restrictions::STMT_EXPR, |this| {
- this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr, true))
+ this.parse_assoc_expr_with(
+ 0,
+ LhsExpr::AlreadyParsed { expr, starts_statement: true },
+ )
})?;
Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Expr(expr)))
} else {
let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac));
let e = self.maybe_recover_from_bad_qpath(e)?;
let e = self.parse_dot_or_call_expr_with(e, lo, attrs)?;
- let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e, false))?;
+ let e = self.parse_assoc_expr_with(
+ 0,
+ LhsExpr::AlreadyParsed { expr: e, starts_statement: false },
+ )?;
StmtKind::Expr(e)
};
Ok(self.mk_stmt(lo.to(hi), kind))
if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of)
&& self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads)
{
- let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap();
+ let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap().subst_identity();
if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind()
&& let Some(adt_def_id) = adt_def.did().as_local()
{
let mut find = FindMin { tcx, effective_visibilities, min: Self::MAX };
find.visit(tcx.type_of(def_id));
if let Some(trait_ref) = tcx.impl_trait_ref(def_id) {
- find.visit_trait(trait_ref);
+ find.visit_trait(trait_ref.subst_identity());
}
find.min
}
GenericParamDefKind::Const { has_default } => {
self.visit(self.ev.tcx.type_of(param.def_id));
if has_default {
- self.visit(self.ev.tcx.const_param_default(param.def_id));
+ self.visit(self.ev.tcx.const_param_default(param.def_id).subst_identity());
}
}
}
fn trait_ref(&mut self) -> &mut Self {
if let Some(trait_ref) = self.ev.tcx.impl_trait_ref(self.item_def_id) {
- self.visit_trait(trait_ref);
+ self.visit_trait(trait_ref.subst_identity());
}
self
}
sugg.to_string(),
Applicability::MaybeIncorrect,
))
- } else if res.is_none() {
+ } else if res.is_none() && matches!(source, PathSource::Type) {
this.report_missing_type_error(path)
} else {
None
}
}
-impl Resolver<'_> {
+impl<'a> Resolver<'a> {
fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
self.node_id_to_def_id.get(&node).copied()
}
self.cstore().item_generics_num_lifetimes(def_id, self.session)
}
}
+
+ pub fn sess(&self) -> &'a Session {
+ self.session
+ }
}
impl<'a> Resolver<'a> {
.map(|s| {
// Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
// where KIND is one of "dylib", "framework", "static", "link-arg" and
- // where MODIFIERS are a comma separated list of supported modifiers
+ // where MODIFIERS are a comma separated list of supported modifiers
// (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
// with either + or - to indicate whether it is enabled or disabled.
// The last value specified for a given modifier wins.
"what location details should be tracked when using caller_location, either \
`none`, or a comma separated list of location details, for which \
valid options are `file`, `line`, and `column` (default: `file,line,column`)"),
+ log_backtrace: Option<String> = (None, parse_opt_string, [TRACKED],
+ "add a backtrace along with logging"),
ls: bool = (false, parse_bool, [UNTRACKED],
"list the symbols defined by a library crate (default: no)"),
macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
unicode-width = "0.1.4"
cfg-if = "1.0"
tracing = "0.1"
-sha1 = { package = "sha-1", version = "0.10.0" }
+sha1 = "0.10.0"
sha2 = "0.10.1"
md5 = { package = "md-5", version = "0.10.0" }
use rustc_data_structures::sync::{AtomicU32, Lrc, MappedReadGuard, ReadGuard, RwLock};
use std::cmp;
use std::hash::Hash;
-use std::path::{Path, PathBuf};
+use std::path::{self, Path, PathBuf};
use std::sync::atomic::Ordering;
use std::fs;
pub fn ensure_source_file_source_present(&self, source_file: Lrc<SourceFile>) -> bool {
source_file.add_external_src(|| {
- match source_file.name {
- FileName::Real(ref name) if let Some(local_path) = name.local_path() => {
- self.file_loader.read_file(local_path).ok()
+ let FileName::Real(ref name) = source_file.name else {
+ return None;
+ };
+
+ let local_path: Cow<'_, Path> = match name {
+ RealFileName::LocalPath(local_path) => local_path.into(),
+ RealFileName::Remapped { local_path: Some(local_path), .. } => local_path.into(),
+ RealFileName::Remapped { local_path: None, virtual_name } => {
+ // The compiler produces better error messages if the sources of dependencies
+ // are available. Attempt to undo any path mapping so we can find remapped
+ // dependencies.
+ // We can only use the heuristic because `add_external_src` checks the file
+ // content hash.
+ self.path_mapping.reverse_map_prefix_heuristically(virtual_name)?.into()
}
- _ => None,
- }
+ };
+
+ self.file_loader.read_file(&local_path).ok()
})
}
}
}
}
+
+ /// Attempts to (heuristically) reverse a prefix mapping.
+ ///
+ /// Returns [`Some`] if there is exactly one mapping where the "to" part is
+ /// a prefix of `path` and has at least one non-empty
+ /// [`Normal`](path::Component::Normal) component. The component
+ /// restriction exists to avoid reverse mapping overly generic paths like
+ /// `/` or `.`).
+ ///
+ /// This is a heuristic and not guaranteed to return the actual original
+ /// path! Do not rely on the result unless you have other means to verify
+ /// that the mapping is correct (e.g. by checking the file content hash).
+ #[instrument(level = "debug", skip(self), ret)]
+ fn reverse_map_prefix_heuristically(&self, path: &Path) -> Option<PathBuf> {
+ let mut found = None;
+
+ for (from, to) in self.mapping.iter() {
+ let has_normal_component = to.components().any(|c| match c {
+ path::Component::Normal(s) => !s.is_empty(),
+ _ => false,
+ });
+
+ if !has_normal_component {
+ continue;
+ }
+
+ let Ok(rest) = path.strip_prefix(to) else {
+ continue;
+ };
+
+ if found.is_some() {
+ return None;
+ }
+
+ found = Some(from.join(rest));
+ }
+
+ found
+ }
}
mapping.map_prefix(path(p)).0.to_string_lossy().to_string()
}
+fn reverse_map_prefix(mapping: &FilePathMapping, p: &str) -> Option<String> {
+ mapping.reverse_map_prefix_heuristically(&path(p)).map(|q| q.to_string_lossy().to_string())
+}
+
#[test]
fn path_prefix_remapping() {
// Relative to relative
);
}
+#[test]
+fn path_prefix_remapping_reverse() {
+ // Ignores options without alphanumeric chars.
+ {
+ let mapping =
+ &FilePathMapping::new(vec![(path("abc"), path("/")), (path("def"), path("."))]);
+
+ assert_eq!(reverse_map_prefix(mapping, "/hello.rs"), None);
+ assert_eq!(reverse_map_prefix(mapping, "./hello.rs"), None);
+ }
+
+ // Returns `None` if multiple options match.
+ {
+ let mapping = &FilePathMapping::new(vec![
+ (path("abc"), path("/redacted")),
+ (path("def"), path("/redacted")),
+ ]);
+
+ assert_eq!(reverse_map_prefix(mapping, "/redacted/hello.rs"), None);
+ }
+
+ // Distinct reverse mappings.
+ {
+ let mapping = &FilePathMapping::new(vec![
+ (path("abc"), path("/redacted")),
+ (path("def/ghi"), path("/fake/dir")),
+ ]);
+
+ assert_eq!(
+ reverse_map_prefix(mapping, "/redacted/path/hello.rs"),
+ Some(path_str("abc/path/hello.rs"))
+ );
+ assert_eq!(
+ reverse_map_prefix(mapping, "/fake/dir/hello.rs"),
+ Some(path_str("def/ghi/hello.rs"))
+ );
+ }
+}
+
#[test]
fn test_next_point() {
let sm = SourceMap::new(FilePathMapping::empty());
}
/// Returns a suggested template modifier to use for this type and an
- /// example of a register named formatted with it.
+ /// example of a register named formatted with it.
///
/// Such suggestions are useful if a type smaller than the full register
/// size is used and a modifier can be used to point to the subregister of
use super::infcx_ext::InferCtxtExt;
use super::{
- fixme_instantiate_canonical_query_response, CanonicalGoal, CanonicalResponse, Certainty,
- EvalCtxt, Goal,
+ instantiate_canonical_query_response, CanonicalGoal, CanonicalResponse, Certainty, EvalCtxt,
+ Goal,
};
use rustc_hir::def_id::DefId;
use rustc_infer::infer::TyCtxtInferExt;
// canonical wrt the caller.
for Candidate { source, result } in normalized_candidates {
self.infcx.probe(|_| {
- let candidate_certainty = fixme_instantiate_canonical_query_response(
- &self.infcx,
- &orig_values,
- result,
- );
+ let candidate_certainty =
+ instantiate_canonical_query_response(&self.infcx, &orig_values, result);
// FIXME: This is a bit scary if the `normalizes_to_goal` overflows.
//
//! FIXME(@lcnr): Write that section, feel free to ping me if you need help here
//! before then or if I still haven't done that before January 2023.
use super::overflow::OverflowData;
-use super::CanonicalGoal;
+use super::{CanonicalGoal, Certainty, MaybeCause, Response};
use super::{EvalCtxt, QueryResult};
use rustc_data_structures::fx::FxHashMap;
-use rustc_middle::ty::TyCtxt;
+use rustc_infer::infer::canonical::{Canonical, CanonicalVarKind, CanonicalVarValues};
+use rustc_middle::ty::{self, TyCtxt};
use std::{cmp::Ordering, collections::hash_map::Entry};
#[derive(Debug, Clone)]
// No entry, simply push this goal on the stack after dealing with overflow.
Entry::Vacant(v) => {
if self.overflow_data.has_overflow(cache.stack.len()) {
- return Err(self.deal_with_overflow());
+ return Err(self.deal_with_overflow(goal));
}
v.insert(ProvisionalEntry {
- response: fixme_response_yes_no_constraints(),
+ response: response_no_constraints(self.tcx, goal, Certainty::Yes),
depth: cache.stack.len(),
});
cache.stack.push(StackElem { goal, has_been_used: false });
{
Err(entry.response)
} else {
- Err(fixme_response_maybe_no_constraints())
+ Err(response_no_constraints(
+ self.tcx,
+ goal,
+ Certainty::Maybe(MaybeCause::Ambiguity),
+ ))
}
}
}
}
}
-fn fixme_response_yes_no_constraints<'tcx>() -> QueryResult<'tcx> {
- unimplemented!()
-}
+pub(super) fn response_no_constraints<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ goal: Canonical<'tcx, impl Sized>,
+ certainty: Certainty,
+) -> QueryResult<'tcx> {
+ let var_values = goal
+ .variables
+ .iter()
+ .enumerate()
+ .map(|(i, info)| match info.kind {
+ CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => {
+ tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i).into())).into()
+ }
+ CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => {
+ let br = ty::BoundRegion {
+ var: ty::BoundVar::from_usize(i),
+ kind: ty::BrAnon(i as u32, None),
+ };
+ tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
+ }
+ CanonicalVarKind::Const(_, ty) | CanonicalVarKind::PlaceholderConst(_, ty) => tcx
+ .mk_const(ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i)), ty)
+ .into(),
+ })
+ .collect();
-fn fixme_response_maybe_no_constraints<'tcx>() -> QueryResult<'tcx> {
- unimplemented!()
+ Ok(Canonical {
+ max_universe: goal.max_universe,
+ variables: goal.variables,
+ value: Response {
+ var_values: CanonicalVarValues { var_values },
+ external_constraints: Default::default(),
+ certainty,
+ },
+ })
}
let mut errors = Vec::new();
for i in 0.. {
if !infcx.tcx.recursion_limit().value_within_limit(i) {
- unimplemented!("overflow")
+ unimplemented!("overflowed on pending obligations: {:?}", self.obligations);
}
let mut has_changed = false;
use std::mem;
-use rustc_infer::infer::canonical::OriginalQueryValues;
-use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
+use rustc_infer::infer::canonical::{OriginalQueryValues, QueryRegionConstraints, QueryResponse};
+use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::Obligation;
+use rustc_middle::infer::canonical::Certainty as OldCertainty;
use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{RegionOutlivesPredicate, ToPredicate, TypeOutlivesPredicate};
use rustc_span::DUMMY_SP;
+use crate::traits::ObligationCause;
+
+use self::cache::response_no_constraints;
use self::infcx_ext::InferCtxtExt;
mod assembly;
}
/// Additional constraints returned on success.
-#[derive(Debug, PartialEq, Eq, Clone, Hash, TypeFoldable, TypeVisitable)]
+#[derive(Debug, PartialEq, Eq, Clone, Hash, TypeFoldable, TypeVisitable, Default)]
pub struct ExternalConstraints<'tcx> {
// FIXME: implement this.
regions: (),
let canonical_response = self.evaluate_canonical_goal(canonical_goal)?;
Ok((
true, // FIXME: check whether `var_values` are an identity substitution.
- fixme_instantiate_canonical_query_response(infcx, &orig_values, canonical_response),
+ instantiate_canonical_query_response(infcx, &orig_values, canonical_response),
))
}
// of `PredicateKind` this is the case and it is and faster than instantiating and
// recanonicalizing.
let Goal { param_env, predicate } = canonical_goal.value;
- if let Some(kind) = predicate.kind().no_bound_vars() {
+
+ if let Some(kind) = predicate.kind().no_bound_vars_ignoring_escaping(self.tcx) {
match kind {
ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) => self.compute_trait_goal(
canonical_goal.unchecked_rebind(Goal { param_env, predicate }),
| ty::PredicateKind::ConstEvaluatable(_)
| ty::PredicateKind::ConstEquate(_, _)
| ty::PredicateKind::TypeWellFormedFromEnv(_)
- | ty::PredicateKind::Ambiguous => unimplemented!(),
+ | ty::PredicateKind::Ambiguous => {
+ // FIXME
+ response_no_constraints(self.tcx, canonical_goal, Certainty::Yes)
+ }
}
} else {
let (infcx, goal, var_values) =
fn compute_type_outlives_goal(
&mut self,
- _goal: CanonicalGoal<'tcx, TypeOutlivesPredicate<'tcx>>,
+ goal: CanonicalGoal<'tcx, TypeOutlivesPredicate<'tcx>>,
) -> QueryResult<'tcx> {
- todo!()
+ // FIXME
+ response_no_constraints(self.tcx, goal, Certainty::Yes)
}
fn compute_region_outlives_goal(
&mut self,
- _goal: CanonicalGoal<'tcx, RegionOutlivesPredicate<'tcx>>,
+ goal: CanonicalGoal<'tcx, RegionOutlivesPredicate<'tcx>>,
) -> QueryResult<'tcx> {
- todo!()
+ // FIXME
+ response_no_constraints(self.tcx, goal, Certainty::Yes)
}
}
}
}
-fn fixme_instantiate_canonical_query_response<'tcx>(
- _: &InferCtxt<'tcx>,
- _: &OriginalQueryValues<'tcx>,
- _: CanonicalResponse<'tcx>,
+fn instantiate_canonical_query_response<'tcx>(
+ infcx: &InferCtxt<'tcx>,
+ original_values: &OriginalQueryValues<'tcx>,
+ response: CanonicalResponse<'tcx>,
) -> Certainty {
- unimplemented!()
+ let Ok(InferOk { value, obligations }) = infcx
+ .instantiate_query_response_and_region_obligations(
+ &ObligationCause::dummy(),
+ ty::ParamEnv::empty(),
+ original_values,
+ &response.unchecked_map(|resp| QueryResponse {
+ var_values: resp.var_values,
+ region_constraints: QueryRegionConstraints::default(),
+ certainty: match resp.certainty {
+ Certainty::Yes => OldCertainty::Proven,
+ Certainty::Maybe(_) => OldCertainty::Ambiguous,
+ },
+ opaque_types: resp.external_constraints.opaque_types,
+ value: resp.certainty,
+ }),
+ ) else { bug!(); };
+ assert!(obligations.is_empty());
+ value
}
+use rustc_infer::infer::canonical::Canonical;
use rustc_infer::traits::query::NoSolution;
use rustc_middle::ty::TyCtxt;
use rustc_session::Limit;
+use super::cache::response_no_constraints;
use super::{Certainty, EvalCtxt, MaybeCause, QueryResult};
/// When detecting a solver overflow, we return ambiguity. Overflow can be
}
impl<'tcx> EvalCtxt<'tcx> {
- pub(super) fn deal_with_overflow(&mut self) -> QueryResult<'tcx> {
+ pub(super) fn deal_with_overflow(
+ &mut self,
+ goal: Canonical<'tcx, impl Sized>,
+ ) -> QueryResult<'tcx> {
self.overflow_data.deal_with_overflow();
- fixme_response_overflow_no_constraints()
+ response_no_constraints(self.tcx, goal, Certainty::Maybe(MaybeCause::Overflow))
}
/// A `while`-loop which tracks overflow.
Ok(Certainty::Maybe(MaybeCause::Overflow))
}
}
-
-fn fixme_response_overflow_no_constraints<'tcx>() -> QueryResult<'tcx> {
- unimplemented!()
-}
) {
let tcx = acx.cx.tcx;
let goal_trait_ref = goal.predicate.projection_ty.trait_ref(tcx);
- let impl_trait_ref = tcx.bound_impl_trait_ref(impl_def_id).unwrap();
+ let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsPlaceholder };
if iter::zip(goal_trait_ref.substs, impl_trait_ref.skip_binder().substs)
.any(|(goal, imp)| !drcx.generic_args_may_unify(goal, imp))
) {
let tcx = acx.cx.tcx;
- let impl_trait_ref = tcx.bound_impl_trait_ref(impl_def_id).unwrap();
+ let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsPlaceholder };
if iter::zip(goal.predicate.trait_ref.substs, impl_trait_ref.skip_binder().substs)
.any(|(goal, imp)| !drcx.generic_args_may_unify(goal, imp))
let impl1_ref = tcx.impl_trait_ref(impl1_def_id);
let impl2_ref = tcx.impl_trait_ref(impl2_def_id);
let may_overlap = match (impl1_ref, impl2_ref) {
- (Some(a), Some(b)) => iter::zip(a.substs, b.substs)
+ (Some(a), Some(b)) => iter::zip(a.skip_binder().substs, b.skip_binder().substs)
.all(|(arg1, arg2)| drcx.generic_args_may_unify(arg1, arg2)),
(None, None) => {
let self_ty1 = tcx.type_of(impl1_def_id);
let header = ty::ImplHeader {
impl_def_id,
self_ty: tcx.bound_type_of(impl_def_id).subst(tcx, impl_substs),
- trait_ref: tcx.bound_impl_trait_ref(impl_def_id).map(|i| i.subst(tcx, impl_substs)),
+ trait_ref: tcx.impl_trait_ref(impl_def_id).map(|i| i.subst(tcx, impl_substs)),
predicates: tcx.predicates_of(impl_def_id).instantiate(tcx, impl_substs).predicates,
};
// We only except this routine to be invoked on implementations
// of a trait, not inherent implementations.
- let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+ let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity();
debug!("orphan_check: trait_ref={:?}", trait_ref);
// If the *trait* is local to the crate, ok.
ocx.normalize(&ObligationCause::dummy(), param_env, placeholder_obligation.trait_ref);
let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
- let impl_trait_ref = tcx.bound_impl_trait_ref(impl_def_id).unwrap().subst(tcx, impl_substs);
+ let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().subst(tcx, impl_substs);
let impl_trait_ref = ocx.normalize(&ObligationCause::dummy(), param_env, impl_trait_ref);
if let Err(_) =
let predicates =
tcx.predicates_of(obligation.cause.body_id.owner.to_def_id()).instantiate_identity(tcx);
- for obligation in
- elaborate_predicates_with_span(tcx, std::iter::zip(predicates.predicates, predicates.spans))
- {
+ for obligation in elaborate_predicates_with_span(tcx, predicates.into_iter()) {
let kind = obligation.predicate.kind();
if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = kind.skip_binder()
&& param_env_candidate_may_apply(kind.rebind(trait_pred))
})
}
}
+
impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
fn report_fulfillment_errors(
&self,
}
}
- for (error, suppressed) in iter::zip(errors, is_suppressed) {
- if !suppressed {
- self.report_fulfillment_error(error, body_id);
+ for from_expansion in [false, true] {
+ for (error, suppressed) in iter::zip(errors, &is_suppressed) {
+ if !suppressed && error.obligation.cause.span.from_expansion() == from_expansion {
+ self.report_fulfillment_error(error, body_id);
+ }
}
}
let mut suggested =
self.suggest_dereferences(&obligation, &mut err, trait_predicate);
suggested |= self.suggest_fn_call(&obligation, &mut err, trait_predicate);
+ let impl_candidates = self.find_similar_impl_candidates(trait_predicate);
+ suggested = if let &[cand] = &impl_candidates[..] {
+ let cand = cand.trait_ref;
+ if let (ty::FnPtr(_), ty::FnDef(..)) =
+ (cand.self_ty().kind(), trait_ref.self_ty().skip_binder().kind())
+ {
+ err.span_suggestion(
+ span.shrink_to_hi(),
+ format!(
+ "the trait `{}` is implemented for fn pointer `{}`, try casting using `as`",
+ cand.print_only_trait_path(),
+ cand.self_ty(),
+ ),
+ format!(" as {}", cand.self_ty()),
+ Applicability::MaybeIncorrect,
+ );
+ true
+ } else {
+ false
+ }
+ } else {
+ false
+ } || suggested;
suggested |=
self.suggest_remove_reference(&obligation, &mut err, trait_predicate);
suggested |= self.suggest_semicolon_removal(
return None;
}
- let imp = self.tcx.impl_trait_ref(def_id).unwrap();
+ let imp = self.tcx.impl_trait_ref(def_id).unwrap().skip_binder();
self.fuzzy_match_tys(trait_pred.skip_binder().self_ty(), imp.self_ty(), false)
.map(|similarity| ImplCandidate { trait_ref: imp, similarity })
candidates.sort();
candidates.dedup();
let len = candidates.len();
- if candidates.len() == 0 {
+ if candidates.is_empty() {
return false;
}
- if candidates.len() == 1 {
- let ty_desc = match candidates[0].self_ty().kind() {
- ty::FnPtr(_) => Some("fn pointer"),
- _ => None,
- };
- let the_desc = match ty_desc {
- Some(desc) => format!(" implemented for {} `", desc),
- None => " implemented for `".to_string(),
- };
+ if let &[cand] = &candidates[..] {
+ let (desc, mention_castable) =
+ match (cand.self_ty().kind(), trait_ref.self_ty().skip_binder().kind()) {
+ (ty::FnPtr(_), ty::FnDef(..)) => {
+ (" implemented for fn pointer `", ", cast using `as`")
+ }
+ (ty::FnPtr(_), _) => (" implemented for fn pointer `", ""),
+ _ => (" implemented for `", ""),
+ };
err.highlighted_help(vec![
- (
- format!("the trait `{}` ", candidates[0].print_only_trait_path()),
- Style::NoStyle,
- ),
+ (format!("the trait `{}` ", cand.print_only_trait_path()), Style::NoStyle),
("is".to_string(), Style::Highlight),
- (the_desc, Style::NoStyle),
- (candidates[0].self_ty().to_string(), Style::Highlight),
+ (desc.to_string(), Style::NoStyle),
+ (cand.self_ty().to_string(), Style::Highlight),
("`".to_string(), Style::NoStyle),
+ (mention_castable.to_string(), Style::NoStyle),
]);
return true;
}
|| self.tcx.is_builtin_derive(def_id)
})
.filter_map(|def_id| self.tcx.impl_trait_ref(def_id))
+ .map(ty::EarlyBinder::subst_identity)
.filter(|trait_ref| {
let self_ty = trait_ref.self_ty();
// Avoid mentioning type parameters.
}
}
+#[derive(Copy, Clone)]
pub enum DefIdOrName {
DefId(DefId),
Name(&'static str),
self.tcx.for_each_relevant_impl(trait_ref.def_id, trait_self_ty, |def_id| {
let impl_substs = self.fresh_substs_for_item(obligation.cause.span, def_id);
- let impl_trait_ref = tcx.bound_impl_trait_ref(def_id).unwrap().subst(tcx, impl_substs);
+ let impl_trait_ref = tcx.impl_trait_ref(def_id).unwrap().subst(tcx, impl_substs);
let impl_self_ty = impl_trait_ref.self_ty();
trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> bool;
+ fn extract_callable_info(
+ &self,
+ hir_id: HirId,
+ param_env: ty::ParamEnv<'tcx>,
+ found: Ty<'tcx>,
+ ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)>;
+
fn suggest_add_reference_to_arg(
&self,
obligation: &PredicateObligation<'tcx>,
err: &mut Diagnostic,
trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> bool {
+ // It doesn't make sense to make this suggestion outside of typeck...
+ // (also autoderef will ICE...)
+ if self.typeck_results.is_none() {
+ return false;
+ }
+
if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = obligation.predicate.kind().skip_binder()
&& Some(trait_pred.def_id()) == self.tcx.lang_items().sized_trait()
{
return false;
}
- // This is duplicated from `extract_callable_info` in typeck, which
- // relies on autoderef, so we can't use it here.
- let found = trait_pred.self_ty().skip_binder().peel_refs();
- let Some((def_id_or_name, output, inputs)) = (match *found.kind()
- {
- ty::FnPtr(fn_sig) => {
- Some((DefIdOrName::Name("function pointer"), fn_sig.output(), fn_sig.inputs()))
- }
- ty::FnDef(def_id, _) => {
- let fn_sig = found.fn_sig(self.tcx);
- Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs()))
- }
- ty::Closure(def_id, substs) => {
- let fn_sig = substs.as_closure().sig();
- Some((
- DefIdOrName::DefId(def_id),
- fn_sig.output(),
- fn_sig.inputs().map_bound(|inputs| &inputs[1..]),
- ))
- }
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
- self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
- if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
- && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
- // args tuple will always be substs[1]
- && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
- {
- Some((
- DefIdOrName::DefId(def_id),
- pred.kind().rebind(proj.term.ty().unwrap()),
- pred.kind().rebind(args.as_slice()),
- ))
- } else {
- None
- }
- })
- }
- ty::Dynamic(data, _, ty::Dyn) => {
- data.iter().find_map(|pred| {
- if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
- && Some(proj.def_id) == self.tcx.lang_items().fn_once_output()
- // for existential projection, substs are shifted over by 1
- && let ty::Tuple(args) = proj.substs.type_at(0).kind()
- {
- Some((
- DefIdOrName::Name("trait object"),
- pred.rebind(proj.term.ty().unwrap()),
- pred.rebind(args.as_slice()),
- ))
- } else {
- None
- }
- })
- }
- ty::Param(_) => {
- obligation.param_env.caller_bounds().iter().find_map(|pred| {
- if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
- && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
- && proj.projection_ty.self_ty() == found
- // args tuple will always be substs[1]
- && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
- {
- Some((
- DefIdOrName::Name("type parameter"),
- pred.kind().rebind(proj.term.ty().unwrap()),
- pred.kind().rebind(args.as_slice()),
- ))
- } else {
- None
- }
- })
- }
- _ => None,
- }) else { return false; };
- let output = self.replace_bound_vars_with_fresh_vars(
- obligation.cause.span,
+ let self_ty = self.replace_bound_vars_with_fresh_vars(
+ DUMMY_SP,
LateBoundRegionConversionTime::FnCall,
- output,
+ trait_pred.self_ty(),
);
- let inputs = inputs.skip_binder().iter().map(|ty| {
- self.replace_bound_vars_with_fresh_vars(
- obligation.cause.span,
- LateBoundRegionConversionTime::FnCall,
- inputs.rebind(*ty),
- )
- });
+
+ let Some((def_id_or_name, output, inputs)) = self.extract_callable_info(
+ obligation.cause.body_id,
+ obligation.param_env,
+ self_ty,
+ ) else { return false; };
// Remapping bound vars here
let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output));
};
let args = inputs
+ .into_iter()
.map(|ty| {
if ty.is_suggestable(self.tcx, false) {
format!("/* {ty} */")
false
}
+ /// Extracts information about a callable type for diagnostics. This is a
+ /// heuristic -- it doesn't necessarily mean that a type is always callable,
+ /// because the callable type must also be well-formed to be called.
+ fn extract_callable_info(
+ &self,
+ hir_id: HirId,
+ param_env: ty::ParamEnv<'tcx>,
+ found: Ty<'tcx>,
+ ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> {
+ // Autoderef is useful here because sometimes we box callables, etc.
+ let Some((def_id_or_name, output, inputs)) = (self.autoderef_steps)(found).into_iter().find_map(|(found, _)| {
+ match *found.kind() {
+ ty::FnPtr(fn_sig) =>
+ Some((DefIdOrName::Name("function pointer"), fn_sig.output(), fn_sig.inputs())),
+ ty::FnDef(def_id, _) => {
+ let fn_sig = found.fn_sig(self.tcx);
+ Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs()))
+ }
+ ty::Closure(def_id, substs) => {
+ let fn_sig = substs.as_closure().sig();
+ Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs().map_bound(|inputs| &inputs[1..])))
+ }
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
+ self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
+ if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
+ && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
+ // args tuple will always be substs[1]
+ && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
+ {
+ Some((
+ DefIdOrName::DefId(def_id),
+ pred.kind().rebind(proj.term.ty().unwrap()),
+ pred.kind().rebind(args.as_slice()),
+ ))
+ } else {
+ None
+ }
+ })
+ }
+ ty::Dynamic(data, _, ty::Dyn) => {
+ data.iter().find_map(|pred| {
+ if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
+ && Some(proj.def_id) == self.tcx.lang_items().fn_once_output()
+ // for existential projection, substs are shifted over by 1
+ && let ty::Tuple(args) = proj.substs.type_at(0).kind()
+ {
+ Some((
+ DefIdOrName::Name("trait object"),
+ pred.rebind(proj.term.ty().unwrap()),
+ pred.rebind(args.as_slice()),
+ ))
+ } else {
+ None
+ }
+ })
+ }
+ ty::Param(param) => {
+ let generics = self.tcx.generics_of(hir_id.owner.to_def_id());
+ let name = if generics.count() > param.index as usize
+ && let def = generics.param_at(param.index as usize, self.tcx)
+ && matches!(def.kind, ty::GenericParamDefKind::Type { .. })
+ && def.name == param.name
+ {
+ DefIdOrName::DefId(def.def_id)
+ } else {
+ DefIdOrName::Name("type parameter")
+ };
+ param_env.caller_bounds().iter().find_map(|pred| {
+ if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
+ && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
+ && proj.projection_ty.self_ty() == found
+ // args tuple will always be substs[1]
+ && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
+ {
+ Some((
+ name,
+ pred.kind().rebind(proj.term.ty().unwrap()),
+ pred.kind().rebind(args.as_slice()),
+ ))
+ } else {
+ None
+ }
+ })
+ }
+ _ => None,
+ }
+ }) else { return None; };
+
+ let output = self.replace_bound_vars_with_fresh_vars(
+ DUMMY_SP,
+ LateBoundRegionConversionTime::FnCall,
+ output,
+ );
+ let inputs = inputs
+ .skip_binder()
+ .iter()
+ .map(|ty| {
+ self.replace_bound_vars_with_fresh_vars(
+ DUMMY_SP,
+ LateBoundRegionConversionTime::FnCall,
+ inputs.rebind(*ty),
+ )
+ })
+ .collect();
+
+ // We don't want to register any extra obligations, which should be
+ // implied by wf, but also because that would possibly result in
+ // erroneous errors later on.
+ let InferOk { value: output, obligations: _ } =
+ self.at(&ObligationCause::dummy(), param_env).normalize(output);
+
+ if output.is_ty_var() { None } else { Some((def_id_or_name, output, inputs)) }
+ }
+
fn suggest_add_reference_to_arg(
&self,
obligation: &PredicateObligation<'tcx>,
// Find another predicate whose self-type is equal to the expected self type,
// but whose substs don't match.
- let other_pred = std::iter::zip(&predicates.predicates, &predicates.spans)
+ let other_pred = predicates.into_iter()
.enumerate()
.find(|(other_idx, (pred, _))| match pred.kind().skip_binder() {
ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred))
// If we found one, then it's very likely the cause of the error.
if let Some((_, (_, other_pred_span))) = other_pred {
err.span_note(
- *other_pred_span,
+ other_pred_span,
"closure inferred to have a different signature due to this bound",
);
}
param_env: ty::ParamEnv<'tcx>,
generic_bounds: ty::InstantiatedPredicates<'tcx>,
) -> impl Iterator<Item = PredicateObligation<'tcx>> {
- std::iter::zip(generic_bounds.predicates, generic_bounds.spans).enumerate().map(
- move |(idx, (predicate, span))| Obligation {
- cause: cause(idx, span),
- recursion_depth: 0,
- param_env,
- predicate,
- },
- )
+ generic_bounds.into_iter().enumerate().map(move |(idx, (predicate, span))| Obligation {
+ cause: cause(idx, span),
+ recursion_depth: 0,
+ param_env,
+ predicate,
+ })
}
/// Determines whether the type `ty` is known to meet `bound` and
// the `TypeOutlives` predicates first inside the unnormalized parameter environment, and
// then we normalize the `TypeOutlives` bounds inside the normalized parameter environment.
//
- // This works fairly well because trait matching does not actually care about param-env
+ // This works fairly well because trait matching does not actually care about param-env
// TypeOutlives predicates - these are normally used by regionck.
let outlives_predicates: Vec<_> = predicates
.drain_filter(|predicate| {
let generics = tcx.generics_of(trait_item_def_id);
let predicates = tcx.predicates_of(trait_item_def_id);
- let impl_trait_ref =
- tcx.impl_trait_ref(impl_def_id).expect("expected impl to correspond to trait");
+ let impl_trait_ref = tcx
+ .impl_trait_ref(impl_def_id)
+ .expect("expected impl to correspond to trait")
+ .subst_identity();
let param_env = tcx.param_env(impl_def_id);
let mut visitor = ReferencesOnlyParentGenerics { tcx, generics, trait_item_def_id };
tcx.predicates_of(impl_fn_def_id).instantiate(tcx, impl_fn_substs),
&mut obligations,
);
- obligations.extend(std::iter::zip(predicates.predicates, predicates.spans).map(
- |(pred, span)| {
- Obligation::with_depth(
- tcx,
- ObligationCause::new(
- obligation.cause.span,
- obligation.cause.body_id,
- if span.is_dummy() {
- super::ItemObligation(impl_fn_def_id)
- } else {
- super::BindingObligation(impl_fn_def_id, span)
- },
- ),
- obligation.recursion_depth + 1,
- obligation.param_env,
- pred,
- )
- },
- ));
+ obligations.extend(predicates.into_iter().map(|(pred, span)| {
+ Obligation::with_depth(
+ tcx,
+ ObligationCause::new(
+ obligation.cause.span,
+ obligation.cause.body_id,
+ if span.is_dummy() {
+ super::ItemObligation(impl_fn_def_id)
+ } else {
+ super::BindingObligation(impl_fn_def_id, span)
+ },
+ ),
+ obligation.recursion_depth + 1,
+ obligation.param_env,
+ pred,
+ )
+ }));
let ty = normalize_with_depth_to(
selcx,
nested: &mut Vec<PredicateObligation<'tcx>>,
) {
let tcx = selcx.tcx();
- let own = tcx
+ let predicates = tcx
.predicates_of(obligation.predicate.def_id)
.instantiate_own(tcx, obligation.predicate.substs);
- for (predicate, span) in std::iter::zip(own.predicates, own.spans) {
+ for (predicate, span) in predicates {
let normalized = normalize_with_depth_to(
selcx,
obligation.param_env,
// Before we create the substitutions and everything, first
// consider a "quick reject". This avoids creating more types
// and so forth that we need to.
- let impl_trait_ref = self.tcx().bound_impl_trait_ref(impl_def_id).unwrap();
+ let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap();
if self.fast_reject_trait_refs(obligation, &impl_trait_ref.0) {
return;
}
})?);
if let ty::Alias(ty::Projection, ..) = placeholder_self_ty.kind() {
- let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs).predicates;
- debug!(?predicates, "projection predicates");
- for predicate in predicates {
+ let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
+ for (predicate, _) in predicates {
let normalized = normalize_with_depth_to(
self,
obligation.param_env,
impl_def_id: DefId,
obligation: &TraitObligation<'tcx>,
) -> Normalized<'tcx, SubstsRef<'tcx>> {
- let impl_trait_ref = self.tcx().bound_impl_trait_ref(impl_def_id).unwrap();
+ let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap();
match self.match_impl(impl_def_id, impl_trait_ref, obligation) {
Ok(substs) => substs,
Err(()) => {
// obligation will normalize to `<$0 as Iterator>::Item = $1` and
// `$1: Copy`, so we must ensure the obligations are emitted in
// that order.
- let predicates = tcx.bound_predicates_of(def_id);
- debug!(?predicates);
- assert_eq!(predicates.0.parent, None);
- let mut obligations = Vec::with_capacity(predicates.0.predicates.len());
- for (predicate, span) in predicates.0.predicates {
- let span = *span;
+ let predicates = tcx.predicates_of(def_id);
+ assert_eq!(predicates.parent, None);
+ let predicates = predicates.instantiate_own(tcx, substs);
+ let mut obligations = Vec::with_capacity(predicates.len());
+ for (predicate, span) in predicates {
let cause = cause.clone().derived_cause(parent_trait_pred, |derived| {
ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
derived,
param_env,
cause.clone(),
recursion_depth,
- predicates.rebind(*predicate).subst(tcx, substs),
+ predicate,
&mut obligations,
);
obligations.push(Obligation { cause, recursion_depth, param_env, predicate });
param_env, source_impl, source_substs, target_node
);
let source_trait_ref =
- infcx.tcx.bound_impl_trait_ref(source_impl).unwrap().subst(infcx.tcx, &source_substs);
+ infcx.tcx.impl_trait_ref(source_impl).unwrap().subst(infcx.tcx, &source_substs);
// translate the Self and Param parts of the substitution, since those
// vary across impls
// create a parameter environment corresponding to a (placeholder) instantiation of impl1
let penv = tcx.param_env(impl1_def_id);
- let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap();
+ let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap().subst_identity();
// Create an infcx, taking the predicates of impl1 as assumptions:
let infcx = tcx.infer_ctxt().build();
pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String> {
use std::fmt::Write;
- let trait_ref = tcx.impl_trait_ref(impl_def_id)?;
+ let trait_ref = tcx.impl_trait_ref(impl_def_id)?.subst_identity();
let mut w = "impl".to_owned();
let substs = InternalSubsts::identity_for_item(tcx, impl_def_id);
impl<'tcx> ChildrenExt<'tcx> for Children {
/// Insert an impl into this set of children without comparing to any existing impls.
fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) {
- let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+ let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder();
if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsInfer)
{
debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st);
/// an impl with a parent. The impl must be present in the list of
/// children already.
fn remove_existing(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) {
- let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+ let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder();
let vec: &mut Vec<DefId>;
if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsInfer)
{
if le && !ge {
debug!(
"descending as child of TraitRef {:?}",
- tcx.impl_trait_ref(possible_sibling).unwrap()
+ tcx.impl_trait_ref(possible_sibling).unwrap().subst_identity()
);
// The impl specializes `possible_sibling`.
} else if ge && !le {
debug!(
"placing as parent of TraitRef {:?}",
- tcx.impl_trait_ref(possible_sibling).unwrap()
+ tcx.impl_trait_ref(possible_sibling).unwrap().subst_identity()
);
replace_children.push(possible_sibling);
) -> Result<Option<FutureCompatOverlapError<'tcx>>, OverlapError<'tcx>> {
assert!(impl_def_id.is_local());
- let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+ // FIXME: use `EarlyBinder` in `self.children`
+ let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder();
let trait_def_id = trait_ref.def_id;
debug!(
impl_def_id: DefId,
assoc_def_id: DefId,
) -> Result<LeafDef, ErrorGuaranteed> {
- let trait_def_id = tcx.impl_trait_ref(impl_def_id).unwrap().def_id;
+ let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap();
let trait_def = tcx.trait_def(trait_def_id);
// This function may be called while we are still building the
// Note that this method could then never be called, so we
// do not want to try and codegen it, in that case (see #23435).
let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
- if impossible_predicates(tcx, predicates.predicates) {
+ if impossible_predicates(
+ tcx,
+ predicates.map(|(predicate, _)| predicate).collect(),
+ ) {
debug!("vtable_entries: predicates do not hold");
return VtblEntry::Vacant;
}
trace!("{:#?}", predicates);
debug_assert_eq!(predicates.predicates.len(), origins.len());
- iter::zip(iter::zip(predicates.predicates, predicates.spans), origins.into_iter().rev())
+ iter::zip(predicates, origins.into_iter().rev())
.map(|((mut pred, span), origin_def_id)| {
let code = if span.is_dummy() {
traits::ItemObligation(origin_def_id)
//! `crate::chalk::lowering` (to lower rustc types into Chalk types).
use rustc_middle::traits::ChalkRustInterner as RustInterner;
-use rustc_middle::ty::{self, AssocKind, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable};
+use rustc_middle::ty::{self, AssocKind, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable};
use rustc_middle::ty::{InternalSubsts, SubstsRef};
use rustc_target::abi::{Integer, IntegerType};
def_id: DefId,
bound_vars: SubstsRef<'tcx>,
) -> Vec<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>> {
- let predicates = self.interner.tcx.predicates_defined_on(def_id).predicates;
- predicates
- .iter()
- .map(|(wc, _)| EarlyBinder(*wc).subst(self.interner.tcx, bound_vars))
- .filter_map(|wc| LowerInto::<
- Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>
- >::lower_into(wc, self.interner)).collect()
+ self.interner
+ .tcx
+ .predicates_defined_on(def_id)
+ .instantiate_own(self.interner.tcx, bound_vars)
+ .filter_map(|(wc, _)| LowerInto::lower_into(wc, self.interner))
+ .collect()
}
fn bounds_for<T>(&self, def_id: DefId, bound_vars: SubstsRef<'tcx>) -> Vec<T>
let bound_vars = bound_vars_for_item(self.interner.tcx, def_id);
let binders = binders_for(self.interner, bound_vars);
- let trait_ref = self.interner.tcx.bound_impl_trait_ref(def_id).expect("not an impl");
+ let trait_ref = self.interner.tcx.impl_trait_ref(def_id).expect("not an impl");
let trait_ref = trait_ref.subst(self.interner.tcx, bound_vars);
let where_clauses = self.where_clauses_for(def_id, bound_vars);
let all_impls = self.interner.tcx.all_impls(def_id);
let matched_impls = all_impls.filter(|impl_def_id| {
use chalk_ir::could_match::CouldMatch;
- let trait_ref = self.interner.tcx.bound_impl_trait_ref(*impl_def_id).unwrap();
+ let trait_ref = self.interner.tcx.impl_trait_ref(*impl_def_id).unwrap();
let bound_vars = bound_vars_for_item(self.interner.tcx, *impl_def_id);
let self_ty = trait_ref.map_bound(|t| t.self_ty());
let trait_def_id = auto_trait_id.0;
let all_impls = self.interner.tcx.all_impls(trait_def_id);
for impl_def_id in all_impls {
- let trait_ref = self.interner.tcx.impl_trait_ref(impl_def_id).unwrap();
+ let trait_ref = self.interner.tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity();
let self_ty = trait_ref.self_ty();
let provides = match (self_ty.kind(), chalk_ty) {
(&ty::Adt(impl_adt_def, ..), Adt(id, ..)) => impl_adt_def.did() == id.0.did(),
use rustc_trait_selection::traits::query::{Fallible, NoSolution};
use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, ObligationCtxt};
use std::fmt;
-use std::iter::zip;
pub(crate) fn provide(p: &mut Providers) {
*p = Providers {
let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs);
debug!(?instantiated_predicates);
- for (instantiated_predicate, predicate_span) in
- zip(instantiated_predicates.predicates, instantiated_predicates.spans)
- {
+ for (instantiated_predicate, predicate_span) in instantiated_predicates {
let span = if span == DUMMY_SP { predicate_span } else { span };
let cause = ObligationCause::new(
span,
assumed_wf_types.extend(liberated_sig.inputs_and_output);
tcx.intern_type_list(&assumed_wf_types)
}
- DefKind::Impl => match tcx.impl_trait_ref(def_id) {
- Some(trait_ref) => {
- let types: Vec<_> = trait_ref.substs.types().collect();
- tcx.intern_type_list(&types)
+ DefKind::Impl => {
+ match tcx.impl_trait_ref(def_id) {
+ Some(trait_ref) => {
+ let types: Vec<_> = trait_ref.skip_binder().substs.types().collect();
+ tcx.intern_type_list(&types)
+ }
+ // Only the impl self type
+ None => tcx.intern_type_list(&[tcx.type_of(def_id)]),
}
- // Only the impl self type
- None => tcx.intern_type_list(&[tcx.type_of(def_id)]),
- },
+ }
DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.parent(def_id)),
DefKind::Mod
| DefKind::Struct
// In a trait impl, we assume that the header trait ref and all its
// constituents are well-formed.
NodeKind::TraitImpl => {
- let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl");
+ let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl").subst_identity();
// FIXME(chalk): this has problems because of late-bound regions
//inputs.extend(trait_ref.substs.iter().flat_map(|arg| arg.walk()));
let trait_ref = tcx
.impl_trait_ref(def_id)
- .unwrap_or_else(|| bug!("issue33140_self_ty called on inherent impl {:?}", def_id));
+ .unwrap_or_else(|| bug!("issue33140_self_ty called on inherent impl {:?}", def_id))
+ .skip_binder();
debug!("issue33140_self_ty({:?}), trait-ref={:?}", def_id, trait_ref);
mod tests;
extern "Rust" {
- // These are the magic symbols to call the global allocator. rustc generates
+ // These are the magic symbols to call the global allocator. rustc generates
// them to call `__rg_alloc` etc. if there is a `#[global_allocator]` attribute
// (the code expanding that attribute macro generates those functions), or to call
// the default implementations in std (`__rdl_alloc` etc. in `library/std/src/alloc.rs`)
#[cfg(not(no_global_oom_handling))]
extern "Rust" {
- // This is the magic symbol to call the global alloc error handler. rustc generates
+ // This is the magic symbol to call the global alloc error handler. rustc generates
// it to call `__rg_oom` if there is a `#[alloc_error_handler]`, or to call the
// default implementations below (`__rdl_oom`) otherwise.
fn __rust_alloc_error_handler(size: usize, align: usize) -> !;
+++ /dev/null
-//! A priority queue implemented with a binary heap.
-//!
-//! Insertion and popping the largest element have *O*(log(*n*)) time complexity.
-//! Checking the largest element is *O*(1). Converting a vector to a binary heap
-//! can be done in-place, and has *O*(*n*) complexity. A binary heap can also be
-//! converted to a sorted vector in-place, allowing it to be used for an *O*(*n* * log(*n*))
-//! in-place heapsort.
-//!
-//! # Examples
-//!
-//! This is a larger example that implements [Dijkstra's algorithm][dijkstra]
-//! to solve the [shortest path problem][sssp] on a [directed graph][dir_graph].
-//! It shows how to use [`BinaryHeap`] with custom types.
-//!
-//! [dijkstra]: https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
-//! [sssp]: https://en.wikipedia.org/wiki/Shortest_path_problem
-//! [dir_graph]: https://en.wikipedia.org/wiki/Directed_graph
-//!
-//! ```
-//! use std::cmp::Ordering;
-//! use std::collections::BinaryHeap;
-//!
-//! #[derive(Copy, Clone, Eq, PartialEq)]
-//! struct State {
-//! cost: usize,
-//! position: usize,
-//! }
-//!
-//! // The priority queue depends on `Ord`.
-//! // Explicitly implement the trait so the queue becomes a min-heap
-//! // instead of a max-heap.
-//! impl Ord for State {
-//! fn cmp(&self, other: &Self) -> Ordering {
-//! // Notice that the we flip the ordering on costs.
-//! // In case of a tie we compare positions - this step is necessary
-//! // to make implementations of `PartialEq` and `Ord` consistent.
-//! other.cost.cmp(&self.cost)
-//! .then_with(|| self.position.cmp(&other.position))
-//! }
-//! }
-//!
-//! // `PartialOrd` needs to be implemented as well.
-//! impl PartialOrd for State {
-//! fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-//! Some(self.cmp(other))
-//! }
-//! }
-//!
-//! // Each node is represented as a `usize`, for a shorter implementation.
-//! struct Edge {
-//! node: usize,
-//! cost: usize,
-//! }
-//!
-//! // Dijkstra's shortest path algorithm.
-//!
-//! // Start at `start` and use `dist` to track the current shortest distance
-//! // to each node. This implementation isn't memory-efficient as it may leave duplicate
-//! // nodes in the queue. It also uses `usize::MAX` as a sentinel value,
-//! // for a simpler implementation.
-//! fn shortest_path(adj_list: &Vec<Vec<Edge>>, start: usize, goal: usize) -> Option<usize> {
-//! // dist[node] = current shortest distance from `start` to `node`
-//! let mut dist: Vec<_> = (0..adj_list.len()).map(|_| usize::MAX).collect();
-//!
-//! let mut heap = BinaryHeap::new();
-//!
-//! // We're at `start`, with a zero cost
-//! dist[start] = 0;
-//! heap.push(State { cost: 0, position: start });
-//!
-//! // Examine the frontier with lower cost nodes first (min-heap)
-//! while let Some(State { cost, position }) = heap.pop() {
-//! // Alternatively we could have continued to find all shortest paths
-//! if position == goal { return Some(cost); }
-//!
-//! // Important as we may have already found a better way
-//! if cost > dist[position] { continue; }
-//!
-//! // For each node we can reach, see if we can find a way with
-//! // a lower cost going through this node
-//! for edge in &adj_list[position] {
-//! let next = State { cost: cost + edge.cost, position: edge.node };
-//!
-//! // If so, add it to the frontier and continue
-//! if next.cost < dist[next.position] {
-//! heap.push(next);
-//! // Relaxation, we have now found a better way
-//! dist[next.position] = next.cost;
-//! }
-//! }
-//! }
-//!
-//! // Goal not reachable
-//! None
-//! }
-//!
-//! fn main() {
-//! // This is the directed graph we're going to use.
-//! // The node numbers correspond to the different states,
-//! // and the edge weights symbolize the cost of moving
-//! // from one node to another.
-//! // Note that the edges are one-way.
-//! //
-//! // 7
-//! // +-----------------+
-//! // | |
-//! // v 1 2 | 2
-//! // 0 -----> 1 -----> 3 ---> 4
-//! // | ^ ^ ^
-//! // | | 1 | |
-//! // | | | 3 | 1
-//! // +------> 2 -------+ |
-//! // 10 | |
-//! // +---------------+
-//! //
-//! // The graph is represented as an adjacency list where each index,
-//! // corresponding to a node value, has a list of outgoing edges.
-//! // Chosen for its efficiency.
-//! let graph = vec![
-//! // Node 0
-//! vec![Edge { node: 2, cost: 10 },
-//! Edge { node: 1, cost: 1 }],
-//! // Node 1
-//! vec![Edge { node: 3, cost: 2 }],
-//! // Node 2
-//! vec![Edge { node: 1, cost: 1 },
-//! Edge { node: 3, cost: 3 },
-//! Edge { node: 4, cost: 1 }],
-//! // Node 3
-//! vec![Edge { node: 0, cost: 7 },
-//! Edge { node: 4, cost: 2 }],
-//! // Node 4
-//! vec![]];
-//!
-//! assert_eq!(shortest_path(&graph, 0, 1), Some(1));
-//! assert_eq!(shortest_path(&graph, 0, 3), Some(3));
-//! assert_eq!(shortest_path(&graph, 3, 0), Some(7));
-//! assert_eq!(shortest_path(&graph, 0, 4), Some(5));
-//! assert_eq!(shortest_path(&graph, 4, 0), None);
-//! }
-//! ```
-
-#![allow(missing_docs)]
-#![stable(feature = "rust1", since = "1.0.0")]
-
-use core::fmt;
-use core::iter::{FromIterator, FusedIterator, InPlaceIterable, SourceIter, TrustedLen};
-use core::mem::{self, swap, ManuallyDrop};
-use core::ops::{Deref, DerefMut};
-use core::ptr;
-
-use crate::collections::TryReserveError;
-use crate::slice;
-use crate::vec::{self, AsVecIntoIter, Vec};
-
-use super::SpecExtend;
-
-#[cfg(test)]
-mod tests;
-
-/// A priority queue implemented with a binary heap.
-///
-/// This will be a max-heap.
-///
-/// It is a logic error for an item to be modified in such a way that the
-/// item's ordering relative to any other item, as determined by the [`Ord`]
-/// trait, changes while it is in the heap. This is normally only possible
-/// through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. The
-/// behavior resulting from such a logic error is not specified, but will
-/// be encapsulated to the `BinaryHeap` that observed the logic error and not
-/// result in undefined behavior. This could include panics, incorrect results,
-/// aborts, memory leaks, and non-termination.
-///
-/// # Examples
-///
-/// ```
-/// use std::collections::BinaryHeap;
-///
-/// // Type inference lets us omit an explicit type signature (which
-/// // would be `BinaryHeap<i32>` in this example).
-/// let mut heap = BinaryHeap::new();
-///
-/// // We can use peek to look at the next item in the heap. In this case,
-/// // there's no items in there yet so we get None.
-/// assert_eq!(heap.peek(), None);
-///
-/// // Let's add some scores...
-/// heap.push(1);
-/// heap.push(5);
-/// heap.push(2);
-///
-/// // Now peek shows the most important item in the heap.
-/// assert_eq!(heap.peek(), Some(&5));
-///
-/// // We can check the length of a heap.
-/// assert_eq!(heap.len(), 3);
-///
-/// // We can iterate over the items in the heap, although they are returned in
-/// // a random order.
-/// for x in &heap {
-/// println!("{x}");
-/// }
-///
-/// // If we instead pop these scores, they should come back in order.
-/// assert_eq!(heap.pop(), Some(5));
-/// assert_eq!(heap.pop(), Some(2));
-/// assert_eq!(heap.pop(), Some(1));
-/// assert_eq!(heap.pop(), None);
-///
-/// // We can clear the heap of any remaining items.
-/// heap.clear();
-///
-/// // The heap should now be empty.
-/// assert!(heap.is_empty())
-/// ```
-///
-/// A `BinaryHeap` with a known list of items can be initialized from an array:
-///
-/// ```
-/// use std::collections::BinaryHeap;
-///
-/// let heap = BinaryHeap::from([1, 5, 2]);
-/// ```
-///
-/// ## Min-heap
-///
-/// Either [`core::cmp::Reverse`] or a custom [`Ord`] implementation can be used to
-/// make `BinaryHeap` a min-heap. This makes `heap.pop()` return the smallest
-/// value instead of the greatest one.
-///
-/// ```
-/// use std::collections::BinaryHeap;
-/// use std::cmp::Reverse;
-///
-/// let mut heap = BinaryHeap::new();
-///
-/// // Wrap values in `Reverse`
-/// heap.push(Reverse(1));
-/// heap.push(Reverse(5));
-/// heap.push(Reverse(2));
-///
-/// // If we pop these scores now, they should come back in the reverse order.
-/// assert_eq!(heap.pop(), Some(Reverse(1)));
-/// assert_eq!(heap.pop(), Some(Reverse(2)));
-/// assert_eq!(heap.pop(), Some(Reverse(5)));
-/// assert_eq!(heap.pop(), None);
-/// ```
-///
-/// # Time complexity
-///
-/// | [push] | [pop] | [peek]/[peek\_mut] |
-/// |---------|---------------|--------------------|
-/// | *O*(1)~ | *O*(log(*n*)) | *O*(1) |
-///
-/// The value for `push` is an expected cost; the method documentation gives a
-/// more detailed analysis.
-///
-/// [`core::cmp::Reverse`]: core::cmp::Reverse
-/// [`Ord`]: core::cmp::Ord
-/// [`Cell`]: core::cell::Cell
-/// [`RefCell`]: core::cell::RefCell
-/// [push]: BinaryHeap::push
-/// [pop]: BinaryHeap::pop
-/// [peek]: BinaryHeap::peek
-/// [peek\_mut]: BinaryHeap::peek_mut
-#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(test), rustc_diagnostic_item = "BinaryHeap")]
-pub struct BinaryHeap<T> {
- data: Vec<T>,
-}
-
-/// Structure wrapping a mutable reference to the greatest item on a
-/// `BinaryHeap`.
-///
-/// This `struct` is created by the [`peek_mut`] method on [`BinaryHeap`]. See
-/// its documentation for more.
-///
-/// [`peek_mut`]: BinaryHeap::peek_mut
-#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
-pub struct PeekMut<'a, T: 'a + Ord> {
- heap: &'a mut BinaryHeap<T>,
- sift: bool,
-}
-
-#[stable(feature = "collection_debug", since = "1.17.0")]
-impl<T: Ord + fmt::Debug> fmt::Debug for PeekMut<'_, T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_tuple("PeekMut").field(&self.heap.data[0]).finish()
- }
-}
-
-#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
-impl<T: Ord> Drop for PeekMut<'_, T> {
- fn drop(&mut self) {
- if self.sift {
- // SAFETY: PeekMut is only instantiated for non-empty heaps.
- unsafe { self.heap.sift_down(0) };
- }
- }
-}
-
-#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
-impl<T: Ord> Deref for PeekMut<'_, T> {
- type Target = T;
- fn deref(&self) -> &T {
- debug_assert!(!self.heap.is_empty());
- // SAFE: PeekMut is only instantiated for non-empty heaps
- unsafe { self.heap.data.get_unchecked(0) }
- }
-}
-
-#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
-impl<T: Ord> DerefMut for PeekMut<'_, T> {
- fn deref_mut(&mut self) -> &mut T {
- debug_assert!(!self.heap.is_empty());
- self.sift = true;
- // SAFE: PeekMut is only instantiated for non-empty heaps
- unsafe { self.heap.data.get_unchecked_mut(0) }
- }
-}
-
-impl<'a, T: Ord> PeekMut<'a, T> {
- /// Removes the peeked value from the heap and returns it.
- #[stable(feature = "binary_heap_peek_mut_pop", since = "1.18.0")]
- pub fn pop(mut this: PeekMut<'a, T>) -> T {
- let value = this.heap.pop().unwrap();
- this.sift = false;
- value
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Clone> Clone for BinaryHeap<T> {
- fn clone(&self) -> Self {
- BinaryHeap { data: self.data.clone() }
- }
-
- fn clone_from(&mut self, source: &Self) {
- self.data.clone_from(&source.data);
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Ord> Default for BinaryHeap<T> {
- /// Creates an empty `BinaryHeap<T>`.
- #[inline]
- fn default() -> BinaryHeap<T> {
- BinaryHeap::new()
- }
-}
-
-#[stable(feature = "binaryheap_debug", since = "1.4.0")]
-impl<T: fmt::Debug> fmt::Debug for BinaryHeap<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_list().entries(self.iter()).finish()
- }
-}
-
-impl<T: Ord> BinaryHeap<T> {
- /// Creates an empty `BinaryHeap` as a max-heap.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// use std::collections::BinaryHeap;
- /// let mut heap = BinaryHeap::new();
- /// heap.push(4);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[must_use]
- pub fn new() -> BinaryHeap<T> {
- BinaryHeap { data: vec![] }
- }
-
- /// Creates an empty `BinaryHeap` with at least the specified capacity.
- ///
- /// The binary heap will be able to hold at least `capacity` elements without
- /// reallocating. This method is allowed to allocate for more elements than
- /// `capacity`. If `capacity` is 0, the binary heap will not allocate.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// use std::collections::BinaryHeap;
- /// let mut heap = BinaryHeap::with_capacity(10);
- /// heap.push(4);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[must_use]
- pub fn with_capacity(capacity: usize) -> BinaryHeap<T> {
- BinaryHeap { data: Vec::with_capacity(capacity) }
- }
-
- /// Returns a mutable reference to the greatest item in the binary heap, or
- /// `None` if it is empty.
- ///
- /// Note: If the `PeekMut` value is leaked, the heap may be in an
- /// inconsistent state.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// use std::collections::BinaryHeap;
- /// let mut heap = BinaryHeap::new();
- /// assert!(heap.peek_mut().is_none());
- ///
- /// heap.push(1);
- /// heap.push(5);
- /// heap.push(2);
- /// {
- /// let mut val = heap.peek_mut().unwrap();
- /// *val = 0;
- /// }
- /// assert_eq!(heap.peek(), Some(&2));
- /// ```
- ///
- /// # Time complexity
- ///
- /// If the item is modified then the worst case time complexity is *O*(log(*n*)),
- /// otherwise it's *O*(1).
- #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
- pub fn peek_mut(&mut self) -> Option<PeekMut<'_, T>> {
- if self.is_empty() { None } else { Some(PeekMut { heap: self, sift: false }) }
- }
-
- /// Removes the greatest item from the binary heap and returns it, or `None` if it
- /// is empty.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// use std::collections::BinaryHeap;
- /// let mut heap = BinaryHeap::from([1, 3]);
- ///
- /// assert_eq!(heap.pop(), Some(3));
- /// assert_eq!(heap.pop(), Some(1));
- /// assert_eq!(heap.pop(), None);
- /// ```
- ///
- /// # Time complexity
- ///
- /// The worst case cost of `pop` on a heap containing *n* elements is *O*(log(*n*)).
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn pop(&mut self) -> Option<T> {
- self.data.pop().map(|mut item| {
- if !self.is_empty() {
- swap(&mut item, &mut self.data[0]);
- // SAFETY: !self.is_empty() means that self.len() > 0
- unsafe { self.sift_down_to_bottom(0) };
- }
- item
- })
- }
-
- /// Pushes an item onto the binary heap.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// use std::collections::BinaryHeap;
- /// let mut heap = BinaryHeap::new();
- /// heap.push(3);
- /// heap.push(5);
- /// heap.push(1);
- ///
- /// assert_eq!(heap.len(), 3);
- /// assert_eq!(heap.peek(), Some(&5));
- /// ```
- ///
- /// # Time complexity
- ///
- /// The expected cost of `push`, averaged over every possible ordering of
- /// the elements being pushed, and over a sufficiently large number of
- /// pushes, is *O*(1). This is the most meaningful cost metric when pushing
- /// elements that are *not* already in any sorted pattern.
- ///
- /// The time complexity degrades if elements are pushed in predominantly
- /// ascending order. In the worst case, elements are pushed in ascending
- /// sorted order and the amortized cost per push is *O*(log(*n*)) against a heap
- /// containing *n* elements.
- ///
- /// The worst case cost of a *single* call to `push` is *O*(*n*). The worst case
- /// occurs when capacity is exhausted and needs a resize. The resize cost
- /// has been amortized in the previous figures.
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn push(&mut self, item: T) {
- let old_len = self.len();
- self.data.push(item);
- // SAFETY: Since we pushed a new item it means that
- // old_len = self.len() - 1 < self.len()
- unsafe { self.sift_up(0, old_len) };
- }
-
- /// Consumes the `BinaryHeap` and returns a vector in sorted
- /// (ascending) order.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// use std::collections::BinaryHeap;
- ///
- /// let mut heap = BinaryHeap::from([1, 2, 4, 5, 7]);
- /// heap.push(6);
- /// heap.push(3);
- ///
- /// let vec = heap.into_sorted_vec();
- /// assert_eq!(vec, [1, 2, 3, 4, 5, 6, 7]);
- /// ```
- #[must_use = "`self` will be dropped if the result is not used"]
- #[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
- pub fn into_sorted_vec(mut self) -> Vec<T> {
- let mut end = self.len();
- while end > 1 {
- end -= 1;
- // SAFETY: `end` goes from `self.len() - 1` to 1 (both included),
- // so it's always a valid index to access.
- // It is safe to access index 0 (i.e. `ptr`), because
- // 1 <= end < self.len(), which means self.len() >= 2.
- unsafe {
- let ptr = self.data.as_mut_ptr();
- ptr::swap(ptr, ptr.add(end));
- }
- // SAFETY: `end` goes from `self.len() - 1` to 1 (both included) so:
- // 0 < 1 <= end <= self.len() - 1 < self.len()
- // Which means 0 < end and end < self.len().
- unsafe { self.sift_down_range(0, end) };
- }
- self.into_vec()
- }
-
- // The implementations of sift_up and sift_down use unsafe blocks in
- // order to move an element out of the vector (leaving behind a
- // hole), shift along the others and move the removed element back into the
- // vector at the final location of the hole.
- // The `Hole` type is used to represent this, and make sure
- // the hole is filled back at the end of its scope, even on panic.
- // Using a hole reduces the constant factor compared to using swaps,
- // which involves twice as many moves.
-
- /// # Safety
- ///
- /// The caller must guarantee that `pos < self.len()`.
- unsafe fn sift_up(&mut self, start: usize, pos: usize) -> usize {
- // Take out the value at `pos` and create a hole.
- // SAFETY: The caller guarantees that pos < self.len()
- let mut hole = unsafe { Hole::new(&mut self.data, pos) };
-
- while hole.pos() > start {
- let parent = (hole.pos() - 1) / 2;
-
- // SAFETY: hole.pos() > start >= 0, which means hole.pos() > 0
- // and so hole.pos() - 1 can't underflow.
- // This guarantees that parent < hole.pos() so
- // it's a valid index and also != hole.pos().
- if hole.element() <= unsafe { hole.get(parent) } {
- break;
- }
-
- // SAFETY: Same as above
- unsafe { hole.move_to(parent) };
- }
-
- hole.pos()
- }
-
- /// Take an element at `pos` and move it down the heap,
- /// while its children are larger.
- ///
- /// # Safety
- ///
- /// The caller must guarantee that `pos < end <= self.len()`.
- unsafe fn sift_down_range(&mut self, pos: usize, end: usize) {
- // SAFETY: The caller guarantees that pos < end <= self.len().
- let mut hole = unsafe { Hole::new(&mut self.data, pos) };
- let mut child = 2 * hole.pos() + 1;
-
- // Loop invariant: child == 2 * hole.pos() + 1.
- while child <= end.saturating_sub(2) {
- // compare with the greater of the two children
- // SAFETY: child < end - 1 < self.len() and
- // child + 1 < end <= self.len(), so they're valid indexes.
- // child == 2 * hole.pos() + 1 != hole.pos() and
- // child + 1 == 2 * hole.pos() + 2 != hole.pos().
- // FIXME: 2 * hole.pos() + 1 or 2 * hole.pos() + 2 could overflow
- // if T is a ZST
- child += unsafe { hole.get(child) <= hole.get(child + 1) } as usize;
-
- // if we are already in order, stop.
- // SAFETY: child is now either the old child or the old child+1
- // We already proven that both are < self.len() and != hole.pos()
- if hole.element() >= unsafe { hole.get(child) } {
- return;
- }
-
- // SAFETY: same as above.
- unsafe { hole.move_to(child) };
- child = 2 * hole.pos() + 1;
- }
-
- // SAFETY: && short circuit, which means that in the
- // second condition it's already true that child == end - 1 < self.len().
- if child == end - 1 && hole.element() < unsafe { hole.get(child) } {
- // SAFETY: child is already proven to be a valid index and
- // child == 2 * hole.pos() + 1 != hole.pos().
- unsafe { hole.move_to(child) };
- }
- }
-
- /// # Safety
- ///
- /// The caller must guarantee that `pos < self.len()`.
- unsafe fn sift_down(&mut self, pos: usize) {
- let len = self.len();
- // SAFETY: pos < len is guaranteed by the caller and
- // obviously len = self.len() <= self.len().
- unsafe { self.sift_down_range(pos, len) };
- }
-
- /// Take an element at `pos` and move it all the way down the heap,
- /// then sift it up to its position.
- ///
- /// Note: This is faster when the element is known to be large / should
- /// be closer to the bottom.
- ///
- /// # Safety
- ///
- /// The caller must guarantee that `pos < self.len()`.
- unsafe fn sift_down_to_bottom(&mut self, mut pos: usize) {
- let end = self.len();
- let start = pos;
-
- // SAFETY: The caller guarantees that pos < self.len().
- let mut hole = unsafe { Hole::new(&mut self.data, pos) };
- let mut child = 2 * hole.pos() + 1;
-
- // Loop invariant: child == 2 * hole.pos() + 1.
- while child <= end.saturating_sub(2) {
- // SAFETY: child < end - 1 < self.len() and
- // child + 1 < end <= self.len(), so they're valid indexes.
- // child == 2 * hole.pos() + 1 != hole.pos() and
- // child + 1 == 2 * hole.pos() + 2 != hole.pos().
- // FIXME: 2 * hole.pos() + 1 or 2 * hole.pos() + 2 could overflow
- // if T is a ZST
- child += unsafe { hole.get(child) <= hole.get(child + 1) } as usize;
-
- // SAFETY: Same as above
- unsafe { hole.move_to(child) };
- child = 2 * hole.pos() + 1;
- }
-
- if child == end - 1 {
- // SAFETY: child == end - 1 < self.len(), so it's a valid index
- // and child == 2 * hole.pos() + 1 != hole.pos().
- unsafe { hole.move_to(child) };
- }
- pos = hole.pos();
- drop(hole);
-
- // SAFETY: pos is the position in the hole and was already proven
- // to be a valid index.
- unsafe { self.sift_up(start, pos) };
- }
-
- /// Rebuild assuming data[0..start] is still a proper heap.
- fn rebuild_tail(&mut self, start: usize) {
- if start == self.len() {
- return;
- }
-
- let tail_len = self.len() - start;
-
- #[inline(always)]
- fn log2_fast(x: usize) -> usize {
- (usize::BITS - x.leading_zeros() - 1) as usize
- }
-
- // `rebuild` takes O(self.len()) operations
- // and about 2 * self.len() comparisons in the worst case
- // while repeating `sift_up` takes O(tail_len * log(start)) operations
- // and about 1 * tail_len * log_2(start) comparisons in the worst case,
- // assuming start >= tail_len. For larger heaps, the crossover point
- // no longer follows this reasoning and was determined empirically.
- let better_to_rebuild = if start < tail_len {
- true
- } else if self.len() <= 2048 {
- 2 * self.len() < tail_len * log2_fast(start)
- } else {
- 2 * self.len() < tail_len * 11
- };
-
- if better_to_rebuild {
- self.rebuild();
- } else {
- for i in start..self.len() {
- // SAFETY: The index `i` is always less than self.len().
- unsafe { self.sift_up(0, i) };
- }
- }
- }
-
- fn rebuild(&mut self) {
- let mut n = self.len() / 2;
- while n > 0 {
- n -= 1;
- // SAFETY: n starts from self.len() / 2 and goes down to 0.
- // The only case when !(n < self.len()) is if
- // self.len() == 0, but it's ruled out by the loop condition.
- unsafe { self.sift_down(n) };
- }
- }
-
- /// Moves all the elements of `other` into `self`, leaving `other` empty.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// use std::collections::BinaryHeap;
- ///
- /// let mut a = BinaryHeap::from([-10, 1, 2, 3, 3]);
- /// let mut b = BinaryHeap::from([-20, 5, 43]);
- ///
- /// a.append(&mut b);
- ///
- /// assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]);
- /// assert!(b.is_empty());
- /// ```
- #[stable(feature = "binary_heap_append", since = "1.11.0")]
- pub fn append(&mut self, other: &mut Self) {
- if self.len() < other.len() {
- swap(self, other);
- }
-
- let start = self.data.len();
-
- self.data.append(&mut other.data);
-
- self.rebuild_tail(start);
- }
-
- /// Clears the binary heap, returning an iterator over the removed elements
- /// in heap order. If the iterator is dropped before being fully consumed,
- /// it drops the remaining elements in heap order.
- ///
- /// The returned iterator keeps a mutable borrow on the heap to optimize
- /// its implementation.
- ///
- /// Note:
- /// * `.drain_sorted()` is *O*(*n* \* log(*n*)); much slower than `.drain()`.
- /// You should use the latter for most cases.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// #![feature(binary_heap_drain_sorted)]
- /// use std::collections::BinaryHeap;
- ///
- /// let mut heap = BinaryHeap::from([1, 2, 3, 4, 5]);
- /// assert_eq!(heap.len(), 5);
- ///
- /// drop(heap.drain_sorted()); // removes all elements in heap order
- /// assert_eq!(heap.len(), 0);
- /// ```
- #[inline]
- #[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
- pub fn drain_sorted(&mut self) -> DrainSorted<'_, T> {
- DrainSorted { inner: self }
- }
-
- /// Retains only the elements specified by the predicate.
- ///
- /// In other words, remove all elements `e` for which `f(&e)` returns
- /// `false`. The elements are visited in unsorted (and unspecified) order.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// #![feature(binary_heap_retain)]
- /// use std::collections::BinaryHeap;
- ///
- /// let mut heap = BinaryHeap::from([-10, -5, 1, 2, 4, 13]);
- ///
- /// heap.retain(|x| x % 2 == 0); // only keep even numbers
- ///
- /// assert_eq!(heap.into_sorted_vec(), [-10, 2, 4])
- /// ```
- #[unstable(feature = "binary_heap_retain", issue = "71503")]
- pub fn retain<F>(&mut self, mut f: F)
- where
- F: FnMut(&T) -> bool,
- {
- let mut first_removed = self.len();
- let mut i = 0;
- self.data.retain(|e| {
- let keep = f(e);
- if !keep && i < first_removed {
- first_removed = i;
- }
- i += 1;
- keep
- });
- // data[0..first_removed] is untouched, so we only need to rebuild the tail:
- self.rebuild_tail(first_removed);
- }
-}
-
-impl<T> BinaryHeap<T> {
- /// Returns an iterator visiting all values in the underlying vector, in
- /// arbitrary order.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// use std::collections::BinaryHeap;
- /// let heap = BinaryHeap::from([1, 2, 3, 4]);
- ///
- /// // Print 1, 2, 3, 4 in arbitrary order
- /// for x in heap.iter() {
- /// println!("{x}");
- /// }
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn iter(&self) -> Iter<'_, T> {
- Iter { iter: self.data.iter() }
- }
-
- /// Returns an iterator which retrieves elements in heap order.
- /// This method consumes the original heap.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// #![feature(binary_heap_into_iter_sorted)]
- /// use std::collections::BinaryHeap;
- /// let heap = BinaryHeap::from([1, 2, 3, 4, 5]);
- ///
- /// assert_eq!(heap.into_iter_sorted().take(2).collect::<Vec<_>>(), [5, 4]);
- /// ```
- #[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
- pub fn into_iter_sorted(self) -> IntoIterSorted<T> {
- IntoIterSorted { inner: self }
- }
-
- /// Returns the greatest item in the binary heap, or `None` if it is empty.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// use std::collections::BinaryHeap;
- /// let mut heap = BinaryHeap::new();
- /// assert_eq!(heap.peek(), None);
- ///
- /// heap.push(1);
- /// heap.push(5);
- /// heap.push(2);
- /// assert_eq!(heap.peek(), Some(&5));
- ///
- /// ```
- ///
- /// # Time complexity
- ///
- /// Cost is *O*(1) in the worst case.
- #[must_use]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn peek(&self) -> Option<&T> {
- self.data.get(0)
- }
-
- /// Returns the number of elements the binary heap can hold without reallocating.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// use std::collections::BinaryHeap;
- /// let mut heap = BinaryHeap::with_capacity(100);
- /// assert!(heap.capacity() >= 100);
- /// heap.push(4);
- /// ```
- #[must_use]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn capacity(&self) -> usize {
- self.data.capacity()
- }
-
- /// Reserves the minimum capacity for at least `additional` elements more than
- /// the current length. Unlike [`reserve`], this will not
- /// deliberately over-allocate to speculatively avoid frequent allocations.
- /// After calling `reserve_exact`, capacity will be greater than or equal to
- /// `self.len() + additional`. Does nothing if the capacity is already
- /// sufficient.
- ///
- /// [`reserve`]: BinaryHeap::reserve
- ///
- /// # Panics
- ///
- /// Panics if the new capacity overflows [`usize`].
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// use std::collections::BinaryHeap;
- /// let mut heap = BinaryHeap::new();
- /// heap.reserve_exact(100);
- /// assert!(heap.capacity() >= 100);
- /// heap.push(4);
- /// ```
- ///
- /// [`reserve`]: BinaryHeap::reserve
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn reserve_exact(&mut self, additional: usize) {
- self.data.reserve_exact(additional);
- }
-
- /// Reserves capacity for at least `additional` elements more than the
- /// current length. The allocator may reserve more space to speculatively
- /// avoid frequent allocations. After calling `reserve`,
- /// capacity will be greater than or equal to `self.len() + additional`.
- /// Does nothing if capacity is already sufficient.
- ///
- /// # Panics
- ///
- /// Panics if the new capacity overflows [`usize`].
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// use std::collections::BinaryHeap;
- /// let mut heap = BinaryHeap::new();
- /// heap.reserve(100);
- /// assert!(heap.capacity() >= 100);
- /// heap.push(4);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn reserve(&mut self, additional: usize) {
- self.data.reserve(additional);
- }
-
- /// Tries to reserve the minimum capacity for at least `additional` elements
- /// more than the current length. Unlike [`try_reserve`], this will not
- /// deliberately over-allocate to speculatively avoid frequent allocations.
- /// After calling `try_reserve_exact`, capacity will be greater than or
- /// equal to `self.len() + additional` if it returns `Ok(())`.
- /// Does nothing if the capacity is already sufficient.
- ///
- /// Note that the allocator may give the collection more space than it
- /// requests. Therefore, capacity can not be relied upon to be precisely
- /// minimal. Prefer [`try_reserve`] if future insertions are expected.
- ///
- /// [`try_reserve`]: BinaryHeap::try_reserve
- ///
- /// # Errors
- ///
- /// If the capacity overflows, or the allocator reports a failure, then an error
- /// is returned.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::collections::BinaryHeap;
- /// use std::collections::TryReserveError;
- ///
- /// fn find_max_slow(data: &[u32]) -> Result<Option<u32>, TryReserveError> {
- /// let mut heap = BinaryHeap::new();
- ///
- /// // Pre-reserve the memory, exiting if we can't
- /// heap.try_reserve_exact(data.len())?;
- ///
- /// // Now we know this can't OOM in the middle of our complex work
- /// heap.extend(data.iter());
- ///
- /// Ok(heap.pop())
- /// }
- /// # find_max_slow(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
- /// ```
- #[stable(feature = "try_reserve_2", since = "1.63.0")]
- pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
- self.data.try_reserve_exact(additional)
- }
-
- /// Tries to reserve capacity for at least `additional` elements more than the
- /// current length. The allocator may reserve more space to speculatively
- /// avoid frequent allocations. After calling `try_reserve`, capacity will be
- /// greater than or equal to `self.len() + additional` if it returns
- /// `Ok(())`. Does nothing if capacity is already sufficient. This method
- /// preserves the contents even if an error occurs.
- ///
- /// # Errors
- ///
- /// If the capacity overflows, or the allocator reports a failure, then an error
- /// is returned.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::collections::BinaryHeap;
- /// use std::collections::TryReserveError;
- ///
- /// fn find_max_slow(data: &[u32]) -> Result<Option<u32>, TryReserveError> {
- /// let mut heap = BinaryHeap::new();
- ///
- /// // Pre-reserve the memory, exiting if we can't
- /// heap.try_reserve(data.len())?;
- ///
- /// // Now we know this can't OOM in the middle of our complex work
- /// heap.extend(data.iter());
- ///
- /// Ok(heap.pop())
- /// }
- /// # find_max_slow(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
- /// ```
- #[stable(feature = "try_reserve_2", since = "1.63.0")]
- pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
- self.data.try_reserve(additional)
- }
-
- /// Discards as much additional capacity as possible.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// use std::collections::BinaryHeap;
- /// let mut heap: BinaryHeap<i32> = BinaryHeap::with_capacity(100);
- ///
- /// assert!(heap.capacity() >= 100);
- /// heap.shrink_to_fit();
- /// assert!(heap.capacity() == 0);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn shrink_to_fit(&mut self) {
- self.data.shrink_to_fit();
- }
-
- /// Discards capacity with a lower bound.
- ///
- /// The capacity will remain at least as large as both the length
- /// and the supplied value.
- ///
- /// If the current capacity is less than the lower limit, this is a no-op.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::collections::BinaryHeap;
- /// let mut heap: BinaryHeap<i32> = BinaryHeap::with_capacity(100);
- ///
- /// assert!(heap.capacity() >= 100);
- /// heap.shrink_to(10);
- /// assert!(heap.capacity() >= 10);
- /// ```
- #[inline]
- #[stable(feature = "shrink_to", since = "1.56.0")]
- pub fn shrink_to(&mut self, min_capacity: usize) {
- self.data.shrink_to(min_capacity)
- }
-
- /// Returns a slice of all values in the underlying vector, in arbitrary
- /// order.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// #![feature(binary_heap_as_slice)]
- /// use std::collections::BinaryHeap;
- /// use std::io::{self, Write};
- ///
- /// let heap = BinaryHeap::from([1, 2, 3, 4, 5, 6, 7]);
- ///
- /// io::sink().write(heap.as_slice()).unwrap();
- /// ```
- #[must_use]
- #[unstable(feature = "binary_heap_as_slice", issue = "83659")]
- pub fn as_slice(&self) -> &[T] {
- self.data.as_slice()
- }
-
- /// Consumes the `BinaryHeap` and returns the underlying vector
- /// in arbitrary order.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// use std::collections::BinaryHeap;
- /// let heap = BinaryHeap::from([1, 2, 3, 4, 5, 6, 7]);
- /// let vec = heap.into_vec();
- ///
- /// // Will print in some order
- /// for x in vec {
- /// println!("{x}");
- /// }
- /// ```
- #[must_use = "`self` will be dropped if the result is not used"]
- #[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
- pub fn into_vec(self) -> Vec<T> {
- self.into()
- }
-
- /// Returns the length of the binary heap.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// use std::collections::BinaryHeap;
- /// let heap = BinaryHeap::from([1, 3]);
- ///
- /// assert_eq!(heap.len(), 2);
- /// ```
- #[must_use]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn len(&self) -> usize {
- self.data.len()
- }
-
- /// Checks if the binary heap is empty.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// use std::collections::BinaryHeap;
- /// let mut heap = BinaryHeap::new();
- ///
- /// assert!(heap.is_empty());
- ///
- /// heap.push(3);
- /// heap.push(5);
- /// heap.push(1);
- ///
- /// assert!(!heap.is_empty());
- /// ```
- #[must_use]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn is_empty(&self) -> bool {
- self.len() == 0
- }
-
- /// Clears the binary heap, returning an iterator over the removed elements
- /// in arbitrary order. If the iterator is dropped before being fully
- /// consumed, it drops the remaining elements in arbitrary order.
- ///
- /// The returned iterator keeps a mutable borrow on the heap to optimize
- /// its implementation.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// use std::collections::BinaryHeap;
- /// let mut heap = BinaryHeap::from([1, 3]);
- ///
- /// assert!(!heap.is_empty());
- ///
- /// for x in heap.drain() {
- /// println!("{x}");
- /// }
- ///
- /// assert!(heap.is_empty());
- /// ```
- #[inline]
- #[stable(feature = "drain", since = "1.6.0")]
- pub fn drain(&mut self) -> Drain<'_, T> {
- Drain { iter: self.data.drain(..) }
- }
-
- /// Drops all items from the binary heap.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// use std::collections::BinaryHeap;
- /// let mut heap = BinaryHeap::from([1, 3]);
- ///
- /// assert!(!heap.is_empty());
- ///
- /// heap.clear();
- ///
- /// assert!(heap.is_empty());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn clear(&mut self) {
- self.drain();
- }
-}
-
-/// Hole represents a hole in a slice i.e., an index without valid value
-/// (because it was moved from or duplicated).
-/// In drop, `Hole` will restore the slice by filling the hole
-/// position with the value that was originally removed.
-struct Hole<'a, T: 'a> {
- data: &'a mut [T],
- elt: ManuallyDrop<T>,
- pos: usize,
-}
-
-impl<'a, T> Hole<'a, T> {
- /// Create a new `Hole` at index `pos`.
- ///
- /// Unsafe because pos must be within the data slice.
- #[inline]
- unsafe fn new(data: &'a mut [T], pos: usize) -> Self {
- debug_assert!(pos < data.len());
- // SAFE: pos should be inside the slice
- let elt = unsafe { ptr::read(data.get_unchecked(pos)) };
- Hole { data, elt: ManuallyDrop::new(elt), pos }
- }
-
- #[inline]
- fn pos(&self) -> usize {
- self.pos
- }
-
- /// Returns a reference to the element removed.
- #[inline]
- fn element(&self) -> &T {
- &self.elt
- }
-
- /// Returns a reference to the element at `index`.
- ///
- /// Unsafe because index must be within the data slice and not equal to pos.
- #[inline]
- unsafe fn get(&self, index: usize) -> &T {
- debug_assert!(index != self.pos);
- debug_assert!(index < self.data.len());
- unsafe { self.data.get_unchecked(index) }
- }
-
- /// Move hole to new location
- ///
- /// Unsafe because index must be within the data slice and not equal to pos.
- #[inline]
- unsafe fn move_to(&mut self, index: usize) {
- debug_assert!(index != self.pos);
- debug_assert!(index < self.data.len());
- unsafe {
- let ptr = self.data.as_mut_ptr();
- let index_ptr: *const _ = ptr.add(index);
- let hole_ptr = ptr.add(self.pos);
- ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1);
- }
- self.pos = index;
- }
-}
-
-impl<T> Drop for Hole<'_, T> {
- #[inline]
- fn drop(&mut self) {
- // fill the hole again
- unsafe {
- let pos = self.pos;
- ptr::copy_nonoverlapping(&*self.elt, self.data.get_unchecked_mut(pos), 1);
- }
- }
-}
-
-/// An iterator over the elements of a `BinaryHeap`.
-///
-/// This `struct` is created by [`BinaryHeap::iter()`]. See its
-/// documentation for more.
-///
-/// [`iter`]: BinaryHeap::iter
-#[must_use = "iterators are lazy and do nothing unless consumed"]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Iter<'a, T: 'a> {
- iter: slice::Iter<'a, T>,
-}
-
-#[stable(feature = "collection_debug", since = "1.17.0")]
-impl<T: fmt::Debug> fmt::Debug for Iter<'_, T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_tuple("Iter").field(&self.iter.as_slice()).finish()
- }
-}
-
-// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Clone for Iter<'_, T> {
- fn clone(&self) -> Self {
- Iter { iter: self.iter.clone() }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> Iterator for Iter<'a, T> {
- type Item = &'a T;
-
- #[inline]
- fn next(&mut self) -> Option<&'a T> {
- self.iter.next()
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.iter.size_hint()
- }
-
- #[inline]
- fn last(self) -> Option<&'a T> {
- self.iter.last()
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
- #[inline]
- fn next_back(&mut self) -> Option<&'a T> {
- self.iter.next_back()
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> ExactSizeIterator for Iter<'_, T> {
- fn is_empty(&self) -> bool {
- self.iter.is_empty()
- }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<T> FusedIterator for Iter<'_, T> {}
-
-/// An owning iterator over the elements of a `BinaryHeap`.
-///
-/// This `struct` is created by [`BinaryHeap::into_iter()`]
-/// (provided by the [`IntoIterator`] trait). See its documentation for more.
-///
-/// [`into_iter`]: BinaryHeap::into_iter
-/// [`IntoIterator`]: core::iter::IntoIterator
-#[stable(feature = "rust1", since = "1.0.0")]
-#[derive(Clone)]
-pub struct IntoIter<T> {
- iter: vec::IntoIter<T>,
-}
-
-#[stable(feature = "collection_debug", since = "1.17.0")]
-impl<T: fmt::Debug> fmt::Debug for IntoIter<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_tuple("IntoIter").field(&self.iter.as_slice()).finish()
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Iterator for IntoIter<T> {
- type Item = T;
-
- #[inline]
- fn next(&mut self) -> Option<T> {
- self.iter.next()
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.iter.size_hint()
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> DoubleEndedIterator for IntoIter<T> {
- #[inline]
- fn next_back(&mut self) -> Option<T> {
- self.iter.next_back()
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> ExactSizeIterator for IntoIter<T> {
- fn is_empty(&self) -> bool {
- self.iter.is_empty()
- }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<T> FusedIterator for IntoIter<T> {}
-
-// In addition to the SAFETY invariants of the following three unsafe traits
-// also refer to the vec::in_place_collect module documentation to get an overview
-#[unstable(issue = "none", feature = "inplace_iteration")]
-#[doc(hidden)]
-unsafe impl<T> SourceIter for IntoIter<T> {
- type Source = IntoIter<T>;
-
- #[inline]
- unsafe fn as_inner(&mut self) -> &mut Self::Source {
- self
- }
-}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-#[doc(hidden)]
-unsafe impl<I> InPlaceIterable for IntoIter<I> {}
-
-unsafe impl<I> AsVecIntoIter for IntoIter<I> {
- type Item = I;
-
- fn as_into_iter(&mut self) -> &mut vec::IntoIter<Self::Item> {
- &mut self.iter
- }
-}
-
-#[must_use = "iterators are lazy and do nothing unless consumed"]
-#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
-#[derive(Clone, Debug)]
-pub struct IntoIterSorted<T> {
- inner: BinaryHeap<T>,
-}
-
-#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
-impl<T: Ord> Iterator for IntoIterSorted<T> {
- type Item = T;
-
- #[inline]
- fn next(&mut self) -> Option<T> {
- self.inner.pop()
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- let exact = self.inner.len();
- (exact, Some(exact))
- }
-}
-
-#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
-impl<T: Ord> ExactSizeIterator for IntoIterSorted<T> {}
-
-#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
-impl<T: Ord> FusedIterator for IntoIterSorted<T> {}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T: Ord> TrustedLen for IntoIterSorted<T> {}
-
-/// A draining iterator over the elements of a `BinaryHeap`.
-///
-/// This `struct` is created by [`BinaryHeap::drain()`]. See its
-/// documentation for more.
-///
-/// [`drain`]: BinaryHeap::drain
-#[stable(feature = "drain", since = "1.6.0")]
-#[derive(Debug)]
-pub struct Drain<'a, T: 'a> {
- iter: vec::Drain<'a, T>,
-}
-
-#[stable(feature = "drain", since = "1.6.0")]
-impl<T> Iterator for Drain<'_, T> {
- type Item = T;
-
- #[inline]
- fn next(&mut self) -> Option<T> {
- self.iter.next()
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.iter.size_hint()
- }
-}
-
-#[stable(feature = "drain", since = "1.6.0")]
-impl<T> DoubleEndedIterator for Drain<'_, T> {
- #[inline]
- fn next_back(&mut self) -> Option<T> {
- self.iter.next_back()
- }
-}
-
-#[stable(feature = "drain", since = "1.6.0")]
-impl<T> ExactSizeIterator for Drain<'_, T> {
- fn is_empty(&self) -> bool {
- self.iter.is_empty()
- }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<T> FusedIterator for Drain<'_, T> {}
-
-/// A draining iterator over the elements of a `BinaryHeap`.
-///
-/// This `struct` is created by [`BinaryHeap::drain_sorted()`]. See its
-/// documentation for more.
-///
-/// [`drain_sorted`]: BinaryHeap::drain_sorted
-#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
-#[derive(Debug)]
-pub struct DrainSorted<'a, T: Ord> {
- inner: &'a mut BinaryHeap<T>,
-}
-
-#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
-impl<'a, T: Ord> Drop for DrainSorted<'a, T> {
- /// Removes heap elements in heap order.
- fn drop(&mut self) {
- struct DropGuard<'r, 'a, T: Ord>(&'r mut DrainSorted<'a, T>);
-
- impl<'r, 'a, T: Ord> Drop for DropGuard<'r, 'a, T> {
- fn drop(&mut self) {
- while self.0.inner.pop().is_some() {}
- }
- }
-
- while let Some(item) = self.inner.pop() {
- let guard = DropGuard(self);
- drop(item);
- mem::forget(guard);
- }
- }
-}
-
-#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
-impl<T: Ord> Iterator for DrainSorted<'_, T> {
- type Item = T;
-
- #[inline]
- fn next(&mut self) -> Option<T> {
- self.inner.pop()
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- let exact = self.inner.len();
- (exact, Some(exact))
- }
-}
-
-#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
-impl<T: Ord> ExactSizeIterator for DrainSorted<'_, T> {}
-
-#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
-impl<T: Ord> FusedIterator for DrainSorted<'_, T> {}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T: Ord> TrustedLen for DrainSorted<'_, 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();
- heap
- }
-}
-
-#[stable(feature = "std_collections_from_array", since = "1.56.0")]
-impl<T: Ord, const N: usize> From<[T; N]> for BinaryHeap<T> {
- /// ```
- /// use std::collections::BinaryHeap;
- ///
- /// let mut h1 = BinaryHeap::from([1, 4, 2, 3]);
- /// let mut h2: BinaryHeap<_> = [1, 4, 2, 3].into();
- /// while let Some((a, b)) = h1.pop().zip(h2.pop()) {
- /// assert_eq!(a, b);
- /// }
- /// ```
- fn from(arr: [T; N]) -> Self {
- Self::from_iter(arr)
- }
-}
-
-#[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
-impl<T> From<BinaryHeap<T>> for Vec<T> {
- /// Converts a `BinaryHeap<T>` into a `Vec<T>`.
- ///
- /// This conversion requires no data movement or allocation, and has
- /// constant time complexity.
- fn from(heap: BinaryHeap<T>) -> Vec<T> {
- heap.data
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Ord> FromIterator<T> for BinaryHeap<T> {
- fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> BinaryHeap<T> {
- BinaryHeap::from(iter.into_iter().collect::<Vec<_>>())
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> IntoIterator for BinaryHeap<T> {
- type Item = T;
- type IntoIter = IntoIter<T>;
-
- /// Creates a consuming iterator, that is, one that moves each value out of
- /// the binary heap in arbitrary order. The binary heap cannot be used
- /// after calling this.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// use std::collections::BinaryHeap;
- /// let heap = BinaryHeap::from([1, 2, 3, 4]);
- ///
- /// // Print 1, 2, 3, 4 in arbitrary order
- /// for x in heap.into_iter() {
- /// // x has type i32, not &i32
- /// println!("{x}");
- /// }
- /// ```
- fn into_iter(self) -> IntoIter<T> {
- IntoIter { iter: self.data.into_iter() }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> IntoIterator for &'a BinaryHeap<T> {
- type Item = &'a T;
- type IntoIter = Iter<'a, T>;
-
- fn into_iter(self) -> Iter<'a, T> {
- self.iter()
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Ord> Extend<T> for BinaryHeap<T> {
- #[inline]
- fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
- <Self as SpecExtend<I>>::spec_extend(self, iter);
- }
-
- #[inline]
- fn extend_one(&mut self, item: T) {
- self.push(item);
- }
-
- #[inline]
- fn extend_reserve(&mut self, additional: usize) {
- self.reserve(additional);
- }
-}
-
-impl<T: Ord, I: IntoIterator<Item = T>> SpecExtend<I> for BinaryHeap<T> {
- default fn spec_extend(&mut self, iter: I) {
- self.extend_desugared(iter.into_iter());
- }
-}
-
-impl<T: Ord> SpecExtend<Vec<T>> for BinaryHeap<T> {
- fn spec_extend(&mut self, ref mut other: Vec<T>) {
- let start = self.data.len();
- self.data.append(other);
- self.rebuild_tail(start);
- }
-}
-
-impl<T: Ord> SpecExtend<BinaryHeap<T>> for BinaryHeap<T> {
- fn spec_extend(&mut self, ref mut other: BinaryHeap<T>) {
- self.append(other);
- }
-}
-
-impl<T: Ord> BinaryHeap<T> {
- fn extend_desugared<I: IntoIterator<Item = T>>(&mut self, iter: I) {
- let iterator = iter.into_iter();
- let (lower, _) = iterator.size_hint();
-
- self.reserve(lower);
-
- iterator.for_each(move |elem| self.push(elem));
- }
-}
-
-#[stable(feature = "extend_ref", since = "1.2.0")]
-impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BinaryHeap<T> {
- fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
- self.extend(iter.into_iter().cloned());
- }
-
- #[inline]
- fn extend_one(&mut self, &item: &'a T) {
- self.push(item);
- }
-
- #[inline]
- fn extend_reserve(&mut self, additional: usize) {
- self.reserve(additional);
- }
-}
--- /dev/null
+//! A priority queue implemented with a binary heap.
+//!
+//! Insertion and popping the largest element have *O*(log(*n*)) time complexity.
+//! Checking the largest element is *O*(1). Converting a vector to a binary heap
+//! can be done in-place, and has *O*(*n*) complexity. A binary heap can also be
+//! converted to a sorted vector in-place, allowing it to be used for an *O*(*n* * log(*n*))
+//! in-place heapsort.
+//!
+//! # Examples
+//!
+//! This is a larger example that implements [Dijkstra's algorithm][dijkstra]
+//! to solve the [shortest path problem][sssp] on a [directed graph][dir_graph].
+//! It shows how to use [`BinaryHeap`] with custom types.
+//!
+//! [dijkstra]: https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
+//! [sssp]: https://en.wikipedia.org/wiki/Shortest_path_problem
+//! [dir_graph]: https://en.wikipedia.org/wiki/Directed_graph
+//!
+//! ```
+//! use std::cmp::Ordering;
+//! use std::collections::BinaryHeap;
+//!
+//! #[derive(Copy, Clone, Eq, PartialEq)]
+//! struct State {
+//! cost: usize,
+//! position: usize,
+//! }
+//!
+//! // The priority queue depends on `Ord`.
+//! // Explicitly implement the trait so the queue becomes a min-heap
+//! // instead of a max-heap.
+//! impl Ord for State {
+//! fn cmp(&self, other: &Self) -> Ordering {
+//! // Notice that the we flip the ordering on costs.
+//! // In case of a tie we compare positions - this step is necessary
+//! // to make implementations of `PartialEq` and `Ord` consistent.
+//! other.cost.cmp(&self.cost)
+//! .then_with(|| self.position.cmp(&other.position))
+//! }
+//! }
+//!
+//! // `PartialOrd` needs to be implemented as well.
+//! impl PartialOrd for State {
+//! fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+//! Some(self.cmp(other))
+//! }
+//! }
+//!
+//! // Each node is represented as a `usize`, for a shorter implementation.
+//! struct Edge {
+//! node: usize,
+//! cost: usize,
+//! }
+//!
+//! // Dijkstra's shortest path algorithm.
+//!
+//! // Start at `start` and use `dist` to track the current shortest distance
+//! // to each node. This implementation isn't memory-efficient as it may leave duplicate
+//! // nodes in the queue. It also uses `usize::MAX` as a sentinel value,
+//! // for a simpler implementation.
+//! fn shortest_path(adj_list: &Vec<Vec<Edge>>, start: usize, goal: usize) -> Option<usize> {
+//! // dist[node] = current shortest distance from `start` to `node`
+//! let mut dist: Vec<_> = (0..adj_list.len()).map(|_| usize::MAX).collect();
+//!
+//! let mut heap = BinaryHeap::new();
+//!
+//! // We're at `start`, with a zero cost
+//! dist[start] = 0;
+//! heap.push(State { cost: 0, position: start });
+//!
+//! // Examine the frontier with lower cost nodes first (min-heap)
+//! while let Some(State { cost, position }) = heap.pop() {
+//! // Alternatively we could have continued to find all shortest paths
+//! if position == goal { return Some(cost); }
+//!
+//! // Important as we may have already found a better way
+//! if cost > dist[position] { continue; }
+//!
+//! // For each node we can reach, see if we can find a way with
+//! // a lower cost going through this node
+//! for edge in &adj_list[position] {
+//! let next = State { cost: cost + edge.cost, position: edge.node };
+//!
+//! // If so, add it to the frontier and continue
+//! if next.cost < dist[next.position] {
+//! heap.push(next);
+//! // Relaxation, we have now found a better way
+//! dist[next.position] = next.cost;
+//! }
+//! }
+//! }
+//!
+//! // Goal not reachable
+//! None
+//! }
+//!
+//! fn main() {
+//! // This is the directed graph we're going to use.
+//! // The node numbers correspond to the different states,
+//! // and the edge weights symbolize the cost of moving
+//! // from one node to another.
+//! // Note that the edges are one-way.
+//! //
+//! // 7
+//! // +-----------------+
+//! // | |
+//! // v 1 2 | 2
+//! // 0 -----> 1 -----> 3 ---> 4
+//! // | ^ ^ ^
+//! // | | 1 | |
+//! // | | | 3 | 1
+//! // +------> 2 -------+ |
+//! // 10 | |
+//! // +---------------+
+//! //
+//! // The graph is represented as an adjacency list where each index,
+//! // corresponding to a node value, has a list of outgoing edges.
+//! // Chosen for its efficiency.
+//! let graph = vec![
+//! // Node 0
+//! vec![Edge { node: 2, cost: 10 },
+//! Edge { node: 1, cost: 1 }],
+//! // Node 1
+//! vec![Edge { node: 3, cost: 2 }],
+//! // Node 2
+//! vec![Edge { node: 1, cost: 1 },
+//! Edge { node: 3, cost: 3 },
+//! Edge { node: 4, cost: 1 }],
+//! // Node 3
+//! vec![Edge { node: 0, cost: 7 },
+//! Edge { node: 4, cost: 2 }],
+//! // Node 4
+//! vec![]];
+//!
+//! assert_eq!(shortest_path(&graph, 0, 1), Some(1));
+//! assert_eq!(shortest_path(&graph, 0, 3), Some(3));
+//! assert_eq!(shortest_path(&graph, 3, 0), Some(7));
+//! assert_eq!(shortest_path(&graph, 0, 4), Some(5));
+//! assert_eq!(shortest_path(&graph, 4, 0), None);
+//! }
+//! ```
+
+#![allow(missing_docs)]
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use core::fmt;
+use core::iter::{FromIterator, FusedIterator, InPlaceIterable, SourceIter, TrustedLen};
+use core::mem::{self, swap, ManuallyDrop};
+use core::num::NonZeroUsize;
+use core::ops::{Deref, DerefMut};
+use core::ptr;
+
+use crate::collections::TryReserveError;
+use crate::slice;
+use crate::vec::{self, AsVecIntoIter, Vec};
+
+use super::SpecExtend;
+
+#[cfg(test)]
+mod tests;
+
+/// A priority queue implemented with a binary heap.
+///
+/// This will be a max-heap.
+///
+/// It is a logic error for an item to be modified in such a way that the
+/// item's ordering relative to any other item, as determined by the [`Ord`]
+/// trait, changes while it is in the heap. This is normally only possible
+/// through interior mutability, global state, I/O, or unsafe code. The
+/// behavior resulting from such a logic error is not specified, but will
+/// be encapsulated to the `BinaryHeap` that observed the logic error and not
+/// result in undefined behavior. This could include panics, incorrect results,
+/// aborts, memory leaks, and non-termination.
+///
+/// As long as no elements change their relative order while being in the heap
+/// as described above, the API of `BinaryHeap` guarantees that the heap
+/// invariant remains intact i.e. its methods all behave as documented. For
+/// example if a method is documented as iterating in sorted order, that's
+/// guaranteed to work as long as elements in the heap have not changed order,
+/// even in the presence of closures getting unwinded out of, iterators getting
+/// leaked, and similar foolishness.
+///
+/// # Examples
+///
+/// ```
+/// use std::collections::BinaryHeap;
+///
+/// // Type inference lets us omit an explicit type signature (which
+/// // would be `BinaryHeap<i32>` in this example).
+/// let mut heap = BinaryHeap::new();
+///
+/// // We can use peek to look at the next item in the heap. In this case,
+/// // there's no items in there yet so we get None.
+/// assert_eq!(heap.peek(), None);
+///
+/// // Let's add some scores...
+/// heap.push(1);
+/// heap.push(5);
+/// heap.push(2);
+///
+/// // Now peek shows the most important item in the heap.
+/// assert_eq!(heap.peek(), Some(&5));
+///
+/// // We can check the length of a heap.
+/// assert_eq!(heap.len(), 3);
+///
+/// // We can iterate over the items in the heap, although they are returned in
+/// // a random order.
+/// for x in &heap {
+/// println!("{x}");
+/// }
+///
+/// // If we instead pop these scores, they should come back in order.
+/// assert_eq!(heap.pop(), Some(5));
+/// assert_eq!(heap.pop(), Some(2));
+/// assert_eq!(heap.pop(), Some(1));
+/// assert_eq!(heap.pop(), None);
+///
+/// // We can clear the heap of any remaining items.
+/// heap.clear();
+///
+/// // The heap should now be empty.
+/// assert!(heap.is_empty())
+/// ```
+///
+/// A `BinaryHeap` with a known list of items can be initialized from an array:
+///
+/// ```
+/// use std::collections::BinaryHeap;
+///
+/// let heap = BinaryHeap::from([1, 5, 2]);
+/// ```
+///
+/// ## Min-heap
+///
+/// Either [`core::cmp::Reverse`] or a custom [`Ord`] implementation can be used to
+/// make `BinaryHeap` a min-heap. This makes `heap.pop()` return the smallest
+/// value instead of the greatest one.
+///
+/// ```
+/// use std::collections::BinaryHeap;
+/// use std::cmp::Reverse;
+///
+/// let mut heap = BinaryHeap::new();
+///
+/// // Wrap values in `Reverse`
+/// heap.push(Reverse(1));
+/// heap.push(Reverse(5));
+/// heap.push(Reverse(2));
+///
+/// // If we pop these scores now, they should come back in the reverse order.
+/// assert_eq!(heap.pop(), Some(Reverse(1)));
+/// assert_eq!(heap.pop(), Some(Reverse(2)));
+/// assert_eq!(heap.pop(), Some(Reverse(5)));
+/// assert_eq!(heap.pop(), None);
+/// ```
+///
+/// # Time complexity
+///
+/// | [push] | [pop] | [peek]/[peek\_mut] |
+/// |---------|---------------|--------------------|
+/// | *O*(1)~ | *O*(log(*n*)) | *O*(1) |
+///
+/// The value for `push` is an expected cost; the method documentation gives a
+/// more detailed analysis.
+///
+/// [`core::cmp::Reverse`]: core::cmp::Reverse
+/// [`Ord`]: core::cmp::Ord
+/// [`Cell`]: core::cell::Cell
+/// [`RefCell`]: core::cell::RefCell
+/// [push]: BinaryHeap::push
+/// [pop]: BinaryHeap::pop
+/// [peek]: BinaryHeap::peek
+/// [peek\_mut]: BinaryHeap::peek_mut
+#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "BinaryHeap")]
+pub struct BinaryHeap<T> {
+ data: Vec<T>,
+}
+
+/// Structure wrapping a mutable reference to the greatest item on a
+/// `BinaryHeap`.
+///
+/// This `struct` is created by the [`peek_mut`] method on [`BinaryHeap`]. See
+/// its documentation for more.
+///
+/// [`peek_mut`]: BinaryHeap::peek_mut
+#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
+pub struct PeekMut<'a, T: 'a + Ord> {
+ heap: &'a mut BinaryHeap<T>,
+ // If a set_len + sift_down are required, this is Some. If a &mut T has not
+ // yet been exposed to peek_mut()'s caller, it's None.
+ original_len: Option<NonZeroUsize>,
+}
+
+#[stable(feature = "collection_debug", since = "1.17.0")]
+impl<T: Ord + fmt::Debug> fmt::Debug for PeekMut<'_, T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_tuple("PeekMut").field(&self.heap.data[0]).finish()
+ }
+}
+
+#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
+impl<T: Ord> Drop for PeekMut<'_, T> {
+ fn drop(&mut self) {
+ if let Some(original_len) = self.original_len {
+ // SAFETY: That's how many elements were in the Vec at the time of
+ // the PeekMut::deref_mut call, and therefore also at the time of
+ // the BinaryHeap::peek_mut call. Since the PeekMut did not end up
+ // getting leaked, we are now undoing the leak amplification that
+ // the DerefMut prepared for.
+ unsafe { self.heap.data.set_len(original_len.get()) };
+
+ // SAFETY: PeekMut is only instantiated for non-empty heaps.
+ unsafe { self.heap.sift_down(0) };
+ }
+ }
+}
+
+#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
+impl<T: Ord> Deref for PeekMut<'_, T> {
+ type Target = T;
+ fn deref(&self) -> &T {
+ debug_assert!(!self.heap.is_empty());
+ // SAFE: PeekMut is only instantiated for non-empty heaps
+ unsafe { self.heap.data.get_unchecked(0) }
+ }
+}
+
+#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
+impl<T: Ord> DerefMut for PeekMut<'_, T> {
+ fn deref_mut(&mut self) -> &mut T {
+ debug_assert!(!self.heap.is_empty());
+
+ let len = self.heap.len();
+ if len > 1 {
+ // Here we preemptively leak all the rest of the underlying vector
+ // after the currently max element. If the caller mutates the &mut T
+ // we're about to give them, and then leaks the PeekMut, all these
+ // elements will remain leaked. If they don't leak the PeekMut, then
+ // either Drop or PeekMut::pop will un-leak the vector elements.
+ //
+ // This is technique is described throughout several other places in
+ // the standard library as "leak amplification".
+ unsafe {
+ // SAFETY: len > 1 so len != 0.
+ self.original_len = Some(NonZeroUsize::new_unchecked(len));
+ // SAFETY: len > 1 so all this does for now is leak elements,
+ // which is safe.
+ self.heap.data.set_len(1);
+ }
+ }
+
+ // SAFE: PeekMut is only instantiated for non-empty heaps
+ unsafe { self.heap.data.get_unchecked_mut(0) }
+ }
+}
+
+impl<'a, T: Ord> PeekMut<'a, T> {
+ /// Removes the peeked value from the heap and returns it.
+ #[stable(feature = "binary_heap_peek_mut_pop", since = "1.18.0")]
+ pub fn pop(mut this: PeekMut<'a, T>) -> T {
+ if let Some(original_len) = this.original_len.take() {
+ // SAFETY: This is how many elements were in the Vec at the time of
+ // the BinaryHeap::peek_mut call.
+ unsafe { this.heap.data.set_len(original_len.get()) };
+
+ // Unlike in Drop, here we don't also need to do a sift_down even if
+ // the caller could've mutated the element. It is removed from the
+ // heap on the next line and pop() is not sensitive to its value.
+ }
+ this.heap.pop().unwrap()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Clone> Clone for BinaryHeap<T> {
+ fn clone(&self) -> Self {
+ BinaryHeap { data: self.data.clone() }
+ }
+
+ fn clone_from(&mut self, source: &Self) {
+ self.data.clone_from(&source.data);
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Ord> Default for BinaryHeap<T> {
+ /// Creates an empty `BinaryHeap<T>`.
+ #[inline]
+ fn default() -> BinaryHeap<T> {
+ BinaryHeap::new()
+ }
+}
+
+#[stable(feature = "binaryheap_debug", since = "1.4.0")]
+impl<T: fmt::Debug> fmt::Debug for BinaryHeap<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_list().entries(self.iter()).finish()
+ }
+}
+
+impl<T: Ord> BinaryHeap<T> {
+ /// Creates an empty `BinaryHeap` as a max-heap.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// use std::collections::BinaryHeap;
+ /// let mut heap = BinaryHeap::new();
+ /// heap.push(4);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
+ pub fn new() -> BinaryHeap<T> {
+ BinaryHeap { data: vec![] }
+ }
+
+ /// Creates an empty `BinaryHeap` with at least the specified capacity.
+ ///
+ /// The binary heap will be able to hold at least `capacity` elements without
+ /// reallocating. This method is allowed to allocate for more elements than
+ /// `capacity`. If `capacity` is 0, the binary heap will not allocate.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// use std::collections::BinaryHeap;
+ /// let mut heap = BinaryHeap::with_capacity(10);
+ /// heap.push(4);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
+ pub fn with_capacity(capacity: usize) -> BinaryHeap<T> {
+ BinaryHeap { data: Vec::with_capacity(capacity) }
+ }
+
+ /// Returns a mutable reference to the greatest item in the binary heap, or
+ /// `None` if it is empty.
+ ///
+ /// Note: If the `PeekMut` value is leaked, some heap elements might get
+ /// leaked along with it, but the remaining elements will remain a valid
+ /// heap.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// use std::collections::BinaryHeap;
+ /// let mut heap = BinaryHeap::new();
+ /// assert!(heap.peek_mut().is_none());
+ ///
+ /// heap.push(1);
+ /// heap.push(5);
+ /// heap.push(2);
+ /// {
+ /// let mut val = heap.peek_mut().unwrap();
+ /// *val = 0;
+ /// }
+ /// assert_eq!(heap.peek(), Some(&2));
+ /// ```
+ ///
+ /// # Time complexity
+ ///
+ /// If the item is modified then the worst case time complexity is *O*(log(*n*)),
+ /// otherwise it's *O*(1).
+ #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
+ pub fn peek_mut(&mut self) -> Option<PeekMut<'_, T>> {
+ if self.is_empty() { None } else { Some(PeekMut { heap: self, original_len: None }) }
+ }
+
+ /// Removes the greatest item from the binary heap and returns it, or `None` if it
+ /// is empty.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// use std::collections::BinaryHeap;
+ /// let mut heap = BinaryHeap::from([1, 3]);
+ ///
+ /// assert_eq!(heap.pop(), Some(3));
+ /// assert_eq!(heap.pop(), Some(1));
+ /// assert_eq!(heap.pop(), None);
+ /// ```
+ ///
+ /// # Time complexity
+ ///
+ /// The worst case cost of `pop` on a heap containing *n* elements is *O*(log(*n*)).
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn pop(&mut self) -> Option<T> {
+ self.data.pop().map(|mut item| {
+ if !self.is_empty() {
+ swap(&mut item, &mut self.data[0]);
+ // SAFETY: !self.is_empty() means that self.len() > 0
+ unsafe { self.sift_down_to_bottom(0) };
+ }
+ item
+ })
+ }
+
+ /// Pushes an item onto the binary heap.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// use std::collections::BinaryHeap;
+ /// let mut heap = BinaryHeap::new();
+ /// heap.push(3);
+ /// heap.push(5);
+ /// heap.push(1);
+ ///
+ /// assert_eq!(heap.len(), 3);
+ /// assert_eq!(heap.peek(), Some(&5));
+ /// ```
+ ///
+ /// # Time complexity
+ ///
+ /// The expected cost of `push`, averaged over every possible ordering of
+ /// the elements being pushed, and over a sufficiently large number of
+ /// pushes, is *O*(1). This is the most meaningful cost metric when pushing
+ /// elements that are *not* already in any sorted pattern.
+ ///
+ /// The time complexity degrades if elements are pushed in predominantly
+ /// ascending order. In the worst case, elements are pushed in ascending
+ /// sorted order and the amortized cost per push is *O*(log(*n*)) against a heap
+ /// containing *n* elements.
+ ///
+ /// The worst case cost of a *single* call to `push` is *O*(*n*). The worst case
+ /// occurs when capacity is exhausted and needs a resize. The resize cost
+ /// has been amortized in the previous figures.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn push(&mut self, item: T) {
+ let old_len = self.len();
+ self.data.push(item);
+ // SAFETY: Since we pushed a new item it means that
+ // old_len = self.len() - 1 < self.len()
+ unsafe { self.sift_up(0, old_len) };
+ }
+
+ /// Consumes the `BinaryHeap` and returns a vector in sorted
+ /// (ascending) order.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// use std::collections::BinaryHeap;
+ ///
+ /// let mut heap = BinaryHeap::from([1, 2, 4, 5, 7]);
+ /// heap.push(6);
+ /// heap.push(3);
+ ///
+ /// let vec = heap.into_sorted_vec();
+ /// assert_eq!(vec, [1, 2, 3, 4, 5, 6, 7]);
+ /// ```
+ #[must_use = "`self` will be dropped if the result is not used"]
+ #[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
+ pub fn into_sorted_vec(mut self) -> Vec<T> {
+ let mut end = self.len();
+ while end > 1 {
+ end -= 1;
+ // SAFETY: `end` goes from `self.len() - 1` to 1 (both included),
+ // so it's always a valid index to access.
+ // It is safe to access index 0 (i.e. `ptr`), because
+ // 1 <= end < self.len(), which means self.len() >= 2.
+ unsafe {
+ let ptr = self.data.as_mut_ptr();
+ ptr::swap(ptr, ptr.add(end));
+ }
+ // SAFETY: `end` goes from `self.len() - 1` to 1 (both included) so:
+ // 0 < 1 <= end <= self.len() - 1 < self.len()
+ // Which means 0 < end and end < self.len().
+ unsafe { self.sift_down_range(0, end) };
+ }
+ self.into_vec()
+ }
+
+ // The implementations of sift_up and sift_down use unsafe blocks in
+ // order to move an element out of the vector (leaving behind a
+ // hole), shift along the others and move the removed element back into the
+ // vector at the final location of the hole.
+ // The `Hole` type is used to represent this, and make sure
+ // the hole is filled back at the end of its scope, even on panic.
+ // Using a hole reduces the constant factor compared to using swaps,
+ // which involves twice as many moves.
+
+ /// # Safety
+ ///
+ /// The caller must guarantee that `pos < self.len()`.
+ unsafe fn sift_up(&mut self, start: usize, pos: usize) -> usize {
+ // Take out the value at `pos` and create a hole.
+ // SAFETY: The caller guarantees that pos < self.len()
+ let mut hole = unsafe { Hole::new(&mut self.data, pos) };
+
+ while hole.pos() > start {
+ let parent = (hole.pos() - 1) / 2;
+
+ // SAFETY: hole.pos() > start >= 0, which means hole.pos() > 0
+ // and so hole.pos() - 1 can't underflow.
+ // This guarantees that parent < hole.pos() so
+ // it's a valid index and also != hole.pos().
+ if hole.element() <= unsafe { hole.get(parent) } {
+ break;
+ }
+
+ // SAFETY: Same as above
+ unsafe { hole.move_to(parent) };
+ }
+
+ hole.pos()
+ }
+
+ /// Take an element at `pos` and move it down the heap,
+ /// while its children are larger.
+ ///
+ /// # Safety
+ ///
+ /// The caller must guarantee that `pos < end <= self.len()`.
+ unsafe fn sift_down_range(&mut self, pos: usize, end: usize) {
+ // SAFETY: The caller guarantees that pos < end <= self.len().
+ let mut hole = unsafe { Hole::new(&mut self.data, pos) };
+ let mut child = 2 * hole.pos() + 1;
+
+ // Loop invariant: child == 2 * hole.pos() + 1.
+ while child <= end.saturating_sub(2) {
+ // compare with the greater of the two children
+ // SAFETY: child < end - 1 < self.len() and
+ // child + 1 < end <= self.len(), so they're valid indexes.
+ // child == 2 * hole.pos() + 1 != hole.pos() and
+ // child + 1 == 2 * hole.pos() + 2 != hole.pos().
+ // FIXME: 2 * hole.pos() + 1 or 2 * hole.pos() + 2 could overflow
+ // if T is a ZST
+ child += unsafe { hole.get(child) <= hole.get(child + 1) } as usize;
+
+ // if we are already in order, stop.
+ // SAFETY: child is now either the old child or the old child+1
+ // We already proven that both are < self.len() and != hole.pos()
+ if hole.element() >= unsafe { hole.get(child) } {
+ return;
+ }
+
+ // SAFETY: same as above.
+ unsafe { hole.move_to(child) };
+ child = 2 * hole.pos() + 1;
+ }
+
+ // SAFETY: && short circuit, which means that in the
+ // second condition it's already true that child == end - 1 < self.len().
+ if child == end - 1 && hole.element() < unsafe { hole.get(child) } {
+ // SAFETY: child is already proven to be a valid index and
+ // child == 2 * hole.pos() + 1 != hole.pos().
+ unsafe { hole.move_to(child) };
+ }
+ }
+
+ /// # Safety
+ ///
+ /// The caller must guarantee that `pos < self.len()`.
+ unsafe fn sift_down(&mut self, pos: usize) {
+ let len = self.len();
+ // SAFETY: pos < len is guaranteed by the caller and
+ // obviously len = self.len() <= self.len().
+ unsafe { self.sift_down_range(pos, len) };
+ }
+
+ /// Take an element at `pos` and move it all the way down the heap,
+ /// then sift it up to its position.
+ ///
+ /// Note: This is faster when the element is known to be large / should
+ /// be closer to the bottom.
+ ///
+ /// # Safety
+ ///
+ /// The caller must guarantee that `pos < self.len()`.
+ unsafe fn sift_down_to_bottom(&mut self, mut pos: usize) {
+ let end = self.len();
+ let start = pos;
+
+ // SAFETY: The caller guarantees that pos < self.len().
+ let mut hole = unsafe { Hole::new(&mut self.data, pos) };
+ let mut child = 2 * hole.pos() + 1;
+
+ // Loop invariant: child == 2 * hole.pos() + 1.
+ while child <= end.saturating_sub(2) {
+ // SAFETY: child < end - 1 < self.len() and
+ // child + 1 < end <= self.len(), so they're valid indexes.
+ // child == 2 * hole.pos() + 1 != hole.pos() and
+ // child + 1 == 2 * hole.pos() + 2 != hole.pos().
+ // FIXME: 2 * hole.pos() + 1 or 2 * hole.pos() + 2 could overflow
+ // if T is a ZST
+ child += unsafe { hole.get(child) <= hole.get(child + 1) } as usize;
+
+ // SAFETY: Same as above
+ unsafe { hole.move_to(child) };
+ child = 2 * hole.pos() + 1;
+ }
+
+ if child == end - 1 {
+ // SAFETY: child == end - 1 < self.len(), so it's a valid index
+ // and child == 2 * hole.pos() + 1 != hole.pos().
+ unsafe { hole.move_to(child) };
+ }
+ pos = hole.pos();
+ drop(hole);
+
+ // SAFETY: pos is the position in the hole and was already proven
+ // to be a valid index.
+ unsafe { self.sift_up(start, pos) };
+ }
+
+ /// Rebuild assuming data[0..start] is still a proper heap.
+ fn rebuild_tail(&mut self, start: usize) {
+ if start == self.len() {
+ return;
+ }
+
+ let tail_len = self.len() - start;
+
+ #[inline(always)]
+ fn log2_fast(x: usize) -> usize {
+ (usize::BITS - x.leading_zeros() - 1) as usize
+ }
+
+ // `rebuild` takes O(self.len()) operations
+ // and about 2 * self.len() comparisons in the worst case
+ // while repeating `sift_up` takes O(tail_len * log(start)) operations
+ // and about 1 * tail_len * log_2(start) comparisons in the worst case,
+ // assuming start >= tail_len. For larger heaps, the crossover point
+ // no longer follows this reasoning and was determined empirically.
+ let better_to_rebuild = if start < tail_len {
+ true
+ } else if self.len() <= 2048 {
+ 2 * self.len() < tail_len * log2_fast(start)
+ } else {
+ 2 * self.len() < tail_len * 11
+ };
+
+ if better_to_rebuild {
+ self.rebuild();
+ } else {
+ for i in start..self.len() {
+ // SAFETY: The index `i` is always less than self.len().
+ unsafe { self.sift_up(0, i) };
+ }
+ }
+ }
+
+ fn rebuild(&mut self) {
+ let mut n = self.len() / 2;
+ while n > 0 {
+ n -= 1;
+ // SAFETY: n starts from self.len() / 2 and goes down to 0.
+ // The only case when !(n < self.len()) is if
+ // self.len() == 0, but it's ruled out by the loop condition.
+ unsafe { self.sift_down(n) };
+ }
+ }
+
+ /// Moves all the elements of `other` into `self`, leaving `other` empty.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// use std::collections::BinaryHeap;
+ ///
+ /// let mut a = BinaryHeap::from([-10, 1, 2, 3, 3]);
+ /// let mut b = BinaryHeap::from([-20, 5, 43]);
+ ///
+ /// a.append(&mut b);
+ ///
+ /// assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]);
+ /// assert!(b.is_empty());
+ /// ```
+ #[stable(feature = "binary_heap_append", since = "1.11.0")]
+ pub fn append(&mut self, other: &mut Self) {
+ if self.len() < other.len() {
+ swap(self, other);
+ }
+
+ let start = self.data.len();
+
+ self.data.append(&mut other.data);
+
+ self.rebuild_tail(start);
+ }
+
+ /// Clears the binary heap, returning an iterator over the removed elements
+ /// in heap order. If the iterator is dropped before being fully consumed,
+ /// it drops the remaining elements in heap order.
+ ///
+ /// The returned iterator keeps a mutable borrow on the heap to optimize
+ /// its implementation.
+ ///
+ /// Note:
+ /// * `.drain_sorted()` is *O*(*n* \* log(*n*)); much slower than `.drain()`.
+ /// You should use the latter for most cases.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(binary_heap_drain_sorted)]
+ /// use std::collections::BinaryHeap;
+ ///
+ /// let mut heap = BinaryHeap::from([1, 2, 3, 4, 5]);
+ /// assert_eq!(heap.len(), 5);
+ ///
+ /// drop(heap.drain_sorted()); // removes all elements in heap order
+ /// assert_eq!(heap.len(), 0);
+ /// ```
+ #[inline]
+ #[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
+ pub fn drain_sorted(&mut self) -> DrainSorted<'_, T> {
+ DrainSorted { inner: self }
+ }
+
+ /// Retains only the elements specified by the predicate.
+ ///
+ /// In other words, remove all elements `e` for which `f(&e)` returns
+ /// `false`. The elements are visited in unsorted (and unspecified) order.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(binary_heap_retain)]
+ /// use std::collections::BinaryHeap;
+ ///
+ /// let mut heap = BinaryHeap::from([-10, -5, 1, 2, 4, 13]);
+ ///
+ /// heap.retain(|x| x % 2 == 0); // only keep even numbers
+ ///
+ /// assert_eq!(heap.into_sorted_vec(), [-10, 2, 4])
+ /// ```
+ #[unstable(feature = "binary_heap_retain", issue = "71503")]
+ pub fn retain<F>(&mut self, mut f: F)
+ where
+ F: FnMut(&T) -> bool,
+ {
+ let mut first_removed = self.len();
+ let mut i = 0;
+ self.data.retain(|e| {
+ let keep = f(e);
+ if !keep && i < first_removed {
+ first_removed = i;
+ }
+ i += 1;
+ keep
+ });
+ // data[0..first_removed] is untouched, so we only need to rebuild the tail:
+ self.rebuild_tail(first_removed);
+ }
+}
+
+impl<T> BinaryHeap<T> {
+ /// Returns an iterator visiting all values in the underlying vector, in
+ /// arbitrary order.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// use std::collections::BinaryHeap;
+ /// let heap = BinaryHeap::from([1, 2, 3, 4]);
+ ///
+ /// // Print 1, 2, 3, 4 in arbitrary order
+ /// for x in heap.iter() {
+ /// println!("{x}");
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn iter(&self) -> Iter<'_, T> {
+ Iter { iter: self.data.iter() }
+ }
+
+ /// Returns an iterator which retrieves elements in heap order.
+ /// This method consumes the original heap.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(binary_heap_into_iter_sorted)]
+ /// use std::collections::BinaryHeap;
+ /// let heap = BinaryHeap::from([1, 2, 3, 4, 5]);
+ ///
+ /// assert_eq!(heap.into_iter_sorted().take(2).collect::<Vec<_>>(), [5, 4]);
+ /// ```
+ #[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
+ pub fn into_iter_sorted(self) -> IntoIterSorted<T> {
+ IntoIterSorted { inner: self }
+ }
+
+ /// Returns the greatest item in the binary heap, or `None` if it is empty.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// use std::collections::BinaryHeap;
+ /// let mut heap = BinaryHeap::new();
+ /// assert_eq!(heap.peek(), None);
+ ///
+ /// heap.push(1);
+ /// heap.push(5);
+ /// heap.push(2);
+ /// assert_eq!(heap.peek(), Some(&5));
+ ///
+ /// ```
+ ///
+ /// # Time complexity
+ ///
+ /// Cost is *O*(1) in the worst case.
+ #[must_use]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn peek(&self) -> Option<&T> {
+ self.data.get(0)
+ }
+
+ /// Returns the number of elements the binary heap can hold without reallocating.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// use std::collections::BinaryHeap;
+ /// let mut heap = BinaryHeap::with_capacity(100);
+ /// assert!(heap.capacity() >= 100);
+ /// heap.push(4);
+ /// ```
+ #[must_use]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn capacity(&self) -> usize {
+ self.data.capacity()
+ }
+
+ /// Reserves the minimum capacity for at least `additional` elements more than
+ /// the current length. Unlike [`reserve`], this will not
+ /// deliberately over-allocate to speculatively avoid frequent allocations.
+ /// After calling `reserve_exact`, capacity will be greater than or equal to
+ /// `self.len() + additional`. Does nothing if the capacity is already
+ /// sufficient.
+ ///
+ /// [`reserve`]: BinaryHeap::reserve
+ ///
+ /// # Panics
+ ///
+ /// Panics if the new capacity overflows [`usize`].
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// use std::collections::BinaryHeap;
+ /// let mut heap = BinaryHeap::new();
+ /// heap.reserve_exact(100);
+ /// assert!(heap.capacity() >= 100);
+ /// heap.push(4);
+ /// ```
+ ///
+ /// [`reserve`]: BinaryHeap::reserve
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn reserve_exact(&mut self, additional: usize) {
+ self.data.reserve_exact(additional);
+ }
+
+ /// Reserves capacity for at least `additional` elements more than the
+ /// current length. The allocator may reserve more space to speculatively
+ /// avoid frequent allocations. After calling `reserve`,
+ /// capacity will be greater than or equal to `self.len() + additional`.
+ /// Does nothing if capacity is already sufficient.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the new capacity overflows [`usize`].
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// use std::collections::BinaryHeap;
+ /// let mut heap = BinaryHeap::new();
+ /// heap.reserve(100);
+ /// assert!(heap.capacity() >= 100);
+ /// heap.push(4);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn reserve(&mut self, additional: usize) {
+ self.data.reserve(additional);
+ }
+
+ /// Tries to reserve the minimum capacity for at least `additional` elements
+ /// more than the current length. Unlike [`try_reserve`], this will not
+ /// deliberately over-allocate to speculatively avoid frequent allocations.
+ /// After calling `try_reserve_exact`, capacity will be greater than or
+ /// equal to `self.len() + additional` if it returns `Ok(())`.
+ /// Does nothing if the capacity is already sufficient.
+ ///
+ /// Note that the allocator may give the collection more space than it
+ /// requests. Therefore, capacity can not be relied upon to be precisely
+ /// minimal. Prefer [`try_reserve`] if future insertions are expected.
+ ///
+ /// [`try_reserve`]: BinaryHeap::try_reserve
+ ///
+ /// # Errors
+ ///
+ /// If the capacity overflows, or the allocator reports a failure, then an error
+ /// is returned.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::BinaryHeap;
+ /// use std::collections::TryReserveError;
+ ///
+ /// fn find_max_slow(data: &[u32]) -> Result<Option<u32>, TryReserveError> {
+ /// let mut heap = BinaryHeap::new();
+ ///
+ /// // Pre-reserve the memory, exiting if we can't
+ /// heap.try_reserve_exact(data.len())?;
+ ///
+ /// // Now we know this can't OOM in the middle of our complex work
+ /// heap.extend(data.iter());
+ ///
+ /// Ok(heap.pop())
+ /// }
+ /// # find_max_slow(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
+ /// ```
+ #[stable(feature = "try_reserve_2", since = "1.63.0")]
+ pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
+ self.data.try_reserve_exact(additional)
+ }
+
+ /// Tries to reserve capacity for at least `additional` elements more than the
+ /// current length. The allocator may reserve more space to speculatively
+ /// avoid frequent allocations. After calling `try_reserve`, capacity will be
+ /// greater than or equal to `self.len() + additional` if it returns
+ /// `Ok(())`. Does nothing if capacity is already sufficient. This method
+ /// preserves the contents even if an error occurs.
+ ///
+ /// # Errors
+ ///
+ /// If the capacity overflows, or the allocator reports a failure, then an error
+ /// is returned.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::BinaryHeap;
+ /// use std::collections::TryReserveError;
+ ///
+ /// fn find_max_slow(data: &[u32]) -> Result<Option<u32>, TryReserveError> {
+ /// let mut heap = BinaryHeap::new();
+ ///
+ /// // Pre-reserve the memory, exiting if we can't
+ /// heap.try_reserve(data.len())?;
+ ///
+ /// // Now we know this can't OOM in the middle of our complex work
+ /// heap.extend(data.iter());
+ ///
+ /// Ok(heap.pop())
+ /// }
+ /// # find_max_slow(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
+ /// ```
+ #[stable(feature = "try_reserve_2", since = "1.63.0")]
+ pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
+ self.data.try_reserve(additional)
+ }
+
+ /// Discards as much additional capacity as possible.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// use std::collections::BinaryHeap;
+ /// let mut heap: BinaryHeap<i32> = BinaryHeap::with_capacity(100);
+ ///
+ /// assert!(heap.capacity() >= 100);
+ /// heap.shrink_to_fit();
+ /// assert!(heap.capacity() == 0);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn shrink_to_fit(&mut self) {
+ self.data.shrink_to_fit();
+ }
+
+ /// Discards capacity with a lower bound.
+ ///
+ /// The capacity will remain at least as large as both the length
+ /// and the supplied value.
+ ///
+ /// If the current capacity is less than the lower limit, this is a no-op.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::BinaryHeap;
+ /// let mut heap: BinaryHeap<i32> = BinaryHeap::with_capacity(100);
+ ///
+ /// assert!(heap.capacity() >= 100);
+ /// heap.shrink_to(10);
+ /// assert!(heap.capacity() >= 10);
+ /// ```
+ #[inline]
+ #[stable(feature = "shrink_to", since = "1.56.0")]
+ pub fn shrink_to(&mut self, min_capacity: usize) {
+ self.data.shrink_to(min_capacity)
+ }
+
+ /// Returns a slice of all values in the underlying vector, in arbitrary
+ /// order.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(binary_heap_as_slice)]
+ /// use std::collections::BinaryHeap;
+ /// use std::io::{self, Write};
+ ///
+ /// let heap = BinaryHeap::from([1, 2, 3, 4, 5, 6, 7]);
+ ///
+ /// io::sink().write(heap.as_slice()).unwrap();
+ /// ```
+ #[must_use]
+ #[unstable(feature = "binary_heap_as_slice", issue = "83659")]
+ pub fn as_slice(&self) -> &[T] {
+ self.data.as_slice()
+ }
+
+ /// Consumes the `BinaryHeap` and returns the underlying vector
+ /// in arbitrary order.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// use std::collections::BinaryHeap;
+ /// let heap = BinaryHeap::from([1, 2, 3, 4, 5, 6, 7]);
+ /// let vec = heap.into_vec();
+ ///
+ /// // Will print in some order
+ /// for x in vec {
+ /// println!("{x}");
+ /// }
+ /// ```
+ #[must_use = "`self` will be dropped if the result is not used"]
+ #[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
+ pub fn into_vec(self) -> Vec<T> {
+ self.into()
+ }
+
+ /// Returns the length of the binary heap.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// use std::collections::BinaryHeap;
+ /// let heap = BinaryHeap::from([1, 3]);
+ ///
+ /// assert_eq!(heap.len(), 2);
+ /// ```
+ #[must_use]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn len(&self) -> usize {
+ self.data.len()
+ }
+
+ /// Checks if the binary heap is empty.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// use std::collections::BinaryHeap;
+ /// let mut heap = BinaryHeap::new();
+ ///
+ /// assert!(heap.is_empty());
+ ///
+ /// heap.push(3);
+ /// heap.push(5);
+ /// heap.push(1);
+ ///
+ /// assert!(!heap.is_empty());
+ /// ```
+ #[must_use]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn is_empty(&self) -> bool {
+ self.len() == 0
+ }
+
+ /// Clears the binary heap, returning an iterator over the removed elements
+ /// in arbitrary order. If the iterator is dropped before being fully
+ /// consumed, it drops the remaining elements in arbitrary order.
+ ///
+ /// The returned iterator keeps a mutable borrow on the heap to optimize
+ /// its implementation.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// use std::collections::BinaryHeap;
+ /// let mut heap = BinaryHeap::from([1, 3]);
+ ///
+ /// assert!(!heap.is_empty());
+ ///
+ /// for x in heap.drain() {
+ /// println!("{x}");
+ /// }
+ ///
+ /// assert!(heap.is_empty());
+ /// ```
+ #[inline]
+ #[stable(feature = "drain", since = "1.6.0")]
+ pub fn drain(&mut self) -> Drain<'_, T> {
+ Drain { iter: self.data.drain(..) }
+ }
+
+ /// Drops all items from the binary heap.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// use std::collections::BinaryHeap;
+ /// let mut heap = BinaryHeap::from([1, 3]);
+ ///
+ /// assert!(!heap.is_empty());
+ ///
+ /// heap.clear();
+ ///
+ /// assert!(heap.is_empty());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn clear(&mut self) {
+ self.drain();
+ }
+}
+
+/// Hole represents a hole in a slice i.e., an index without valid value
+/// (because it was moved from or duplicated).
+/// In drop, `Hole` will restore the slice by filling the hole
+/// position with the value that was originally removed.
+struct Hole<'a, T: 'a> {
+ data: &'a mut [T],
+ elt: ManuallyDrop<T>,
+ pos: usize,
+}
+
+impl<'a, T> Hole<'a, T> {
+ /// Create a new `Hole` at index `pos`.
+ ///
+ /// Unsafe because pos must be within the data slice.
+ #[inline]
+ unsafe fn new(data: &'a mut [T], pos: usize) -> Self {
+ debug_assert!(pos < data.len());
+ // SAFE: pos should be inside the slice
+ let elt = unsafe { ptr::read(data.get_unchecked(pos)) };
+ Hole { data, elt: ManuallyDrop::new(elt), pos }
+ }
+
+ #[inline]
+ fn pos(&self) -> usize {
+ self.pos
+ }
+
+ /// Returns a reference to the element removed.
+ #[inline]
+ fn element(&self) -> &T {
+ &self.elt
+ }
+
+ /// Returns a reference to the element at `index`.
+ ///
+ /// Unsafe because index must be within the data slice and not equal to pos.
+ #[inline]
+ unsafe fn get(&self, index: usize) -> &T {
+ debug_assert!(index != self.pos);
+ debug_assert!(index < self.data.len());
+ unsafe { self.data.get_unchecked(index) }
+ }
+
+ /// Move hole to new location
+ ///
+ /// Unsafe because index must be within the data slice and not equal to pos.
+ #[inline]
+ unsafe fn move_to(&mut self, index: usize) {
+ debug_assert!(index != self.pos);
+ debug_assert!(index < self.data.len());
+ unsafe {
+ let ptr = self.data.as_mut_ptr();
+ let index_ptr: *const _ = ptr.add(index);
+ let hole_ptr = ptr.add(self.pos);
+ ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1);
+ }
+ self.pos = index;
+ }
+}
+
+impl<T> Drop for Hole<'_, T> {
+ #[inline]
+ fn drop(&mut self) {
+ // fill the hole again
+ unsafe {
+ let pos = self.pos;
+ ptr::copy_nonoverlapping(&*self.elt, self.data.get_unchecked_mut(pos), 1);
+ }
+ }
+}
+
+/// An iterator over the elements of a `BinaryHeap`.
+///
+/// This `struct` is created by [`BinaryHeap::iter()`]. See its
+/// documentation for more.
+///
+/// [`iter`]: BinaryHeap::iter
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Iter<'a, T: 'a> {
+ iter: slice::Iter<'a, T>,
+}
+
+#[stable(feature = "collection_debug", since = "1.17.0")]
+impl<T: fmt::Debug> fmt::Debug for Iter<'_, T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_tuple("Iter").field(&self.iter.as_slice()).finish()
+ }
+}
+
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> Clone for Iter<'_, T> {
+ fn clone(&self) -> Self {
+ Iter { iter: self.iter.clone() }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T> Iterator for Iter<'a, T> {
+ type Item = &'a T;
+
+ #[inline]
+ fn next(&mut self) -> Option<&'a T> {
+ self.iter.next()
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+
+ #[inline]
+ fn last(self) -> Option<&'a T> {
+ self.iter.last()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
+ #[inline]
+ fn next_back(&mut self) -> Option<&'a T> {
+ self.iter.next_back()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> ExactSizeIterator for Iter<'_, T> {
+ fn is_empty(&self) -> bool {
+ self.iter.is_empty()
+ }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<T> FusedIterator for Iter<'_, T> {}
+
+/// An owning iterator over the elements of a `BinaryHeap`.
+///
+/// This `struct` is created by [`BinaryHeap::into_iter()`]
+/// (provided by the [`IntoIterator`] trait). See its documentation for more.
+///
+/// [`into_iter`]: BinaryHeap::into_iter
+/// [`IntoIterator`]: core::iter::IntoIterator
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Clone)]
+pub struct IntoIter<T> {
+ iter: vec::IntoIter<T>,
+}
+
+#[stable(feature = "collection_debug", since = "1.17.0")]
+impl<T: fmt::Debug> fmt::Debug for IntoIter<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_tuple("IntoIter").field(&self.iter.as_slice()).finish()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> Iterator for IntoIter<T> {
+ type Item = T;
+
+ #[inline]
+ fn next(&mut self) -> Option<T> {
+ self.iter.next()
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> DoubleEndedIterator for IntoIter<T> {
+ #[inline]
+ fn next_back(&mut self) -> Option<T> {
+ self.iter.next_back()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> ExactSizeIterator for IntoIter<T> {
+ fn is_empty(&self) -> bool {
+ self.iter.is_empty()
+ }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<T> FusedIterator for IntoIter<T> {}
+
+// In addition to the SAFETY invariants of the following three unsafe traits
+// also refer to the vec::in_place_collect module documentation to get an overview
+#[unstable(issue = "none", feature = "inplace_iteration")]
+#[doc(hidden)]
+unsafe impl<T> SourceIter for IntoIter<T> {
+ type Source = IntoIter<T>;
+
+ #[inline]
+ unsafe fn as_inner(&mut self) -> &mut Self::Source {
+ self
+ }
+}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+#[doc(hidden)]
+unsafe impl<I> InPlaceIterable for IntoIter<I> {}
+
+unsafe impl<I> AsVecIntoIter for IntoIter<I> {
+ type Item = I;
+
+ fn as_into_iter(&mut self) -> &mut vec::IntoIter<Self::Item> {
+ &mut self.iter
+ }
+}
+
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
+#[derive(Clone, Debug)]
+pub struct IntoIterSorted<T> {
+ inner: BinaryHeap<T>,
+}
+
+#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
+impl<T: Ord> Iterator for IntoIterSorted<T> {
+ type Item = T;
+
+ #[inline]
+ fn next(&mut self) -> Option<T> {
+ self.inner.pop()
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let exact = self.inner.len();
+ (exact, Some(exact))
+ }
+}
+
+#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
+impl<T: Ord> ExactSizeIterator for IntoIterSorted<T> {}
+
+#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
+impl<T: Ord> FusedIterator for IntoIterSorted<T> {}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T: Ord> TrustedLen for IntoIterSorted<T> {}
+
+/// A draining iterator over the elements of a `BinaryHeap`.
+///
+/// This `struct` is created by [`BinaryHeap::drain()`]. See its
+/// documentation for more.
+///
+/// [`drain`]: BinaryHeap::drain
+#[stable(feature = "drain", since = "1.6.0")]
+#[derive(Debug)]
+pub struct Drain<'a, T: 'a> {
+ iter: vec::Drain<'a, T>,
+}
+
+#[stable(feature = "drain", since = "1.6.0")]
+impl<T> Iterator for Drain<'_, T> {
+ type Item = T;
+
+ #[inline]
+ fn next(&mut self) -> Option<T> {
+ self.iter.next()
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+}
+
+#[stable(feature = "drain", since = "1.6.0")]
+impl<T> DoubleEndedIterator for Drain<'_, T> {
+ #[inline]
+ fn next_back(&mut self) -> Option<T> {
+ self.iter.next_back()
+ }
+}
+
+#[stable(feature = "drain", since = "1.6.0")]
+impl<T> ExactSizeIterator for Drain<'_, T> {
+ fn is_empty(&self) -> bool {
+ self.iter.is_empty()
+ }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<T> FusedIterator for Drain<'_, T> {}
+
+/// A draining iterator over the elements of a `BinaryHeap`.
+///
+/// This `struct` is created by [`BinaryHeap::drain_sorted()`]. See its
+/// documentation for more.
+///
+/// [`drain_sorted`]: BinaryHeap::drain_sorted
+#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
+#[derive(Debug)]
+pub struct DrainSorted<'a, T: Ord> {
+ inner: &'a mut BinaryHeap<T>,
+}
+
+#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
+impl<'a, T: Ord> Drop for DrainSorted<'a, T> {
+ /// Removes heap elements in heap order.
+ fn drop(&mut self) {
+ struct DropGuard<'r, 'a, T: Ord>(&'r mut DrainSorted<'a, T>);
+
+ impl<'r, 'a, T: Ord> Drop for DropGuard<'r, 'a, T> {
+ fn drop(&mut self) {
+ while self.0.inner.pop().is_some() {}
+ }
+ }
+
+ while let Some(item) = self.inner.pop() {
+ let guard = DropGuard(self);
+ drop(item);
+ mem::forget(guard);
+ }
+ }
+}
+
+#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
+impl<T: Ord> Iterator for DrainSorted<'_, T> {
+ type Item = T;
+
+ #[inline]
+ fn next(&mut self) -> Option<T> {
+ self.inner.pop()
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let exact = self.inner.len();
+ (exact, Some(exact))
+ }
+}
+
+#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
+impl<T: Ord> ExactSizeIterator for DrainSorted<'_, T> {}
+
+#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
+impl<T: Ord> FusedIterator for DrainSorted<'_, T> {}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T: Ord> TrustedLen for DrainSorted<'_, 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();
+ heap
+ }
+}
+
+#[stable(feature = "std_collections_from_array", since = "1.56.0")]
+impl<T: Ord, const N: usize> From<[T; N]> for BinaryHeap<T> {
+ /// ```
+ /// use std::collections::BinaryHeap;
+ ///
+ /// let mut h1 = BinaryHeap::from([1, 4, 2, 3]);
+ /// let mut h2: BinaryHeap<_> = [1, 4, 2, 3].into();
+ /// while let Some((a, b)) = h1.pop().zip(h2.pop()) {
+ /// assert_eq!(a, b);
+ /// }
+ /// ```
+ fn from(arr: [T; N]) -> Self {
+ Self::from_iter(arr)
+ }
+}
+
+#[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
+impl<T> From<BinaryHeap<T>> for Vec<T> {
+ /// Converts a `BinaryHeap<T>` into a `Vec<T>`.
+ ///
+ /// This conversion requires no data movement or allocation, and has
+ /// constant time complexity.
+ fn from(heap: BinaryHeap<T>) -> Vec<T> {
+ heap.data
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Ord> FromIterator<T> for BinaryHeap<T> {
+ fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> BinaryHeap<T> {
+ BinaryHeap::from(iter.into_iter().collect::<Vec<_>>())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> IntoIterator for BinaryHeap<T> {
+ type Item = T;
+ type IntoIter = IntoIter<T>;
+
+ /// Creates a consuming iterator, that is, one that moves each value out of
+ /// the binary heap in arbitrary order. The binary heap cannot be used
+ /// after calling this.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// use std::collections::BinaryHeap;
+ /// let heap = BinaryHeap::from([1, 2, 3, 4]);
+ ///
+ /// // Print 1, 2, 3, 4 in arbitrary order
+ /// for x in heap.into_iter() {
+ /// // x has type i32, not &i32
+ /// println!("{x}");
+ /// }
+ /// ```
+ fn into_iter(self) -> IntoIter<T> {
+ IntoIter { iter: self.data.into_iter() }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T> IntoIterator for &'a BinaryHeap<T> {
+ type Item = &'a T;
+ type IntoIter = Iter<'a, T>;
+
+ fn into_iter(self) -> Iter<'a, T> {
+ self.iter()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Ord> Extend<T> for BinaryHeap<T> {
+ #[inline]
+ fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
+ <Self as SpecExtend<I>>::spec_extend(self, iter);
+ }
+
+ #[inline]
+ fn extend_one(&mut self, item: T) {
+ self.push(item);
+ }
+
+ #[inline]
+ fn extend_reserve(&mut self, additional: usize) {
+ self.reserve(additional);
+ }
+}
+
+impl<T: Ord, I: IntoIterator<Item = T>> SpecExtend<I> for BinaryHeap<T> {
+ default fn spec_extend(&mut self, iter: I) {
+ self.extend_desugared(iter.into_iter());
+ }
+}
+
+impl<T: Ord> SpecExtend<Vec<T>> for BinaryHeap<T> {
+ fn spec_extend(&mut self, ref mut other: Vec<T>) {
+ let start = self.data.len();
+ self.data.append(other);
+ self.rebuild_tail(start);
+ }
+}
+
+impl<T: Ord> SpecExtend<BinaryHeap<T>> for BinaryHeap<T> {
+ fn spec_extend(&mut self, ref mut other: BinaryHeap<T>) {
+ self.append(other);
+ }
+}
+
+impl<T: Ord> BinaryHeap<T> {
+ fn extend_desugared<I: IntoIterator<Item = T>>(&mut self, iter: I) {
+ let iterator = iter.into_iter();
+ let (lower, _) = iterator.size_hint();
+
+ self.reserve(lower);
+
+ iterator.for_each(move |elem| self.push(elem));
+ }
+}
+
+#[stable(feature = "extend_ref", since = "1.2.0")]
+impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BinaryHeap<T> {
+ fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
+ self.extend(iter.into_iter().cloned());
+ }
+
+ #[inline]
+ fn extend_one(&mut self, &item: &'a T) {
+ self.push(item);
+ }
+
+ #[inline]
+ fn extend_reserve(&mut self, additional: usize) {
+ self.reserve(additional);
+ }
+}
use super::*;
use crate::boxed::Box;
use crate::testing::crash_test::{CrashTestDummy, Panic};
+use core::mem;
use std::iter::TrustedLen;
use std::panic::{catch_unwind, AssertUnwindSafe};
assert_eq!(heap.peek(), Some(&9));
}
+#[test]
+fn test_peek_mut_leek() {
+ let data = vec![4, 2, 7];
+ let mut heap = BinaryHeap::from(data);
+ let mut max = heap.peek_mut().unwrap();
+ *max = -1;
+
+ // The PeekMut object's Drop impl would have been responsible for moving the
+ // -1 out of the max position of the BinaryHeap, but we don't run it.
+ mem::forget(max);
+
+ // Absent some mitigation like leak amplification, the -1 would incorrectly
+ // end up in the last position of the returned Vec, with the rest of the
+ // heap's original contents in front of it in sorted order.
+ let sorted_vec = heap.into_sorted_vec();
+ assert!(sorted_vec.is_sorted(), "{:?}", sorted_vec);
+}
+
#[test]
fn test_peek_mut_pop() {
let data = vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1];
#![feature(hasher_prefixfree_extras)]
#![feature(inline_const)]
#![feature(inplace_iteration)]
+#![cfg_attr(test, feature(is_sorted))]
#![feature(iter_advance_by)]
#![feature(iter_next_chunk)]
#![feature(iter_repeat_n)]
// This is a `NonNull` to allow optimizing the size of this type in enums,
// but it is not necessarily a valid pointer.
// `Weak::new` sets this to `usize::MAX` so that it doesn’t need
- // to allocate space on the heap. That's not a value a real pointer
+ // to allocate space on the heap. That's not a value a real pointer
// will ever have because RcBox has alignment at least 2.
// This is only possible when `T: Sized`; unsized `T` never dangle.
ptr: NonNull<RcBox<T>>,
// This is a `NonNull` to allow optimizing the size of this type in enums,
// but it is not necessarily a valid pointer.
// `Weak::new` sets this to `usize::MAX` so that it doesn’t need
- // to allocate space on the heap. That's not a value a real pointer
+ // to allocate space on the heap. That's not a value a real pointer
// will ever have because RcBox has alignment at least 2.
// This is only possible when `T: Sized`; unsized `T` never dangle.
ptr: NonNull<ArcInner<T>>,
//
// The acquire label here ensures a happens-before relationship with any
// writes to `strong` (in particular in `Weak::upgrade`) prior to decrements
- // of the `weak` count (via `Weak::drop`, which uses release). If the upgraded
+ // of the `weak` count (via `Weak::drop`, which uses release). If the upgraded
// weak ref was never dropped, the CAS here will fail so we do not care to synchronize.
if self.inner().weak.compare_exchange(1, usize::MAX, Acquire, Relaxed).is_ok() {
// This needs to be an `Acquire` to synchronize with the decrement of the `strong`
}
// This fence is needed to prevent reordering of use of the data and
- // deletion of the data. Because it is marked `Release`, the decreasing
+ // deletion of the data. Because it is marked `Release`, the decreasing
// of the reference count synchronizes with this `Acquire` fence. This
// means that use of the data happens before decreasing the reference
// count, which happens before this fence, which happens before the
} else {
return Weak { ptr: self.ptr };
};
- // See comments in Arc::clone() for why this is relaxed. This can use a
+ // See comments in Arc::clone() for why this is relaxed. This can use a
// fetch_add (ignoring the lock) because the weak count is only locked
// where are *no other* weak pointers in existence. (So we can't be
// running this code in that case).
// to avoid dropping the allocator twice we need to wrap it into ManuallyDrop
pub(super) alloc: ManuallyDrop<A>,
pub(super) ptr: *const T,
- pub(super) end: *const T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
+ pub(super) end: *const T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
// ptr == end is a quick test for the Iterator being empty, that works
// for both ZST and non-ZST.
}
let mut this = ManuallyDrop::new(self);
// SAFETY: This allocation originally came from a `Vec`, so it passes
- // all those checks. We have `this.buf` ≤ `this.ptr` ≤ `this.end`,
+ // all those checks. We have `this.buf` ≤ `this.ptr` ≤ `this.end`,
// so the `sub_ptr`s below cannot wrap, and will produce a well-formed
- // range. `end` ≤ `buf + cap`, so the range will be in-bounds.
+ // range. `end` ≤ `buf + cap`, so the range will be in-bounds.
// Taking `alloc` is ok because nothing else is going to look at it,
// since our `Drop` impl isn't going to run so there's no more code.
unsafe {
#[inline]
fn is_zero(&self) -> bool {
// Because this is generated as a runtime check, it's not obvious that
- // it's worth doing if the array is really long. The threshold here
+ // it's worth doing if the array is really long. The threshold here
// is largely arbitrary, but was picked because as of 2022-07-01 LLVM
// fails to const-fold the check in `vec![[1; 32]; n]`
// See https://github.com/rust-lang/rust/pull/97581#issuecomment-1166628022
self.reserve(range.len());
// SAFETY:
- // - `slice::range` guarantees that the given range is valid for indexing self
+ // - `slice::range` guarantees that the given range is valid for indexing self
unsafe {
self.spec_extend_from_within(range);
}
// HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is
// required for this method definition, is not available. Instead use the
- // `slice::to_vec` function which is only available with cfg(test)
+ // `slice::to_vec` function which is only available with cfg(test)
// NB see the slice::hack module in slice.rs for more information
#[cfg(test)]
fn clone(&self) -> Self {
}
// Test that, if we reserved enough space, adding and removing elements does not
- // invalidate references into the vector (such as `v0`). This test also
+ // invalidate references into the vector (such as `v0`). This test also
// runs in Miri, which would detect such problems.
// Note that this test does *not* constitute a stable guarantee that all these functions do not
// reallocate! Only what is explicitly documented at
/// use std::array::IntoIter;
/// use std::mem::MaybeUninit;
///
- /// # // Hi! Thanks for reading the code. This is restricted to `Copy` because
- /// # // otherwise it could leak. A fully-general version this would need a drop
+ /// # // Hi! Thanks for reading the code. This is restricted to `Copy` because
+ /// # // otherwise it could leak. A fully-general version this would need a drop
/// # // guard to handle panics from the iterator, but this works for an example.
/// fn next_chunk<T: Copy, const N: usize>(
/// it: &mut impl Iterator<Item = T>,
let initialized = 0..0;
// SAFETY: We're telling it that none of the elements are initialized,
- // which is trivially true. And ∀N: usize, 0 <= N.
+ // which is trivially true. And ∀N: usize, 0 <= N.
unsafe { Self::new_unchecked(buffer, initialized) }
}
/// This method should generally not be invoked manually, but rather through
/// the [`write!`] macro itself.
///
+ /// # Errors
+ ///
+ /// This function will return an instance of [`Error`] on error. Please see
+ /// [write_str](Write::write_str) for details.
+ ///
/// # Examples
///
/// ```
where
Self: TrustedRandomAccessNoCoerce,
{
- // SAFETY: The TrustedRandomAccess contract requires that callers only pass an index
+ // SAFETY: The TrustedRandomAccess contract requires that callers only pass an index
// that is in bounds.
// Additionally Self: TrustedRandomAccess is only implemented for Copy types
// which means even repeated reads of the same index would be safe.
+use crate::fmt;
use crate::ops::{Generator, GeneratorState};
use crate::pin::Pin;
/// ```
#[inline]
#[unstable(feature = "iter_from_generator", issue = "43122", reason = "generators are unstable")]
-pub fn from_generator<G: Generator<Return = ()> + Unpin>(
- generator: G,
-) -> impl Iterator<Item = G::Yield> {
+pub fn from_generator<G: Generator<Return = ()> + Unpin>(generator: G) -> FromGenerator<G> {
FromGenerator(generator)
}
-struct FromGenerator<G>(G);
+/// An iterator over the values yielded by an underlying generator.
+///
+/// This `struct` is created by the [`iter::from_generator()`] function. See its documentation for
+/// more.
+///
+/// [`iter::from_generator()`]: from_generator
+#[unstable(feature = "iter_from_generator", issue = "43122", reason = "generators are unstable")]
+#[derive(Clone)]
+pub struct FromGenerator<G>(G);
+#[unstable(feature = "iter_from_generator", issue = "43122", reason = "generators are unstable")]
impl<G: Generator<Return = ()> + Unpin> Iterator for FromGenerator<G> {
type Item = G::Yield;
}
}
}
+
+#[unstable(feature = "iter_from_generator", issue = "43122", reason = "generators are unstable")]
+impl<G> fmt::Debug for FromGenerator<G> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("FromGenerator").finish()
+ }
+}
/// Developer's Manual (Volume 1).
///
/// The only field which is relevant for the following code is PC, Precision Control. This
- /// field determines the precision of the operations performed by the FPU. It can be set to:
+ /// field determines the precision of the operations performed by the FPU. It can be set to:
/// - 0b00, single precision i.e., 32-bits
/// - 0b10, double precision i.e., 64-bits
/// - 0b11, double extended precision i.e., 80-bits (default state)
///
/// ```
/// #![feature(bigint_helper_methods)]
- /// // Only the most significant word is signed.
+ /// // Only the most significant word is signed.
/// //
#[doc = concat!("// 10 MAX (a = 10 × 2^", stringify!($BITS), " + 2^", stringify!($BITS), " - 1)")]
#[doc = concat!("// + -5 9 (b = -5 × 2^", stringify!($BITS), " + 9)")]
/// overflow.
///
/// Performs "ternary subtraction" by subtracting both an integer
- /// operandand a borrow-in bit from `self`, and returns a tuple of the
+ /// operand and a borrow-in bit from `self`, and returns a tuple of the
/// difference along with a boolean indicating whether an arithmetic
/// overflow would occur. On overflow, the wrapped value is returned.
///
///
/// ```
/// #![feature(bigint_helper_methods)]
- /// // Only the most significant word is signed.
+ /// // Only the most significant word is signed.
/// //
#[doc = concat!("// 6 8 (a = 6 × 2^", stringify!($BITS), " + 8)")]
#[doc = concat!("// - -5 9 (b = -5 × 2^", stringify!($BITS), " + 9)")]
///
/// # Examples
///
- /// Converts an <code>Option<[String]></code> into an <code>Option<[usize]></code>, preserving
- /// the original. The [`map`] method takes the `self` argument by value, consuming the original,
- /// so this technique uses `as_ref` to first take an `Option` to a reference
- /// to the value inside the original.
+ /// Calculates the length of an <code>Option<[String]></code> as an <code>Option<[usize]></code>
+ /// without moving the [`String`]. The [`map`] method takes the `self` argument by value,
+ /// consuming the original, so this technique uses `as_ref` to first take an `Option` to a
+ /// reference to the value inside the original.
///
/// [`map`]: Option::map
/// [String]: ../../std/string/struct.String.html "String"
+ /// [`String`]: ../../std/string/struct.String.html "String"
///
/// ```
/// let text: Option<String> = Some("Hello, world!".to_string());
///
/// # Examples
///
- /// Converts an <code>Option<[String]></code> into an <code>Option<[usize]></code>, consuming
- /// the original:
+ /// Calculates the length of an <code>Option<[String]></code> as an
+ /// <code>Option<[usize]></code>, consuming the original:
///
/// [String]: ../../std/string/struct.String.html "String"
/// ```
impl<'a, T: ?Sized> Pin<&'a T> {
/// Constructs a new pin by mapping the interior value.
///
- /// For example, if you wanted to get a `Pin` of a field of something,
+ /// For example, if you wanted to get a `Pin` of a field of something,
/// you could use this to get access to that field in one line of code.
/// However, there are several gotchas with these "pinning projections";
/// see the [`pin` module] documentation for further details on that topic.
/// Construct a new pin by mapping the interior value.
///
- /// For example, if you wanted to get a `Pin` of a field of something,
+ /// For example, if you wanted to get a `Pin` of a field of something,
/// you could use this to get access to that field in one line of code.
/// However, there are several gotchas with these "pinning projections";
/// see the [`pin` module] documentation for further details on that topic.
// offset is not a multiple of `stride`, the input pointer was misaligned and no pointer
// offset will be able to produce a `p` aligned to the specified `a`.
//
- // The naive `-p (mod a)` equation inhibits LLVM's ability to select instructions
+ // The naive `-p (mod a)` equation inhibits LLVM's ability to select instructions
// like `lea`. We compute `(round_up_to_next_alignment(p, a) - p)` instead. This
// redistributes operations around the load-bearing, but pessimizing `and` instruction
// sufficiently for LLVM to be able to utilize the various optimizations it knows about.
use crate::cmp;
use crate::cmp::Ordering;
use crate::fmt;
-use crate::intrinsics::{assume, exact_div, unchecked_sub};
+use crate::intrinsics::assume;
use crate::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce};
use crate::marker::{PhantomData, Send, Sized, Sync};
use crate::mem::{self, SizedTypeProperties};
}
}
-// Macro helper functions
-#[inline(always)]
-fn size_from_ptr<T>(_: *const T) -> usize {
- mem::size_of::<T>()
-}
-
/// Immutable slice iterator
///
/// This struct is created by the [`iter`] method on [slices].
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct Iter<'a, T: 'a> {
ptr: NonNull<T>,
- end: *const T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
+ end: *const T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
// ptr == end is a quick test for the Iterator being empty, that works
// for both ZST and non-ZST.
_marker: PhantomData<&'a T>,
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct IterMut<'a, T: 'a> {
ptr: NonNull<T>,
- end: *mut T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
+ end: *mut T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
// ptr == end is a quick test for the Iterator being empty, that works
// for both ZST and non-ZST.
_marker: PhantomData<&'a mut T>,
};
}
-// To get rid of some bounds checks (see `position`), we compute the length in a somewhat
-// unexpected way. (Tested by `codegen/slice-position-bounds-check`.)
macro_rules! len {
($self: ident) => {{
#![allow(unused_unsafe)] // we're sometimes used within an unsafe block
let start = $self.ptr;
- let size = size_from_ptr(start.as_ptr());
- if size == 0 {
- // This _cannot_ use `unchecked_sub` because we depend on wrapping
+ if T::IS_ZST {
+ // This _cannot_ use `ptr_sub` because we depend on wrapping
// to represent the length of long ZST slice iterators.
$self.end.addr().wrapping_sub(start.as_ptr().addr())
} else {
- // We know that `start <= end`, so can do better than `offset_from`,
- // which needs to deal in signed. By setting appropriate flags here
- // we can tell LLVM this, which helps it remove bounds checks.
- // SAFETY: By the type invariant, `start <= end`
- let diff = unsafe { unchecked_sub($self.end.addr(), start.as_ptr().addr()) };
- // By also telling LLVM that the pointers are apart by an exact
- // multiple of the type size, it can optimize `len() == 0` down to
- // `start == end` instead of `(end - start) < size`.
- // SAFETY: By the type invariant, the pointers are aligned so the
- // distance between them must be a multiple of pointee size
- unsafe { exact_div(diff, size) }
+ // To get rid of some bounds checks (see `position`), we use ptr_sub instead of
+ // offset_from (Tested by `codegen/slice-position-bounds-check`.)
+ // SAFETY: by the type invariant pointers are aligned and `start <= end`
+ unsafe { $self.end.sub_ptr(start.as_ptr()) }
}
}};
}
// Because this function is first compiled in isolation,
// this check tells LLVM that the indexing below is
- // in-bounds. Then after inlining -- once the actual
+ // in-bounds. Then after inlining -- once the actual
// lengths of the slices are known -- it's removed.
let (a, b) = (&mut a[..n], &mut b[..n]);
ArrayChunksMut::new(self)
}
- /// Returns an iterator over overlapping windows of `N` elements of a slice,
+ /// Returns an iterator over overlapping windows of `N` elements of a slice,
/// starting at the beginning of the slice.
///
/// This is the const generic equivalent of [`windows`].
let mid = left + size / 2;
// SAFETY: the while condition means `size` is strictly positive, so
- // `size/2 < size`. Thus `left + size/2 < left + size`, which
+ // `size/2 < size`. Thus `left + size/2 < left + size`, which
// coupled with the `left + size <= self.len()` invariant means
// we have `left + size/2 < self.len()`, and this is in-bounds.
let cmp = f(unsafe { self.get_unchecked(mid) });
impl<T> Drop for CopyOnDrop<T> {
fn drop(&mut self) {
- // SAFETY: This is a helper class.
- // Please refer to its usage for correctness.
- // Namely, one must be sure that `src` and `dst` does not overlap as required by `ptr::copy_nonoverlapping`.
+ // SAFETY: This is a helper class.
+ // Please refer to its usage for correctness.
+ // Namely, one must be sure that `src` and `dst` does not overlap as required by `ptr::copy_nonoverlapping`.
unsafe {
ptr::copy_nonoverlapping(self.src, self.dest, 1);
}
// SAFETY: data races are prevented by atomic intrinsics.
unsafe { atomic_xor(self.p.get(), core::ptr::invalid_mut(val), order).cast() }
}
+
+ /// Returns a mutable pointer to the underlying pointer.
+ ///
+ /// Doing non-atomic reads and writes on the resulting integer can be a data race.
+ /// This method is mostly useful for FFI, where the function signature may use
+ /// `*mut *mut T` instead of `&AtomicPtr<T>`.
+ ///
+ /// Returning an `*mut` pointer from a shared reference to this atomic is safe because the
+ /// atomic types work with interior mutability. All modifications of an atomic change the value
+ /// through a shared reference, and can do so safely as long as they use atomic operations. Any
+ /// use of the returned raw pointer requires an `unsafe` block and still has to uphold the same
+ /// restriction: operations on it must be atomic.
+ ///
+ /// # Examples
+ ///
+ /// ```ignore (extern-declaration)
+ /// #![feature(atomic_mut_ptr)]
+ //// use std::sync::atomic::AtomicPtr;
+ ///
+ /// extern "C" {
+ /// fn my_atomic_op(arg: *mut *mut u32);
+ /// }
+ ///
+ /// let mut value = 17;
+ /// let atomic = AtomicPtr::new(&mut value);
+ ///
+ /// // SAFETY: Safe as long as `my_atomic_op` is atomic.
+ /// unsafe {
+ /// my_atomic_op(atomic.as_mut_ptr());
+ /// }
+ /// ```
+ #[inline]
+ #[unstable(feature = "atomic_mut_ptr", reason = "recently added", issue = "66893")]
+ pub fn as_mut_ptr(&self) -> *mut *mut T {
+ self.p.get()
+ }
}
#[cfg(target_has_atomic_load_store = "8")]
#[doc = concat!(" fn my_atomic_op(arg: *mut ", stringify!($int_type), ");")]
/// }
///
- #[doc = concat!("let mut atomic = ", stringify!($atomic_type), "::new(1);")]
+ #[doc = concat!("let atomic = ", stringify!($atomic_type), "::new(1);")]
///
- // SAFETY: Safe as long as `my_atomic_op` is atomic.
+ /// // SAFETY: Safe as long as `my_atomic_op` is atomic.
/// unsafe {
/// my_atomic_op(atomic.as_mut_ptr());
/// }
// optional:
//
// one or more similar inputs for which data[input] succeeds,
- // and the corresponding output as an array. This helps validate
+ // and the corresponding output as an array. This helps validate
// "critical points" where an input range straddles the boundary
// between valid and invalid.
// (such as the input `len..len`, which is just barely valid)
}
/// Tests whether this file type represents a regular file.
- /// The result is mutually exclusive to the results of
+ /// The result is mutually exclusive to the results of
/// [`is_dir`] and [`is_symlink`]; only zero or one of these
/// tests may pass.
///
let mut reader = BufReader::with_capacity(5, ErrAfterFirstSeekReader { first_seek: true });
assert_eq!(reader.fill_buf().ok(), Some(&[0, 0, 0, 0, 0][..]));
- // The following seek will require two underlying seeks. The first will
- // succeed but the second will fail. This should still invalidate the
+ // The following seek will require two underlying seeks. The first will
+ // succeed but the second will fail. This should still invalidate the
// buffer.
assert!(reader.seek(SeekFrom::Current(i64::MIN)).is_err());
assert_eq!(reader.buffer().len(), 0);
//! This module is supported on Unix platforms and WASI, which both use a
//! similar file descriptor system for referencing OS resources.
-#![stable(feature = "io_safety", since = "1.63.0")]
+#![stable(feature = "os_fd", since = "1.66.0")]
#![deny(unsafe_op_in_unsafe_fn)]
// `RawFd`, `AsRawFd`, etc.
mod tests;
// Export the types and traits for the public API.
-#[unstable(feature = "os_fd", issue = "98699")]
+#[stable(feature = "os_fd", since = "1.66.0")]
pub use owned::*;
-#[unstable(feature = "os_fd", issue = "98699")]
+#[stable(feature = "os_fd", since = "1.66.0")]
pub use raw::*;
// For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics
// will never be supported, as this is a bare metal framework with
- // no capabilities for multi-process execution. While F_DUPFD is also
+ // no capabilities for multi-process execution. While F_DUPFD is also
// not supported yet, it might be (currently it returns ENOSYS).
#[cfg(target_os = "espidf")]
let cmd = libc::F_DUPFD;
// and after increase and decrease, but not necessarily during their execution.
//
// Additionally, the top bit of GLOBAL_PANIC_COUNT (GLOBAL_ALWAYS_ABORT_FLAG)
- // records whether panic::always_abort() has been called. This can only be
+ // records whether panic::always_abort() has been called. This can only be
// set, never cleared.
// panic::always_abort() is usually called to prevent memory allocations done by
// the panic handling in the child created by `libc::fork`.
- // Memory allocations performed in a child created with `libc::fork` are undefined
+ // Memory allocations performed in a child created with `libc::fork` are undefined
// behavior in most operating systems.
// Accessing LOCAL_PANIC_COUNT in a child created by `libc::fork` would lead to a memory
// allocation. Only GLOBAL_PANIC_COUNT can be accessed in this situation. This is
// true if path *physically* has a root separator; for most Windows
// prefixes, it may have a "logical" root separator for the purposes of
- // normalization, e.g., \\server\share == \\server\share\.
+ // normalization, e.g., \\server\share == \\server\share\.
has_physical_root: bool,
// The iterator is double-ended, and these two states keep track of what has
}
macro_rules! impl_cmp {
- ($lhs:ty, $rhs: ty) => {
+ (<$($life:lifetime),*> $lhs:ty, $rhs: ty) => {
#[stable(feature = "partialeq_path", since = "1.6.0")]
- impl<'a, 'b> PartialEq<$rhs> for $lhs {
+ impl<$($life),*> PartialEq<$rhs> for $lhs {
#[inline]
fn eq(&self, other: &$rhs) -> bool {
<Path as PartialEq>::eq(self, other)
}
#[stable(feature = "partialeq_path", since = "1.6.0")]
- impl<'a, 'b> PartialEq<$lhs> for $rhs {
+ impl<$($life),*> PartialEq<$lhs> for $rhs {
#[inline]
fn eq(&self, other: &$lhs) -> bool {
<Path as PartialEq>::eq(self, other)
}
#[stable(feature = "cmp_path", since = "1.8.0")]
- impl<'a, 'b> PartialOrd<$rhs> for $lhs {
+ impl<$($life),*> PartialOrd<$rhs> for $lhs {
#[inline]
fn partial_cmp(&self, other: &$rhs) -> Option<cmp::Ordering> {
<Path as PartialOrd>::partial_cmp(self, other)
}
#[stable(feature = "cmp_path", since = "1.8.0")]
- impl<'a, 'b> PartialOrd<$lhs> for $rhs {
+ impl<$($life),*> PartialOrd<$lhs> for $rhs {
#[inline]
fn partial_cmp(&self, other: &$lhs) -> Option<cmp::Ordering> {
<Path as PartialOrd>::partial_cmp(self, other)
};
}
-impl_cmp!(PathBuf, Path);
-impl_cmp!(PathBuf, &'a Path);
-impl_cmp!(Cow<'a, Path>, Path);
-impl_cmp!(Cow<'a, Path>, &'b Path);
-impl_cmp!(Cow<'a, Path>, PathBuf);
+impl_cmp!(<> PathBuf, Path);
+impl_cmp!(<'a> PathBuf, &'a Path);
+impl_cmp!(<'a> Cow<'a, Path>, Path);
+impl_cmp!(<'a, 'b> Cow<'a, Path>, &'b Path);
+impl_cmp!(<'a> Cow<'a, Path>, PathBuf);
macro_rules! impl_cmp_os_str {
- ($lhs:ty, $rhs: ty) => {
+ (<$($life:lifetime),*> $lhs:ty, $rhs: ty) => {
#[stable(feature = "cmp_path", since = "1.8.0")]
- impl<'a, 'b> PartialEq<$rhs> for $lhs {
+ impl<$($life),*> PartialEq<$rhs> for $lhs {
#[inline]
fn eq(&self, other: &$rhs) -> bool {
<Path as PartialEq>::eq(self, other.as_ref())
}
#[stable(feature = "cmp_path", since = "1.8.0")]
- impl<'a, 'b> PartialEq<$lhs> for $rhs {
+ impl<$($life),*> PartialEq<$lhs> for $rhs {
#[inline]
fn eq(&self, other: &$lhs) -> bool {
<Path as PartialEq>::eq(self.as_ref(), other)
}
#[stable(feature = "cmp_path", since = "1.8.0")]
- impl<'a, 'b> PartialOrd<$rhs> for $lhs {
+ impl<$($life),*> PartialOrd<$rhs> for $lhs {
#[inline]
fn partial_cmp(&self, other: &$rhs) -> Option<cmp::Ordering> {
<Path as PartialOrd>::partial_cmp(self, other.as_ref())
}
#[stable(feature = "cmp_path", since = "1.8.0")]
- impl<'a, 'b> PartialOrd<$lhs> for $rhs {
+ impl<$($life),*> PartialOrd<$lhs> for $rhs {
#[inline]
fn partial_cmp(&self, other: &$lhs) -> Option<cmp::Ordering> {
<Path as PartialOrd>::partial_cmp(self.as_ref(), other)
};
}
-impl_cmp_os_str!(PathBuf, OsStr);
-impl_cmp_os_str!(PathBuf, &'a OsStr);
-impl_cmp_os_str!(PathBuf, Cow<'a, OsStr>);
-impl_cmp_os_str!(PathBuf, OsString);
-impl_cmp_os_str!(Path, OsStr);
-impl_cmp_os_str!(Path, &'a OsStr);
-impl_cmp_os_str!(Path, Cow<'a, OsStr>);
-impl_cmp_os_str!(Path, OsString);
-impl_cmp_os_str!(&'a Path, OsStr);
-impl_cmp_os_str!(&'a Path, Cow<'b, OsStr>);
-impl_cmp_os_str!(&'a Path, OsString);
-impl_cmp_os_str!(Cow<'a, Path>, OsStr);
-impl_cmp_os_str!(Cow<'a, Path>, &'b OsStr);
-impl_cmp_os_str!(Cow<'a, Path>, OsString);
+impl_cmp_os_str!(<> PathBuf, OsStr);
+impl_cmp_os_str!(<'a> PathBuf, &'a OsStr);
+impl_cmp_os_str!(<'a> PathBuf, Cow<'a, OsStr>);
+impl_cmp_os_str!(<> PathBuf, OsString);
+impl_cmp_os_str!(<> Path, OsStr);
+impl_cmp_os_str!(<'a> Path, &'a OsStr);
+impl_cmp_os_str!(<'a> Path, Cow<'a, OsStr>);
+impl_cmp_os_str!(<> Path, OsString);
+impl_cmp_os_str!(<'a> &'a Path, OsStr);
+impl_cmp_os_str!(<'a, 'b> &'a Path, Cow<'b, OsStr>);
+impl_cmp_os_str!(<'a> &'a Path, OsString);
+impl_cmp_os_str!(<'a> Cow<'a, Path>, OsStr);
+impl_cmp_os_str!(<'a, 'b> Cow<'a, Path>, &'b OsStr);
+impl_cmp_os_str!(<'a> Cow<'a, Path>, OsString);
#[stable(since = "1.7.0", feature = "strip_prefix")]
impl fmt::Display for StripPrefixError {
return true;
}
Err(_) => {
- backoff.spin();
+ backoff.spin_light();
tail = self.tail.load(Ordering::Relaxed);
}
}
return false;
}
- backoff.spin();
+ backoff.spin_light();
tail = self.tail.load(Ordering::Relaxed);
} else {
// Snooze because we need to wait for the stamp to get updated.
- backoff.snooze();
+ backoff.spin_heavy();
tail = self.tail.load(Ordering::Relaxed);
}
}
return true;
}
Err(_) => {
- backoff.spin();
+ backoff.spin_light();
head = self.head.load(Ordering::Relaxed);
}
}
}
}
- backoff.spin();
+ backoff.spin_light();
head = self.head.load(Ordering::Relaxed);
} else {
// Snooze because we need to wait for the stamp to get updated.
- backoff.snooze();
+ backoff.spin_heavy();
head = self.head.load(Ordering::Relaxed);
}
}
if backoff.is_completed() {
break;
} else {
- backoff.spin();
+ backoff.spin_light();
}
}
fn wait_write(&self) {
let backoff = Backoff::new();
while self.state.load(Ordering::Acquire) & WRITE == 0 {
- backoff.snooze();
+ backoff.spin_heavy();
}
}
}
if !next.is_null() {
return next;
}
- backoff.snooze();
+ backoff.spin_heavy();
}
}
// If we reached the end of the block, wait until the next one is installed.
if offset == BLOCK_CAP {
- backoff.snooze();
+ backoff.spin_heavy();
tail = self.tail.index.load(Ordering::Acquire);
block = self.tail.block.load(Ordering::Acquire);
continue;
return true;
},
Err(_) => {
- backoff.spin();
+ backoff.spin_light();
tail = self.tail.index.load(Ordering::Acquire);
block = self.tail.block.load(Ordering::Acquire);
}
// If we reached the end of the block, wait until the next one is installed.
if offset == BLOCK_CAP {
- backoff.snooze();
+ backoff.spin_heavy();
head = self.head.index.load(Ordering::Acquire);
block = self.head.block.load(Ordering::Acquire);
continue;
// The block can be null here only if the first message is being sent into the channel.
// In that case, just wait until it gets initialized.
if block.is_null() {
- backoff.snooze();
+ backoff.spin_heavy();
head = self.head.index.load(Ordering::Acquire);
block = self.head.block.load(Ordering::Acquire);
continue;
return true;
},
Err(_) => {
- backoff.spin();
+ backoff.spin_light();
head = self.head.index.load(Ordering::Acquire);
block = self.head.block.load(Ordering::Acquire);
}
// New updates to tail will be rejected by MARK_BIT and aborted unless it's
// at boundary. We need to wait for the updates take affect otherwise there
// can be memory leaks.
- backoff.snooze();
+ backoff.spin_heavy();
tail = self.tail.index.load(Ordering::Acquire);
}
use crate::fmt;
use crate::panic::{RefUnwindSafe, UnwindSafe};
use crate::time::{Duration, Instant};
-use error::*;
+pub use error::*;
/// Creates a channel of unbounded capacity.
///
}
const SPIN_LIMIT: u32 = 6;
-const YIELD_LIMIT: u32 = 10;
-/// Performs exponential backoff in spin loops.
+/// Performs quadratic backoff in spin loops.
pub struct Backoff {
step: Cell<u32>,
}
Backoff { step: Cell::new(0) }
}
- /// Backs off in a lock-free loop.
+ /// Backs off using lightweight spinning.
///
- /// This method should be used when we need to retry an operation because another thread made
- /// progress.
+ /// This method should be used for:
+ /// - Retrying an operation because another thread made progress. i.e. on CAS failure.
+ /// - Waiting for an operation to complete by spinning optimistically for a few iterations
+ /// before falling back to parking the thread (see `Backoff::is_completed`).
#[inline]
- pub fn spin(&self) {
+ pub fn spin_light(&self) {
let step = self.step.get().min(SPIN_LIMIT);
for _ in 0..step.pow(2) {
crate::hint::spin_loop();
}
- if self.step.get() <= SPIN_LIMIT {
- self.step.set(self.step.get() + 1);
- }
+ self.step.set(self.step.get() + 1);
}
- /// Backs off in a blocking loop.
+ /// Backs off using heavyweight spinning.
+ ///
+ /// This method should be used in blocking loops where parking the thread is not an option.
#[inline]
- pub fn snooze(&self) {
+ pub fn spin_heavy(&self) {
if self.step.get() <= SPIN_LIMIT {
for _ in 0..self.step.get().pow(2) {
crate::hint::spin_loop()
crate::thread::yield_now();
}
- if self.step.get() <= YIELD_LIMIT {
- self.step.set(self.step.get() + 1);
- }
+ self.step.set(self.step.get() + 1);
}
- /// Returns `true` if quadratic backoff has completed and blocking the thread is advised.
+ /// Returns `true` if quadratic backoff has completed and parking the thread is advised.
#[inline]
pub fn is_completed(&self) -> bool {
- self.step.get() > YIELD_LIMIT
+ self.step.get() > SPIN_LIMIT
}
}
fn wait_ready(&self) {
let backoff = Backoff::new();
while !self.ready.load(Ordering::Acquire) {
- backoff.snooze();
+ backoff.spin_heavy();
}
}
}
pub fn try_send(&self, t: T) -> Result<(), TrySendError<T>> {
self.inner.try_send(t)
}
+
+ // Attempts to send for a value on this receiver, returning an error if the
+ // corresponding channel has hung up, or if it waits more than `timeout`.
+ //
+ // This method is currently private and only used for tests.
+ #[allow(unused)]
+ fn send_timeout(&self, t: T, timeout: Duration) -> Result<(), mpmc::SendTimeoutError<T>> {
+ self.inner.send_timeout(t, timeout)
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
use super::*;
use crate::env;
+use crate::sync::mpmc::SendTimeoutError;
use crate::thread;
use crate::time::Duration;
assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(1));
}
+#[test]
+fn send_timeout() {
+ let (tx, _rx) = sync_channel::<i32>(1);
+ assert_eq!(tx.send_timeout(1, Duration::from_millis(1)), Ok(()));
+ assert_eq!(tx.send_timeout(1, Duration::from_millis(1)), Err(SendTimeoutError::Timeout(1)));
+}
+
#[test]
fn smoke_threads() {
let (tx, rx) = sync_channel::<i32>(0);
// Terminate and delete the task
// Safety: `self.task` still represents a task we own (because
// this method or `join_inner` is called only once for
- // each `Thread`). The task indicated that it's safe to
+ // each `Thread`). The task indicated that it's safe to
// delete by entering the `FINISHED` state.
unsafe { terminate_and_delete_task(self.task) };
) -> Option<io::Result<FileAttr>> {
use crate::sync::atomic::{AtomicU8, Ordering};
- // Linux kernel prior to 4.11 or glibc prior to glibc 2.28 don't support `statx`
- // We store the availability in global to avoid unnecessary syscalls.
- // 0: Unknown
- // 1: Not available
- // 2: Available
- static STATX_STATE: AtomicU8 = AtomicU8::new(0);
+ // Linux kernel prior to 4.11 or glibc prior to glibc 2.28 don't support `statx`.
+ // We check for it on first failure and remember availability to avoid having to
+ // do it again.
+ #[repr(u8)]
+ enum STATX_STATE{ Unknown = 0, Present, Unavailable }
+ static STATX_SAVED_STATE: AtomicU8 = AtomicU8::new(STATX_STATE::Unknown as u8);
+
syscall! {
fn statx(
fd: c_int,
) -> c_int
}
- match STATX_STATE.load(Ordering::Relaxed) {
- 0 => {
- // It is a trick to call `statx` with null pointers to check if the syscall
- // is available. According to the manual, it is expected to fail with EFAULT.
- // We do this mainly for performance, since it is nearly hundreds times
- // faster than a normal successful call.
- let err = cvt(statx(0, ptr::null(), 0, libc::STATX_ALL, ptr::null_mut()))
- .err()
- .and_then(|e| e.raw_os_error());
- // We don't check `err == Some(libc::ENOSYS)` because the syscall may be limited
- // and returns `EPERM`. Listing all possible errors seems not a good idea.
- // See: https://github.com/rust-lang/rust/issues/65662
- if err != Some(libc::EFAULT) {
- STATX_STATE.store(1, Ordering::Relaxed);
- return None;
- }
- STATX_STATE.store(2, Ordering::Relaxed);
- }
- 1 => return None,
- _ => {}
+ if STATX_SAVED_STATE.load(Ordering::Relaxed) == STATX_STATE::Unavailable as u8 {
+ return None;
}
let mut buf: libc::statx = mem::zeroed();
if let Err(err) = cvt(statx(fd, path, flags, mask, &mut buf)) {
- return Some(Err(err));
+ if STATX_SAVED_STATE.load(Ordering::Relaxed) == STATX_STATE::Present as u8 {
+ return Some(Err(err));
+ }
+
+ // Availability not checked yet.
+ //
+ // First try the cheap way.
+ if err.raw_os_error() == Some(libc::ENOSYS) {
+ STATX_SAVED_STATE.store(STATX_STATE::Unavailable as u8, Ordering::Relaxed);
+ return None;
+ }
+
+ // Error other than `ENOSYS` is not a good enough indicator -- it is
+ // known that `EPERM` can be returned as a result of using seccomp to
+ // block the syscall.
+ // Availability is checked by performing a call which expects `EFAULT`
+ // if the syscall is usable.
+ // See: https://github.com/rust-lang/rust/issues/65662
+ // FIXME this can probably just do the call if `EPERM` was received, but
+ // previous iteration of the code checked it for all errors and for now
+ // this is retained.
+ // FIXME what about transient conditions like `ENOMEM`?
+ let err2 = cvt(statx(0, ptr::null(), 0, libc::STATX_ALL, ptr::null_mut()))
+ .err()
+ .and_then(|e| e.raw_os_error());
+ if err2 == Some(libc::EFAULT) {
+ STATX_SAVED_STATE.store(STATX_STATE::Present as u8, Ordering::Relaxed);
+ return Some(Err(err));
+ } else {
+ STATX_SAVED_STATE.store(STATX_STATE::Unavailable as u8, Ordering::Relaxed);
+ return None;
+ }
}
// We cannot fill `stat64` exhaustively because of private padding fields.
loop {
// As of POSIX.1-2017, readdir() is not required to be thread safe; only
// readdir_r() is. However, readdir_r() cannot correctly handle platforms
- // with unlimited or variable NAME_MAX. Many modern platforms guarantee
+ // with unlimited or variable NAME_MAX. Many modern platforms guarantee
// thread safety for readdir() as long an individual DIR* is not accessed
// concurrently, which is sufficient for Rust.
super::os::set_errno(0);
let entry_ptr = readdir64(self.inner.dirp.0);
if entry_ptr.is_null() {
- // We either encountered an error, or reached the end. Either way,
+ // We either encountered an error, or reached the end. Either way,
// the next call to next() should return None.
self.end_of_stream = true;
// - copy_file_range file is immutable or syscall is blocked by seccomp¹ (EPERM)
// - copy_file_range cannot be used with pipes or device nodes (EINVAL)
// - the writer fd was opened with O_APPEND (EBADF²)
- // and no bytes were written successfully yet. (All these errnos should
+ // and no bytes were written successfully yet. (All these errnos should
// not be returned if something was already written, but they happen in
// the wild, see #91152.)
//
// available on Fuchsia.
//
// It does not appear that Fuchsia is Unix-like enough to implement ExitStatus (or indeed many
- // other things from std::os::unix) properly. This veneer is always going to be a bodge. So
+ // other things from std::os::unix) properly. This veneer is always going to be a bodge. So
// while I don't know if these implementations are actually correct, I think they will do for
// now at least.
pub fn core_dumped(&self) -> bool {
pub fn into_raw(&self) -> c_int {
// We don't know what someone who calls into_raw() will do with this value, but it should
- // have the conventional Unix representation. Despite the fact that this is not
+ // have the conventional Unix representation. Despite the fact that this is not
// standardised in SuS or POSIX, all Unix systems encode the signal and exit status the
- // same way. (Ie the WIFEXITED, WEXITSTATUS etc. macros have identical behaviour on every
+ // same way. (Ie the WIFEXITED, WEXITSTATUS etc. macros have identical behaviour on every
// Unix.)
//
// The caller of `std::os::unix::into_raw` is probably wanting a Unix exit status, and may
// different Unix variant.
//
// The other view would be to say that the caller on Fuchsia ought to know that `into_raw`
- // will give a raw Fuchsia status (whatever that is - I don't know, personally). That is
+ // will give a raw Fuchsia status (whatever that is - I don't know, personally). That is
// not possible here because we must return a c_int because that's what Unix (including
// SuS and POSIX) say a wait status is, but Fuchsia apparently uses a u64, so it won't
// necessarily fit.
//
// It seems to me that the right answer would be to provide std::os::fuchsia with its
// own ExitStatusExt, rather that trying to provide a not very convincing imitation of
- // Unix. Ie, std::os::unix::process:ExitStatusExt ought not to exist on Fuchsia. But
+ // Unix. Ie, std::os::unix::process:ExitStatusExt ought not to exist on Fuchsia. But
// fixing this up that is beyond the scope of my efforts now.
let exit_status_as_if_unix: u8 = self.0.try_into().expect("Fuchsia process return code bigger than 8 bits, but std::os::unix::ExitStatusExt::into_raw() was called to try to convert the value into a traditional Unix-style wait status, which cannot represent values greater than 255.");
let wait_status_as_if_unix = (exit_status_as_if_unix as c_int) << 8;
}
pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
- // This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0. This is
+ // This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0. This is
// true on all actual versions of Unix, is widely assumed, and is specified in SuS
- // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html . If it is not
+ // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html. If it is not
// true for a platform pretending to be Unix, the tests (our doctests, and also
- // procsss_unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too.
+ // procsss_unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too.
match NonZero_c_int::try_from(self.0) {
/* was nonzero */ Ok(failure) => Err(ExitStatusError(failure)),
/* was zero, couldn't convert */ Err(_) => Ok(()),
t(0x00000, "exit status: 0");
t(0x0ff00, "exit status: 255");
- // On MacOS, 0x0137f is WIFCONTINUED, not WIFSTOPPED. Probably *BSD is similar.
+ // On MacOS, 0x0137f is WIFCONTINUED, not WIFSTOPPED. Probably *BSD is similar.
// https://github.com/rust-lang/rust/pull/82749#issuecomment-790525956
// The purpose of this test is to test our string formatting, not our understanding of the wait
- // status magic numbers. So restrict these to Linux.
+ // status magic numbers. So restrict these to Linux.
if cfg!(target_os = "linux") {
t(0x0137f, "stopped (not terminated) by signal: 19 (SIGSTOP)");
t(0x0ffff, "continued (WIFCONTINUED)");
}
// Testing "unrecognised wait status" is hard because the wait.h macros typically
- // assume that the value came from wait and isn't mad. With the glibc I have here
+ // assume that the value came from wait and isn't mad. With the glibc I have here
// this works:
if cfg!(all(target_os = "linux", target_env = "gnu")) {
t(0x000ff, "unrecognised wait status: 255 0xff");
}
pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
- // This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0. This is
+ // This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0. This is
// true on all actual versions of Unix, is widely assumed, and is specified in SuS
- // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html . If it is not
+ // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html. If it is not
// true for a platform pretending to be Unix, the tests (our doctests, and also
- // procsss_unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too.
+ // procsss_unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too.
match NonZero_c_int::try_from(self.0) {
Ok(failure) => Err(ExitStatusError(failure)),
Err(_) => Ok(()),
n => {
assert_eq!(n, libc::EINVAL);
// EINVAL means |stack_size| is either too small or not a
- // multiple of the system page size. Because it's definitely
+ // multiple of the system page size. Because it's definitely
// >= PTHREAD_STACK_MIN, it must be an alignment issue.
// Round up to the nearest page and try again.
let page_size = os::page_size();
if cfg!(all(target_os = "linux", not(target_env = "musl"))) {
// Linux doesn't allocate the whole stack right away, and
// the kernel has its own stack-guard mechanism to fault
- // when growing too close to an existing mapping. If we map
+ // when growing too close to an existing mapping. If we map
// our own guard, then the kernel starts enforcing a rather
// large gap above that, rendering much of the possible
- // stack space useless. See #43052.
+ // stack space useless. See #43052.
//
// Instead, we'll just note where we expect rlimit to start
// faulting, so our handler can report "stack overflow", and
None
} else if cfg!(target_os = "freebsd") {
// FreeBSD's stack autogrows, and optionally includes a guard page
- // at the bottom. If we try to remap the bottom of the stack
- // ourselves, FreeBSD's guard page moves upwards. So we'll just use
+ // at the bottom. If we try to remap the bottom of the stack
+ // ourselves, FreeBSD's guard page moves upwards. So we'll just use
// the builtin guard page.
let stackptr = get_stack_start_aligned()?;
let guardaddr = stackptr.addr();
// Technically the number of guard pages is tunable and controlled
// by the security.bsd.stack_guard_page sysctl, but there are
- // few reasons to change it from the default. The default value has
+ // few reasons to change it from the default. The default value has
// been 1 ever since FreeBSD 11.1 and 10.4.
const GUARD_PAGES: usize = 1;
let guard = guardaddr..guardaddr + GUARD_PAGES * page_size;
} else if cfg!(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))
{
// glibc used to include the guard area within the stack, as noted in the BUGS
- // section of `man pthread_attr_getguardsize`. This has been corrected starting
+ // section of `man pthread_attr_getguardsize`. This has been corrected starting
// with glibc 2.27, and in some distro backports, so the guard is now placed at the
- // end (below) the stack. There's no easy way for us to know which we have at
+ // end (below) the stack. There's no easy way for us to know which we have at
// runtime, so we'll just match any fault in the range right above or below the
// stack base to call that fault a stack overflow.
Some(stackaddr - guardsize..stackaddr + guardsize)
// Double quotes are used as a way of introducing literal semicolons
// (since c:\some;dir is a valid Windows path). Double quotes are not
// themselves permitted in path names, so there is no way to escape a
- // double quote. Quoted regions can appear in arbitrary locations, so
+ // double quote. Quoted regions can appear in arbitrary locations, so
//
// c:\foo;c:\som"e;di"r;c:\bar
//
// FIXME On UNIX, we guard against stack sizes that are too small but
// that's because pthreads enforces that stacks are at least
- // PTHREAD_STACK_MIN bytes big. Windows has no such lower limit, it's
+ // PTHREAD_STACK_MIN bytes big. Windows has no such lower limit, it's
// just that below a certain threshold you can't do anything useful.
// That threshold is application and architecture-specific, however.
let ret = c::CreateThread(
} else {
if !opts.nocapture {
// If we encounter a non-unwinding panic, flush any captured output from the current test,
- // and stop capturing output to ensure that the non-unwinding panic message is visible.
+ // and stop capturing output to ensure that the non-unwinding panic message is visible.
// We also acquire the locks for both output streams to prevent output from other threads
// from interleaving with the panic message or appearing after it.
let builtin_panic_hook = panic::take_hook();
}
} else {
// Found nothing in TERMINFO_DIRS, use the default paths:
- // According to /etc/terminfo/README, after looking at
+ // According to /etc/terminfo/README, after looking at
// ~/.terminfo, ncurses will search /etc/terminfo, then
// /lib/terminfo, and eventually /usr/share/terminfo.
// On Haiku the database can be found at /boot/system/data/terminfo
-This directory contains the source code of the rust project, including:
+This directory contains some source code for the Rust project, including:
-- The test suite
- The bootstrapping build system
-- Various submodules for tools, like cargo, etc.
+- Various submodules for tools, like cargo, tidy, etc.
For more information on how various parts of the compiler work, see the [rustc dev guide].
cmd.arg("-Z").arg("force-unstable-if-unmarked");
}
+ // allow-features is handled from within this rustc wrapper because of
+ // issues with build scripts. Some packages use build scripts to
+ // dynamically detect if certain nightly features are available.
+ // There are different ways this causes problems:
+ //
+ // * rustix runs `rustc` on a small test program to see if the feature is
+ // available (and sets a `cfg` if it is). It does not honor
+ // CARGO_ENCODED_RUSTFLAGS.
+ // * proc-macro2 detects if `rustc -vV` says "nighty" or "dev" and enables
+ // nightly features. It will scan CARGO_ENCODED_RUSTFLAGS for
+ // -Zallow-features. Unfortunately CARGO_ENCODED_RUSTFLAGS is not set
+ // for build-dependencies when --target is used.
+ //
+ // The issues above means we can't just use RUSTFLAGS, and we can't use
+ // `cargo -Zallow-features=…`. Passing it through here ensures that it
+ // always gets set. Unfortunately that also means we need to enable more
+ // features than we really want (like those for proc-macro2), but there
+ // isn't much of a way around it.
+ //
+ // I think it is unfortunate that build scripts are doing this at all,
+ // since changes to nightly features can cause crates to break even if the
+ // user didn't want or care about the use of the nightly features. I think
+ // nightly features should be opt-in only. Unfortunately the dynamic
+ // checks are now too wide spread that we just need to deal with it.
+ //
+ // If you want to try to remove this, I suggest working with the crate
+ // authors to remove the dynamic checking. Another option is to pursue
+ // https://github.com/rust-lang/cargo/issues/11244 and
+ // https://github.com/rust-lang/cargo/issues/4423, which will likely be
+ // very difficult, but could help expose -Zallow-features into build
+ // scripts so they could try to honor them.
+ if let Ok(allow_features) = env::var("RUSTC_ALLOW_FEATURES") {
+ cmd.arg(format!("-Zallow-features={allow_features}"));
+ }
+
if let Ok(flags) = env::var("MAGIC_EXTRA_RUSTFLAGS") {
for flag in flags.split(' ') {
cmd.arg(flag);
// this), as well as #63012 which is the tracking issue for this
// feature on the rustc side.
cargo.arg("-Zbinary-dep-depinfo");
- match mode {
- Mode::ToolBootstrap => {
- // Restrict the allowed features to those passed by rustbuild, so we don't depend on nightly accidentally.
- rustflags.arg("-Zallow-features=binary-dep-depinfo");
- }
- Mode::ToolStd => {
- // Right now this is just compiletest and a few other tools that build on stable.
- // Allow them to use `feature(test)`, but nothing else.
- rustflags.arg("-Zallow-features=binary-dep-depinfo,test,proc_macro_internals,proc_macro_diagnostic,proc_macro_span");
+ let allow_features = match mode {
+ Mode::ToolBootstrap | Mode::ToolStd => {
+ // Restrict the allowed features so we don't depend on nightly
+ // accidentally.
+ //
+ // binary-dep-depinfo is used by rustbuild itself for all
+ // compilations.
+ //
+ // Lots of tools depend on proc_macro2 and proc-macro-error.
+ // Those have build scripts which assume nightly features are
+ // available if the `rustc` version is "nighty" or "dev". See
+ // bin/rustc.rs for why that is a problem. Instead of labeling
+ // those features for each individual tool that needs them,
+ // just blanket allow them here.
+ //
+ // If this is ever removed, be sure to add something else in
+ // its place to keep the restrictions in place (or make a way
+ // to unset RUSTC_BOOTSTRAP).
+ "binary-dep-depinfo,proc_macro_span,proc_macro_span_shrink,proc_macro_diagnostic"
+ .to_string()
}
- Mode::Std | Mode::Rustc | Mode::Codegen | Mode::ToolRustc => {}
- }
+ Mode::Std | Mode::Rustc | Mode::Codegen | Mode::ToolRustc => String::new(),
+ };
cargo.arg("-j").arg(self.jobs().to_string());
}
}
- Cargo { command: cargo, rustflags, rustdocflags }
+ Cargo { command: cargo, rustflags, rustdocflags, allow_features }
}
/// Ensure that a given step is built, returning its output. This will
command: Command,
rustflags: Rustflags,
rustdocflags: Rustflags,
+ allow_features: String,
}
impl Cargo {
self.command.current_dir(dir);
self
}
+
+ /// Adds nightly-only features that this invocation is allowed to use.
+ ///
+ /// By default, all nightly features are allowed. Once this is called, it
+ /// will be restricted to the given set.
+ pub fn allow_features(&mut self, features: &str) -> &mut Cargo {
+ if !self.allow_features.is_empty() {
+ self.allow_features.push(',');
+ }
+ self.allow_features.push_str(features);
+ self
+ }
}
impl From<Cargo> for Command {
cargo.command.env("RUSTDOCFLAGS", rustdocflags);
}
+ if !cargo.allow_features.is_empty() {
+ cargo.command.env("RUSTC_ALLOW_FEATURES", cargo.allow_features);
+ }
+
cargo.command
}
}
&["rust-analyzer/in-rust-tree".to_owned()],
);
- cargo.rustflag(
- "-Zallow-features=proc_macro_internals,proc_macro_diagnostic,proc_macro_span",
- );
+ cargo.allow_features(crate::tool::RustAnalyzer::ALLOW_FEATURES);
// For ./x.py clippy, don't check those targets because
// linting tests and benchmarks can produce very noisy results
SourceType::InTree,
&["sysroot-abi".to_owned()],
);
+ cargo.allow_features(tool::RustAnalyzer::ALLOW_FEATURES);
let dir = builder.src.join(workspace_path);
// needed by rust-analyzer to find its own text fixtures, cf.
// We need `ToolStd` for the locally-built sysroot because
// compiletest uses unstable features of the `test` crate.
builder.ensure(compile::Std::new(compiler, host));
- let cargo = tool::prepare_tool_cargo(
+ let mut cargo = tool::prepare_tool_cargo(
builder,
compiler,
Mode::ToolStd,
SourceType::InTree,
&[],
);
+ cargo.allow_features("test");
try_run(builder, &mut cargo.into());
}
is_optional_tool: bool,
source_type: SourceType,
extra_features: Vec<String>,
+ /// Nightly-only features that are allowed (comma-separated list).
+ allow_features: &'static str,
}
impl Step for ToolBuild {
_ => panic!("unexpected Mode for tool build"),
}
- let cargo = prepare_tool_cargo(
+ let mut cargo = prepare_tool_cargo(
builder,
compiler,
self.mode,
self.source_type,
&self.extra_features,
);
+ if !self.allow_features.is_empty() {
+ cargo.allow_features(self.allow_features);
+ }
builder.info(&format!("Building stage{} tool {} ({})", compiler.stage, tool, target));
let mut duplicates = Vec::new();
$name:ident, $path:expr, $tool_name:expr
$(,is_external_tool = $external:expr)*
$(,is_unstable_tool = $unstable:expr)*
+ $(,allow_features = $allow_features:expr)?
;
)+) => {
#[derive(Copy, PartialEq, Eq, Clone)]
SourceType::InTree
},
extra_features: vec![],
+ allow_features: concat!($($allow_features)*),
}).expect("expected to build -- essential tool")
}
}
Tidy, "src/tools/tidy", "tidy";
Linkchecker, "src/tools/linkchecker", "linkchecker";
CargoTest, "src/tools/cargotest", "cargotest";
- Compiletest, "src/tools/compiletest", "compiletest", is_unstable_tool = true;
+ Compiletest, "src/tools/compiletest", "compiletest", is_unstable_tool = true, allow_features = "test";
BuildManifest, "src/tools/build-manifest", "build-manifest";
RemoteTestClient, "src/tools/remote-test-client", "remote-test-client";
RustInstaller, "src/tools/rust-installer", "rust-installer", is_external_tool = true;
is_optional_tool: false,
source_type: SourceType::InTree,
extra_features: Vec::new(),
+ allow_features: "",
})
.expect("expected to build -- essential tool")
}
is_optional_tool: false,
source_type: SourceType::InTree,
extra_features: Vec::new(),
+ allow_features: "",
})
.expect("expected to build -- essential tool")
}
is_optional_tool: false,
source_type: SourceType::Submodule,
extra_features: Vec::new(),
+ allow_features: "",
})
.expect("expected to build -- essential tool");
is_optional_tool: true,
source_type: SourceType::Submodule,
extra_features: Vec::new(),
+ allow_features: "",
});
};
is_optional_tool: false,
source_type: SourceType::InTree,
extra_features: Vec::new(),
+ allow_features: "",
})
.expect("expected to build -- essential tool");
pub target: TargetSelection,
}
+impl RustAnalyzer {
+ pub const ALLOW_FEATURES: &str =
+ "proc_macro_internals,proc_macro_diagnostic,proc_macro_span,proc_macro_span_shrink";
+}
+
impl Step for RustAnalyzer {
type Output = Option<PathBuf>;
const DEFAULT: bool = true;
extra_features: vec!["rust-analyzer/in-rust-tree".to_owned()],
is_optional_tool: false,
source_type: SourceType::InTree,
+ allow_features: RustAnalyzer::ALLOW_FEATURES,
})
}
}
extra_features: vec!["proc-macro-srv/sysroot-abi".to_owned()],
is_optional_tool: false,
source_type: SourceType::InTree,
+ allow_features: RustAnalyzer::ALLOW_FEATURES,
})?;
// Copy `rust-analyzer-proc-macro-srv` to `<sysroot>/libexec/`
$tool_name:expr,
stable = $stable:expr
$(,tool_std = $tool_std:literal)?
+ $(,allow_features = $allow_features:expr)?
;)+) => {
$(
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
extra_features: $sel.extra_features,
is_optional_tool: true,
source_type: SourceType::InTree,
+ allow_features: concat!($($allow_features)*),
})
}
}
git clone https://github.com/WebAssembly/wasi-libc
cd wasi-libc
-git reset --hard 8b7148f69ae241a2749b3defe4606da8143b72e0
+git reset --hard 4362b1885fd369e042a7c0ecd8df3b6cd47fb4e8
make -j$(nproc) \
CC="$bin/clang" \
NM="$bin/llvm-nm" \
python3 ../x.py test --stage 0 src/tools/compiletest && \
python3 ../x.py test --stage 0 core alloc std test proc_macro && \
# Build both public and internal documentation.
+ RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 0 compiler && \
RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 0 library/test && \
/scripts/validate-toolstate.sh && \
/scripts/validate-error-codes.sh && \
cargo test --tests
```
+> **Note**: The default for `LLVM_PROFILE_FILE` is `default_%m_%p.profraw`. Versions prior to 1.65 had a default of `default.profraw`, so if using those earlier versions, it is recommended to explicitly set `LLVM_PROFILE_FILE="default_%m_%p.profraw"` to avoid having multiple tests overwrite the `.profraw` files.
+
Make note of the test binary file paths, displayed after the word "`Running`" in the test output:
```text
## `invalid_html_tags`
-This lint is **allowed by default** and is **nightly-only**. It detects unclosed
+This lint **warns by default**. It detects unclosed
or invalid HTML tags. For example:
```rust
bound_params: Vec::new(),
})
})
- .chain(
- lifetime_to_bounds.into_iter().filter(|&(_, ref bounds)| !bounds.is_empty()).map(
- |(lifetime, bounds)| {
- let mut bounds_vec = bounds.into_iter().collect();
- self.sort_where_bounds(&mut bounds_vec);
- WherePredicate::RegionPredicate { lifetime, bounds: bounds_vec }
- },
- ),
- )
+ .chain(lifetime_to_bounds.into_iter().filter(|(_, bounds)| !bounds.is_empty()).map(
+ |(lifetime, bounds)| {
+ let mut bounds_vec = bounds.into_iter().collect();
+ self.sort_where_bounds(&mut bounds_vec);
+ WherePredicate::RegionPredicate { lifetime, bounds: bounds_vec }
+ },
+ ))
.collect()
}
trait_def_id,
impl_def_id
);
- let trait_ref = cx.tcx.bound_impl_trait_ref(impl_def_id).unwrap();
+ let trait_ref = cx.tcx.impl_trait_ref(impl_def_id).unwrap();
if !matches!(trait_ref.0.self_ty().kind(), ty::Param(_)) {
continue;
}
let _prof_timer = cx.tcx.sess.prof.generic_activity("build_impl");
let tcx = cx.tcx;
- let associated_trait = tcx.impl_trait_ref(did);
+ let associated_trait = tcx.impl_trait_ref(did).map(ty::EarlyBinder::skip_binder);
// Only inline impl if the implemented trait is
// reachable in rustdoc generated documentation
Some(def.def_id),
)),
default: match has_default {
- true => Some(Box::new(cx.tcx.const_param_default(def.def_id).to_string())),
+ true => Some(Box::new(
+ cx.tcx.const_param_default(def.def_id).subst_identity().to_string(),
+ )),
false => None,
},
},
// Look for equality predicates on associated types that can be merged into
// general bound predicates.
- equalities.retain(|&(ref lhs, ref rhs, ref bound_params)| {
+ equalities.retain(|(lhs, rhs, bound_params)| {
let Some((ty, trait_did, name)) = lhs.projection() else { return true; };
let Some((bounds, _)) = tybounds.get_mut(ty) else { return true };
let bound_params = bound_params
}
// Index this method for searching later on.
- if let Some(ref s) = item.name.or_else(|| {
+ if let Some(s) = item.name.or_else(|| {
if item.is_stripped() {
None
} else if let clean::ImportItem(ref i) = *item.kind &&
// for where the type was defined. On the other
// hand, `paths` always has the right
// information if present.
- Some(&(ref fqp, _)) => Some(&fqp[..fqp.len() - 1]),
+ Some((fqp, _)) => Some(&fqp[..fqp.len() - 1]),
None => None,
};
((did, path), true)
short_markdown_summary(x.as_str(), &item.link_names(self.cache))
});
let ty = item.type_();
- let name = s.to_string();
- if ty != ItemType::StructField || u16::from_str_radix(&name, 10).is_err() {
+ if ty != ItemType::StructField
+ || u16::from_str_radix(s.as_str(), 10).is_err()
+ {
// In case this is a field from a tuple struct, we don't add it into
// the search index because its name is something like "0", which is
// not useful for rustdoc search.
self.cache.search_index.push(IndexItem {
ty,
- name,
+ name: s,
path: join_with_double_colon(path),
desc,
parent,
root_path: Option<&str>,
) -> Result<(String, ItemType, Vec<Symbol>), HrefError> {
let tcx = cx.shared.tcx;
- let crate_name = tcx.crate_name(def_id.krate).to_string();
+ let crate_name = tcx.crate_name(def_id.krate);
let cache = cx.cache();
let fqp: Vec<Symbol> = tcx
}
})
.collect();
- let mut relative = fqp.iter().map(|elem| elem.to_string());
+ let mut relative = fqp.iter().copied();
let cstore = CStore::from_tcx(tcx);
// We need this to prevent a `panic` when this function is used from intra doc links...
if !cstore.has_crate_data(def_id.krate) {
};
let mut path = if is_macro_2 {
- once(crate_name.clone()).chain(relative).collect()
+ once(crate_name).chain(relative).collect()
} else {
- vec![crate_name.clone(), relative.next_back().unwrap()]
+ vec![crate_name, relative.next_back().unwrap()]
};
if path.len() < 2 {
// The minimum we can have is the crate name followed by the macro name. If shorter, then
}
if let Some(last) = path.last_mut() {
- *last = format!("macro.{}.html", last);
+ *last = Symbol::intern(&format!("macro.{}.html", last.as_str()));
}
let url = match cache.extern_locations[&def_id.krate] {
ExternalLocation::Remote(ref s) => {
// `ExternalLocation::Remote` always end with a `/`.
- format!("{}{}", s, path.join("/"))
+ format!("{}{}", s, path.iter().map(|p| p.as_str()).join("/"))
}
ExternalLocation::Local => {
// `root_path` always end with a `/`.
- format!("{}{}/{}", root_path.unwrap_or(""), crate_name, path.join("/"))
+ format!(
+ "{}{}/{}",
+ root_path.unwrap_or(""),
+ crate_name,
+ path.iter().map(|p| p.as_str()).join("/")
+ )
}
ExternalLocation::Unknown => {
debug!("crate {} not in cache when linkifying macros", crate_name);
clean::Tuple(ref typs) => {
match &typs[..] {
&[] => primitive_link(f, PrimitiveType::Unit, "()", cx),
- &[ref one] => {
+ [one] => {
if let clean::Generic(name) = one {
primitive_link(f, PrimitiveType::Tuple, &format!("({name},)"), cx)
} else {
_ => String::new(),
};
let m = mutability.print_with_space();
- let amp = if f.alternate() { "&".to_string() } else { "&".to_string() };
+ let amp = if f.alternate() { "&" } else { "&" };
match **ty {
clean::DynTrait(ref bounds, ref trait_lt)
if bounds.len() > 1 || trait_lt.is_some() =>
use rustc_hir::HirId;
use rustc_middle::ty::TyCtxt;
use rustc_span::edition::Edition;
-use rustc_span::Span;
+use rustc_span::{Span, Symbol};
use once_cell::sync::Lazy;
use std::borrow::Cow;
#[derive(Clone, Debug)]
pub struct Playground {
- pub crate_name: Option<String>,
+ pub crate_name: Option<Symbol>,
pub url: String,
}
.map(|l| map_line(l).for_code())
.intersperse("\n".into())
.collect::<String>();
- let krate = krate.as_ref().map(|s| &**s);
+ let krate = krate.as_ref().map(|s| s.as_str());
let (test, _, _) =
doctest::make_test(&test, krate, false, &Default::default(), edition, None);
let channel = if test.contains("#![feature(") { "&version=nightly" } else { "" };
// If user passed in `--playground-url` arg, we fill in crate name here
let mut playground = None;
if let Some(url) = playground_url {
- playground =
- Some(markdown::Playground { crate_name: Some(krate.name(tcx).to_string()), url });
+ playground = Some(markdown::Playground { crate_name: Some(krate.name(tcx)), url });
}
let mut layout = layout::Layout {
logo: String::new(),
}
(sym::html_playground_url, Some(s)) => {
playground = Some(markdown::Playground {
- crate_name: Some(krate.name(tcx).to_string()),
+ crate_name: Some(krate.name(tcx)),
url: s.to_string(),
});
}
write!(
buf,
"<div class=\"main-heading\">\
- <h1 class=\"fqn\">Rustdoc settings</h1>\
+ <h1>Rustdoc settings</h1>\
<span class=\"out-of-band\">\
<a id=\"back\" href=\"javascript:void(0)\" onclick=\"history.back();\">\
Back\
write!(
buf,
"<div class=\"main-heading\">\
- <h1 class=\"fqn\">Rustdoc help</h1>\
+ <h1>Rustdoc help</h1>\
<span class=\"out-of-band\">\
<a id=\"back\" href=\"javascript:void(0)\" onclick=\"history.back();\">\
Back\
#[derive(Debug)]
pub(crate) struct IndexItem {
pub(crate) ty: ItemType,
- pub(crate) name: String,
+ pub(crate) name: Symbol,
pub(crate) path: String,
pub(crate) desc: String,
pub(crate) parent: Option<DefId>,
}
}
- f.write_str("<h1 class=\"fqn\">List of all items</h1>");
+ f.write_str("<h1>List of all items</h1>");
// Note: print_entries does not escape the title, because we know the current set of titles
// doesn't require escaping.
print_entries(f, &self.structs, ItemSection::Structs);
let mut ids = IdMap::default();
format!(
"<div class=\"main-heading\">\
- <h1 class=\"fqn\">About scraped examples</h1>\
+ <h1>About scraped examples</h1>\
</div>\
<div>{}</div>",
Markdown {
debug!("Doc block: =====\n{}\n=====", s);
if is_collapsible {
w.write_str(
- "<details class=\"rustdoc-toggle top-doc\" open>\
+ "<details class=\"toggle top-doc\" open>\
<summary class=\"hideme\">\
<span>Expand description</span>\
</summary>",
write!(
&mut out,
"<h3>Notable traits for <code>{}</code></h3>\
- <pre class=\"content\"><code>",
+ <pre><code>",
impl_.for_.print(cx)
);
}
let toggled = !doc_buffer.is_empty();
if toggled {
let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
- write!(w, "<details class=\"rustdoc-toggle{}\" open><summary>", method_toggle_class);
+ write!(w, "<details class=\"toggle{}\" open><summary>", method_toggle_class);
}
match &*item.kind {
clean::MethodItem(..) | clean::TyMethodItem(_) => {
close_tags.insert_str(0, "</details>");
write!(
w,
- "<details class=\"rustdoc-toggle implementors-toggle\"{}>",
+ "<details class=\"toggle implementors-toggle\"{}>",
if rendering_params.toggle_open_by_default { " open" } else { "" }
);
write!(w, "<summary>")
let mut work = VecDeque::new();
let mut process_path = |did: DefId| {
- let get_extern = || cache.external_paths.get(&did).map(|s| s.0.clone());
- let fqp = cache.exact_paths.get(&did).cloned().or_else(get_extern);
+ let get_extern = || cache.external_paths.get(&did).map(|s| &s.0);
+ let fqp = cache.exact_paths.get(&did).or_else(get_extern);
if let Some(path) = fqp {
out.push(join_with_double_colon(&path));
if it.peek().is_some() {
write!(
w,
- "<details class=\"rustdoc-toggle more-examples-toggle\">\
+ "<details class=\"toggle more-examples-toggle\">\
<summary class=\"hideme\">\
<span>More examples</span>\
</summary>\
fn toggle_open(w: &mut Buffer, text: impl fmt::Display) {
write!(
w,
- "<details class=\"rustdoc-toggle type-contents-toggle\">\
+ "<details class=\"toggle type-contents-toggle\">\
<summary class=\"hideme\">\
<span>Show {}</span>\
</summary>",
let toggled = !content.is_empty();
if toggled {
let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
- write!(w, "<details class=\"rustdoc-toggle{method_toggle_class}\" open><summary>");
+ write!(w, "<details class=\"toggle{method_toggle_class}\" open><summary>");
}
write!(w, "<section id=\"{}\" class=\"method has-srclink\">", id);
render_rightside(w, cx, m, t, RenderMode::Normal);
.chain(std::iter::once("implementors"))
.collect();
if let Some(did) = it.item_id.as_def_id() &&
- let get_extern = { || cache.external_paths.get(&did).map(|s| s.0.clone()) } &&
- let Some(fqp) = cache.exact_paths.get(&did).cloned().or_else(get_extern) {
+ let get_extern = { || cache.external_paths.get(&did).map(|s| &s.0) } &&
+ let Some(fqp) = cache.exact_paths.get(&did).or_else(get_extern) {
js_src_path.extend(fqp[..fqp.len() - 1].iter().copied());
js_src_path.push_fmt(format_args!("{}.{}.js", it.type_(), fqp.last().unwrap()));
} else {
if item.is_non_exhaustive() {
write!(
w,
- "<details class=\"rustdoc-toggle non-exhaustive\">\
+ "<details class=\"toggle non-exhaustive\">\
<summary class=\"hideme\"><span>{}</span></summary>\
<div class=\"docblock\">",
{
// Attach all orphan items to the type's definition if the type
// has since been learned.
for &OrphanImplItem { parent, ref item, ref impl_generics } in &cache.orphan_impl_items {
- if let Some(&(ref fqp, _)) = cache.paths.get(&parent) {
+ if let Some((fqp, _)) = cache.paths.get(&parent) {
let desc = item
.doc_value()
.map_or_else(String::new, |s| short_markdown_summary(&s, &item.link_names(cache)));
cache.search_index.push(IndexItem {
ty: item.type_(),
- name: item.name.unwrap().to_string(),
+ name: item.name.unwrap(),
path: join_with_double_colon(&fqp[..fqp.len() - 1]),
desc,
parent: Some(parent),
// Sort search index items. This improves the compressibility of the search index.
cache.search_index.sort_unstable_by(|k1, k2| {
// `sort_unstable_by_key` produces lifetime errors
- let k1 = (&k1.path, &k1.name, &k1.ty, &k1.parent);
- let k2 = (&k2.path, &k2.name, &k2.ty, &k2.parent);
+ let k1 = (&k1.path, k1.name.as_str(), &k1.ty, &k1.parent);
+ let k2 = (&k2.path, k2.name.as_str(), &k2.ty, &k2.parent);
std::cmp::Ord::cmp(&k1, &k2)
});
)?;
crate_data.serialize_field(
"n",
- &self.items.iter().map(|item| &item.name).collect::<Vec<_>>(),
+ &self.items.iter().map(|item| item.name.as_str()).collect::<Vec<_>>(),
)?;
crate_data.serialize_field(
"q",
)?;
crate_data.serialize_field(
"p",
- &self.paths.iter().map(|(it, s)| (it, s.to_string())).collect::<Vec<_>>(),
+ &self.paths.iter().map(|(it, s)| (it, s.as_str())).collect::<Vec<_>>(),
)?;
if has_aliases {
crate_data.serialize_field("a", &self.aliases)?;
let decl = &func.decl;
let combined_generics;
- let (self_, generics) = if let Some(&(ref impl_self, ref impl_generics)) = impl_generics {
+ let (self_, generics) = if let Some((impl_self, impl_generics)) = impl_generics {
match (impl_generics.is_empty(), func.generics.is_empty()) {
(true, _) => (Some(impl_self), &func.generics),
(_, true) => (Some(impl_self), impl_generics),
};
let content = format!(
- "<h1 class=\"fqn\">List of all crates</h1><ul class=\"all-items\">{}</ul>",
+ "<h1>List of all crates</h1><ul class=\"all-items\">{}</ul>",
krates
.iter()
.map(|s| {
.docblock > h6:first-child {
margin-top: 0;
}
-h1.fqn {
+.main-heading h1 {
margin: 0;
padding: 0;
flex-grow: 1;
margin-right: auto;
}
-details:not(.rustdoc-toggle) summary {
+details:not(.toggle) summary {
margin-bottom: .6em;
}
content: "\00a0";
}
-.notable .docblock {
+.notable .content {
margin: 0.25em 0.5em;
}
-.notable .docblock pre, .notable .docblock code {
+.notable .content pre, .notable .content code {
background: transparent;
margin: 0;
padding: 0;
white-space: pre-wrap;
}
+.notable .content > h3:first-child {
+ margin: 0 0 5px 0;
+}
+
.search-failed {
text-align: center;
margin-top: 20px;
Unfortunately we can't yet specify contain: content or contain: strict
because the [-]/[+] toggles extend past the boundaries of the <details>
https://developer.mozilla.org/en-US/docs/Web/CSS/contain */
-details.rustdoc-toggle {
+details.toggle {
contain: layout;
position: relative;
}
/* The hideme class is used on summary tags that contain a span with
placeholder text shown only when the toggle is closed. For instance,
"Expand description" or "Show methods". */
-details.rustdoc-toggle > summary.hideme {
+details.toggle > summary.hideme {
cursor: pointer;
font-size: 1rem;
}
-details.rustdoc-toggle > summary {
+details.toggle > summary {
list-style: none;
/* focus outline is shown on `::before` instead of this */
outline: none;
}
-details.rustdoc-toggle > summary::-webkit-details-marker,
-details.rustdoc-toggle > summary::marker {
+details.toggle > summary::-webkit-details-marker,
+details.toggle > summary::marker {
display: none;
}
-details.rustdoc-toggle > summary.hideme > span {
+details.toggle > summary.hideme > span {
margin-left: 9px;
}
-details.rustdoc-toggle > summary::before {
+details.toggle > summary::before {
background: url("toggle-plus-1092eb4930d581b0.svg") no-repeat top left;
content: "";
cursor: pointer;
filter: var(--toggle-filter);
}
-details.rustdoc-toggle > summary.hideme > span,
+details.toggle > summary.hideme > span,
.more-examples-toggle summary, .more-examples-toggle .hide-more {
color: var(--toggles-color);
}
/* Screen readers see the text version at the end the line.
Visual readers see the icon at the start of the line, but small and transparent. */
-details.rustdoc-toggle > summary::after {
+details.toggle > summary::after {
content: "Expand";
overflow: hidden;
width: 0;
position: absolute;
}
-details.rustdoc-toggle > summary.hideme::after {
+details.toggle > summary.hideme::after {
/* "hideme" toggles already have a description when they're contracted */
content: "";
}
-details.rustdoc-toggle > summary:focus::before,
-details.rustdoc-toggle > summary:hover::before {
+details.toggle > summary:focus::before,
+details.toggle > summary:hover::before {
opacity: 1;
}
-details.rustdoc-toggle > summary:focus-visible::before {
+details.toggle > summary:focus-visible::before {
/* The SVG is black, and gets turned white using a filter in the dark themes.
Do the same with the outline.
The dotted 1px style is copied from Firefox's focus ring style.
margin-bottom: 8px;
}
-details.rustdoc-toggle > summary.hideme::before {
+details.toggle > summary.hideme::before {
position: relative;
}
-details.rustdoc-toggle > summary:not(.hideme)::before {
+details.toggle > summary:not(.hideme)::before {
position: absolute;
left: -24px;
top: 4px;
}
-.impl-items > details.rustdoc-toggle > summary:not(.hideme)::before {
+.impl-items > details.toggle > summary:not(.hideme)::before {
position: absolute;
left: -24px;
}
affect the layout of the items to its right. To do that, we use
absolute positioning. Note that we also set position: relative
on the parent <details> to make this work properly. */
-details.rustdoc-toggle[open] > summary.hideme {
+details.toggle[open] > summary.hideme {
position: absolute;
}
-details.rustdoc-toggle[open] > summary.hideme > span {
+details.toggle[open] > summary.hideme > span {
display: none;
}
-details.rustdoc-toggle[open] > summary::before {
+details.toggle[open] > summary::before {
background: url("toggle-minus-31bbd6e4c77f5c96.svg") no-repeat top left;
}
-details.rustdoc-toggle[open] > summary::after {
+details.toggle[open] > summary::after {
content: "Collapse";
}
display: block;
}
- #main-content > details.rustdoc-toggle > summary::before,
- #main-content > div > details.rustdoc-toggle > summary::before {
+ #main-content > details.toggle > summary::before,
+ #main-content > div > details.toggle > summary::before {
left: -11px;
}
}
/* Position of the "[-]" element. */
- details.rustdoc-toggle:not(.top-doc) > summary {
+ details.toggle:not(.top-doc) > summary {
margin-left: 10px;
}
- .impl-items > details.rustdoc-toggle > summary:not(.hideme)::before,
- #main-content > details.rustdoc-toggle:not(.top-doc) > summary::before,
- #main-content > div > details.rustdoc-toggle > summary::before {
+ .impl-items > details.toggle > summary:not(.hideme)::before,
+ #main-content > details.toggle:not(.top-doc) > summary::before,
+ #main-content > div > details.toggle > summary::before {
left: -11px;
}
@media print {
nav.sidebar, nav.sub, .out-of-band, a.srclink, #copy-path,
- details.rustdoc-toggle[open] > summary::before, details.rustdoc-toggle > summary::before,
- details.rustdoc-toggle.top-doc > summary {
+ details.toggle[open] > summary::before, details.toggle > summary::before,
+ details.toggle.top-doc > summary {
display: none;
}
.impl,
#implementors-list > .docblock,
.impl-items > section,
-.impl-items > .rustdoc-toggle > summary,
+.impl-items > .toggle > summary,
.methods > section,
-.methods > .rustdoc-toggle > summary
+.methods > .toggle > summary
{
margin-bottom: 0.75em;
}
.variants > .docblock,
.implementors-toggle > .docblock,
-.impl-items > .rustdoc-toggle[open]:not(:last-child),
-.methods > .rustdoc-toggle[open]:not(:last-child),
+.impl-items > .toggle[open]:not(:last-child),
+.methods > .toggle[open]:not(:last-child),
.implementors-toggle[open]:not(:last-child) {
margin-bottom: 2em;
}
-#trait-implementations-list .impl-items > .rustdoc-toggle:not(:last-child),
-#synthetic-implementations-list .impl-items > .rustdoc-toggle:not(:last-child),
-#blanket-implementations-list .impl-items > .rustdoc-toggle:not(:last-child) {
+#trait-implementations-list .impl-items > .toggle:not(:last-child),
+#synthetic-implementations-list .impl-items > .toggle:not(:last-child),
+#blanket-implementations-list .impl-items > .toggle:not(:last-child) {
margin-bottom: 1em;
}
}
.setting-line .radio-line input,
-.setting-line .toggle input {
+.setting-line .settings-toggle input {
margin-right: 0.3em;
height: 1.2rem;
width: 1.2rem;
.setting-line .radio-line input {
border-radius: 50%;
}
-.setting-line .toggle input:checked {
+.setting-line .settings-toggle input:checked {
content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40">\
<path d="M7,25L17,32L33,12" fill="none" stroke="black" stroke-width="5"/>\
<path d="M7,23L17,30L33,10" fill="none" stroke="white" stroke-width="5"/></svg>');
}
.setting-line .radio-line input + span,
-.setting-line .toggle span {
+.setting-line .settings-toggle span {
padding-bottom: 1px;
}
margin-left: 0.5em;
}
-.toggle {
+.settings-toggle {
position: relative;
width: 100%;
margin-right: 20px;
box-shadow: inset 0 0 0 3px var(--main-background-color);
background-color: var(--settings-input-color);
}
-.setting-line .toggle input:checked {
+.setting-line .settings-toggle input:checked {
background-color: var(--settings-input-color);
}
.setting-line .radio-line input:focus,
-.setting-line .toggle input:focus {
+.setting-line .settings-toggle input:focus {
box-shadow: 0 0 1px 1px var(--settings-input-color);
}
/* In here we combine both `:focus` and `:checked` properties. */
0 0 2px 2px var(--settings-input-color);
}
.setting-line .radio-line input:hover,
-.setting-line .toggle input:hover {
+.setting-line .settings-toggle input:hover {
border-color: var(--settings-input-color) !important;
}
}
let currentNbImpls = implementors.getElementsByClassName("impl").length;
- const traitName = document.querySelector("h1.fqn > .trait").textContent;
+ const traitName = document.querySelector(".main-heading h1 > .trait").textContent;
const baseIdName = "impl-" + traitName + "-";
const libs = Object.getOwnPropertyNames(imp);
// We don't want to include impls from this JS file, when the HTML already has them.
function expandAllDocs() {
const innerToggle = document.getElementById(toggleAllDocsId);
removeClass(innerToggle, "will-expand");
- onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => {
+ onEachLazy(document.getElementsByClassName("toggle"), e => {
if (!hasClass(e, "type-contents-toggle") && !hasClass(e, "more-examples-toggle")) {
e.open = true;
}
function collapseAllDocs() {
const innerToggle = document.getElementById(toggleAllDocsId);
addClass(innerToggle, "will-expand");
- onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => {
+ onEachLazy(document.getElementsByClassName("toggle"), e => {
if (e.parentNode.id !== "implementations-list" ||
(!hasClass(e, "implementors-toggle") &&
!hasClass(e, "type-contents-toggle"))
setImplementorsTogglesOpen("blanket-implementations-list", false);
}
- onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => {
+ onEachLazy(document.getElementsByClassName("toggle"), e => {
if (!hideLargeItemContents && hasClass(e, "type-contents-toggle")) {
e.open = true;
}
});
});
- onEachLazy(document.querySelectorAll(".rustdoc-toggle > summary:not(.hideme)"), el => {
+ onEachLazy(document.querySelectorAll(".toggle > summary:not(.hideme)"), el => {
el.addEventListener("click", e => {
if (e.target.tagName !== "SUMMARY" && e.target.tagName !== "A") {
e.preventDefault();
window.hideAllModals(false);
const ty = e.getAttribute("data-ty");
const wrapper = document.createElement("div");
- wrapper.innerHTML = "<div class=\"docblock\">" + window.NOTABLE_TRAITS[ty] + "</div>";
+ wrapper.innerHTML = "<div class=\"content\">" + window.NOTABLE_TRAITS[ty] + "</div>";
wrapper.className = "notable popover";
const focusCatcher = document.createElement("div");
focusCatcher.setAttribute("tabindex", "0");
});
output += "</div></div>";
} else {
- // This is a toggle.
+ // This is a checkbox toggle.
const checked = setting["default"] === true ? " checked" : "";
output += `\
-<label class="toggle">\
+<label class="settings-toggle">\
<input type="checkbox" id="${js_data_name}"${checked}>\
<span class="label">${setting_name}</span>\
</label>`;
<div class="main-heading"> {#- -#}
- <h1 class="fqn"> {#- -#}
+ <h1> {#- -#}
{{-typ-}}
{#- The breadcrumbs of the item path, like std::string -#}
{%- for component in path_components -%}
let crate_version = options.crate_version.clone();
let output_format = options.output_format;
- let externs = options.externs.clone();
let scrape_examples_options = options.scrape_examples_options.clone();
let bin_crate = options.bin_crate;
let resolver_caches = resolver.borrow_mut().access(|resolver| {
collect_intra_doc_links::early_resolve_intra_doc_links(
resolver,
- sess,
krate,
- externs,
render_options.document_private,
)
});
tcx.find_map_relevant_impl(trait_, ty, |impl_| {
let trait_ref = tcx.impl_trait_ref(impl_).expect("this is not an inherent impl");
// Check if these are the same type.
- let impl_type = trait_ref.self_ty();
+ let impl_type = trait_ref.skip_binder().self_ty();
trace!(
"comparing type {} with kind {:?} against type {:?}",
impl_type,
use rustc_hir::TraitCandidate;
use rustc_middle::ty::{DefIdTree, Visibility};
use rustc_resolve::{ParentScope, Resolver};
-use rustc_session::config::Externs;
-use rustc_session::Session;
use rustc_span::symbol::sym;
use rustc_span::{Symbol, SyntaxContext};
pub(crate) fn early_resolve_intra_doc_links(
resolver: &mut Resolver<'_>,
- sess: &Session,
krate: &ast::Crate,
- externs: Externs,
document_private_items: bool,
) -> ResolverCaches {
let parent_scope =
ParentScope::module(resolver.expect_module(CRATE_DEF_ID.to_def_id()), resolver);
let mut link_resolver = EarlyDocLinkResolver {
resolver,
- sess,
parent_scope,
visited_mods: Default::default(),
markdown_links: Default::default(),
// the known necessary crates. Load them all unconditionally until we find a way to fix this.
// DO NOT REMOVE THIS without first testing on the reproducer in
// https://github.com/jyn514/objr/commit/edcee7b8124abf0e4c63873e8422ff81beb11ebb
- for (extern_name, _) in externs.iter().filter(|(_, entry)| entry.add_prelude) {
+ for (extern_name, _) in
+ link_resolver.resolver.sess().opts.externs.iter().filter(|(_, entry)| entry.add_prelude)
+ {
link_resolver.resolver.resolve_rustdoc_path(extern_name, TypeNS, parent_scope);
}
struct EarlyDocLinkResolver<'r, 'ra> {
resolver: &'r mut Resolver<'ra>,
- sess: &'r Session,
parent_scope: ParentScope<'ra>,
visited_mods: DefIdSet,
markdown_links: FxHashMap<String, Vec<PreprocessedMarkdownLink>>,
fn resolve_doc_links_extern_impl(&mut self, def_id: DefId, is_inherent: bool) {
self.resolve_doc_links_extern_outer_fixme(def_id, def_id);
let assoc_item_def_ids = Vec::from_iter(
- self.resolver.cstore().associated_item_def_ids_untracked(def_id, self.sess),
+ self.resolver.cstore().associated_item_def_ids_untracked(def_id, self.resolver.sess()),
);
for assoc_def_id in assoc_item_def_ids {
if !is_inherent || self.resolver.cstore().visibility_untracked(assoc_def_id).is_public()
if !self.resolver.cstore().may_have_doc_links_untracked(def_id) {
return;
}
- let attrs = Vec::from_iter(self.resolver.cstore().item_attrs_untracked(def_id, self.sess));
+ let attrs = Vec::from_iter(
+ self.resolver.cstore().item_attrs_untracked(def_id, self.resolver.sess()),
+ );
let parent_scope = ParentScope::module(
self.resolver.get_nearest_non_block_module(
self.resolver.opt_parent(scope_id).unwrap_or(scope_id),
if !self.resolver.cstore().may_have_doc_links_untracked(def_id) {
return;
}
- let attrs = Vec::from_iter(self.resolver.cstore().item_attrs_untracked(def_id, self.sess));
+ let attrs = Vec::from_iter(
+ self.resolver.cstore().item_attrs_untracked(def_id, self.resolver.sess()),
+ );
let parent_scope = ParentScope::module(self.resolver.expect_module(def_id), self.resolver);
self.resolve_doc_links(doc_attrs(attrs.iter()), parent_scope);
}
let field_def_ids = Vec::from_iter(
self.resolver
.cstore()
- .associated_item_def_ids_untracked(def_id, self.sess),
+ .associated_item_def_ids_untracked(def_id, self.resolver.sess()),
);
for field_def_id in field_def_ids {
self.resolve_doc_links_extern_outer(field_def_id, scope_id);
}
// handled in the `strip-priv-imports` pass
- clean::ExternCrateItem { .. } => {}
- clean::ImportItem(ref imp) => {
- // Because json doesn't inline imports from private modules, we need to mark
- // the imported item as retained so it's impls won't be stripped.
- //
- // FIXME: Is it necessary to check for json output here: See
- // https://github.com/rust-lang/rust/pull/100325#discussion_r941495215
- if let Some(did) = imp.source.did && self.is_json_output {
- self.retained.insert(did.into());
- }
- }
+ clean::ExternCrateItem { .. } | clean::ImportItem(_) => {}
clean::ImplItem(..) => {}
-Subproject commit d992ab4e9034930e7809749f04077045af8f4d79
+Subproject commit 1cd6d3803dfb0b342272862a8590f5dfc9f72573
// Only care about `impl PartialEq<Foo> for Foo`
// For `impl PartialEq<B> for A, input_types is [A, B]
- if trait_ref.substs.type_at(1) == ty {
+ if trait_ref.subst_identity().substs.type_at(1) == ty {
span_lint_and_then(
cx,
DERIVED_HASH_WITH_MANUAL_EQ,
// Only care about `impl PartialOrd<Foo> for Foo`
// For `impl PartialOrd<B> for A, input_types is [A, B]
- if trait_ref.substs.type_at(1) == ty {
+ if trait_ref.subst_identity().substs.type_at(1) == ty {
let mess = if partial_ord_is_automatically_derived {
"you are implementing `Ord` explicitly but have derived `PartialOrd`"
} else {
if_chain! {
if let hir::ItemKind::Impl(impl_) = &item.kind;
if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id);
- if cx.tcx.is_diagnostic_item(sym::From, impl_trait_ref.def_id);
+ if cx.tcx.is_diagnostic_item(sym::From, impl_trait_ref.skip_binder().def_id);
then {
lint_impl_body(cx, item.span, impl_.items);
}
&& let Some(into_trait_seg) = hir_trait_ref.path.segments.last()
// `impl Into<target_ty> for self_ty`
&& let Some(GenericArgs { args: [GenericArg::Type(target_ty)], .. }) = into_trait_seg.args
- && let Some(middle_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
+ && let Some(middle_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id).map(ty::EarlyBinder::subst_identity)
&& cx.tcx.is_diagnostic_item(sym::Into, middle_trait_ref.def_id)
&& !matches!(middle_trait_ref.substs.type_at(1).kind(), ty::Alias(ty::Opaque, _))
{
let container_id = assoc_item.container_id(cx.tcx);
let trait_def_id = match assoc_item.container {
TraitContainer => Some(container_id),
- ImplContainer => cx.tcx.impl_trait_ref(container_id).map(|t| t.def_id),
+ ImplContainer => cx.tcx.impl_trait_ref(container_id).map(|t| t.skip_binder().def_id),
};
if let Some(trait_def_id) = trait_def_id {
if send_trait == trait_id;
if hir_impl.polarity == ImplPolarity::Positive;
if let Some(ty_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id);
- if let self_ty = ty_trait_ref.self_ty();
+ if let self_ty = ty_trait_ref.subst_identity().self_ty();
if let ty::Adt(adt_def, impl_trait_substs) = self_ty.kind();
then {
let mut non_send_fields = Vec::new();
})) => {
#[allow(trivial_casts)]
if let Some(Node::Item(item)) = get_parent_node(cx.tcx, owner_id.into())
- && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
+ && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id).map(|t| t.subst_identity())
&& let Some(trait_item_id) = cx.tcx.associated_item(owner_id).trait_item_def_id
{
(
then {
// `self_ty` is the semantic self type of `impl <trait> for <type>`. This cannot be
// `Self`.
- let self_ty = impl_trait_ref.self_ty();
+ let self_ty = impl_trait_ref.subst_identity().self_ty();
// `trait_method_sig` is the signature of the function, how it is declared in the
// trait, not in the impl of the trait.
}
// test `stat`
- assert_eq!(fs::metadata("foo.txt").unwrap_err().kind(), ErrorKind::PermissionDenied);
+ let err = fs::metadata("foo.txt").unwrap_err();
+ assert_eq!(err.kind(), ErrorKind::PermissionDenied);
// check that it is the right kind of `PermissionDenied`
- assert_eq!(Error::last_os_error().raw_os_error(), Some(libc::EACCES));
+ assert_eq!(err.raw_os_error(), Some(libc::EACCES));
}
edition = "2021"
[dependencies]
-clap = "3.1.1"
+clap = "4.0.32"
env_logger = "0.7.1"
[dependencies.mdbook]
-version = "0.4.21"
+version = "0.4.25"
default-features = false
features = ["search"]
use mdbook::MDBook;
fn main() {
- let crate_version = format!("v{}", crate_version!());
+ let crate_version = concat!("v", crate_version!());
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("warn")).init();
let d_arg = arg!(-d --"dest-dir" <DEST_DIR>
"The output directory for your book\n(Defaults to ./book when omitted)")
- .required(false);
- let dir_arg = arg!([dir]
-"A directory for your book\n(Defaults to Current Directory when omitted)");
+ .required(false)
+ .value_parser(clap::value_parser!(PathBuf));
+
+ let dir_arg = arg!([dir] "Root directory for the book\n\
+ (Defaults to the current directory when omitted)")
+ .value_parser(clap::value_parser!(PathBuf));
let matches = Command::new("rustbook")
.about("Build a book with mdBook")
.author("Steve Klabnik <steve@steveklabnik.com>")
- .version(&*crate_version)
+ .version(crate_version)
.subcommand_required(true)
.arg_required_else_help(true)
.subcommand(
// Set this to allow us to catch bugs in advance.
book.config.build.create_missing = false;
- if let Some(dest_dir) = args.value_of("dest-dir") {
- book.config.build.build_dir = PathBuf::from(dest_dir);
+ if let Some(dest_dir) = args.get_one::<PathBuf>("dest-dir") {
+ book.config.build.build_dir = dest_dir.into();
}
book.build()?;
}
fn get_book_dir(args: &ArgMatches) -> PathBuf {
- if let Some(dir) = args.value_of("dir") {
+ if let Some(p) = args.get_one::<PathBuf>("dir") {
// Check if path is relative from current dir, or absolute...
- let p = Path::new(dir);
- if p.is_relative() { env::current_dir().unwrap().join(dir) } else { p.to_path_buf() }
+ if p.is_relative() { env::current_dir().unwrap().join(p) } else { p.to_path_buf() }
} else {
env::current_dir().unwrap()
}
[dependencies]
cargo_metadata = "0.14"
+cargo-platform = "0.1.2"
regex = "1"
miropt-test-tools = { path = "../miropt-test-tools" }
lazy_static = "1"
//! Checks the licenses of third-party dependencies.
-use cargo_metadata::{Metadata, Package, PackageId, Resolve};
-use std::collections::{BTreeSet, HashSet};
+use cargo_metadata::{DepKindInfo, Metadata, Package, PackageId};
+use std::collections::HashSet;
use std::path::Path;
/// These are licenses that are allowed for all crates, including the runtime,
"autocfg",
"bitflags",
"block-buffer",
- "bumpalo", // Included in Cargo's dep graph but only activated on wasm32-*-unknown.
"cc",
"cfg-if",
"chalk-derive",
"chalk-engine",
"chalk-ir",
"chalk-solve",
- "chrono",
"convert_case", // dependency of derive_more
"compiler_builtins",
"cpufeatures",
"dlmalloc",
"either",
"ena",
- "env_logger",
"expect-test",
"fallible-iterator", // dependency of `thorin`
"fastrand",
- "filetime",
"fixedbitset",
"flate2",
"fluent-bundle",
"gsgdt",
"hashbrown",
"hermit-abi",
- "humantime",
"icu_list",
"icu_locid",
"icu_provider",
"icu_provider_adapters",
"icu_provider_macros",
- "if_chain",
"indexmap",
"instant",
"intl-memoizer",
"itertools",
"itoa",
"jobserver",
- "js-sys", // Included in Cargo's dep graph but only activated on wasm32-*-unknown.
"lazy_static",
"libc",
"libloading",
"memmap2",
"memoffset",
"miniz_oxide",
- "num-integer",
- "num-traits",
"num_cpus",
"object",
"odht",
"proc-macro2",
"psm",
"punycode",
- "quick-error",
"quote",
"rand",
"rand_chacha",
"serde",
"serde_derive",
"serde_json",
- "sha-1",
+ "sha1",
"sha2",
"sharded-slab",
"smallvec",
"thiserror-impl",
"thorin-dwp",
"thread_local",
- "time",
"tinystr",
"tinyvec",
"tinyvec_macros",
"valuable",
"version_check",
"wasi",
- // vvv Included in Cargo's dep graph but only activated on wasm32-*-unknown.
- "wasm-bindgen",
- "wasm-bindgen-backend",
- "wasm-bindgen-macro",
- "wasm-bindgen-macro-support",
- "wasm-bindgen-shared",
- // ^^^ Included in Cargo's dep graph but only activated on wasm32-*-unknown.
"winapi",
"winapi-i686-pc-windows-gnu",
"winapi-util",
restricted_dependency_crates: &[&'static str],
bad: &mut bool,
) {
+ let mut deps = HashSet::new();
+ for to_check in restricted_dependency_crates {
+ let to_check = pkg_from_name(metadata, to_check);
+ use cargo_platform::Cfg;
+ use std::str::FromStr;
+ // We don't expect the compiler to ever run on wasm32, so strip
+ // out those dependencies to avoid polluting the permitted list.
+ deps_of_filtered(metadata, &to_check.id, &mut deps, &|dep_kinds| {
+ dep_kinds.iter().any(|dep_kind| {
+ dep_kind
+ .target
+ .as_ref()
+ .map(|target| {
+ !target.matches(
+ "wasm32-unknown-unknown",
+ &[
+ Cfg::from_str("target_arch=\"wasm32\"").unwrap(),
+ Cfg::from_str("target_os=\"unknown\"").unwrap(),
+ ],
+ )
+ })
+ .unwrap_or(true)
+ })
+ });
+ }
+
// Check that the PERMITTED_DEPENDENCIES does not have unused entries.
- for name in permitted_dependencies {
- if !metadata.packages.iter().any(|p| p.name == *name) {
+ for permitted in permitted_dependencies {
+ if !deps.iter().any(|dep_id| &pkg_from_id(metadata, dep_id).name == permitted) {
tidy_error!(
bad,
- "could not find allowed package `{}`\n\
+ "could not find allowed package `{permitted}`\n\
Remove from PERMITTED_DEPENDENCIES list if it is no longer used.",
- name
);
}
}
- // Get the list in a convenient form.
- let permitted_dependencies: HashSet<_> = permitted_dependencies.iter().cloned().collect();
-
- // Check dependencies.
- let mut visited = BTreeSet::new();
- let mut unapproved = BTreeSet::new();
- for &krate in restricted_dependency_crates.iter() {
- let pkg = pkg_from_name(metadata, krate);
- let mut bad =
- check_crate_dependencies(&permitted_dependencies, metadata, &mut visited, pkg);
- unapproved.append(&mut bad);
- }
-
- if !unapproved.is_empty() {
- tidy_error!(bad, "Dependencies for {} not explicitly permitted:", descr);
- for dep in unapproved {
- println!("* {dep}");
- }
- }
-}
-
-/// Checks the dependencies of the given crate from the given cargo metadata to see if they are on
-/// the list of permitted dependencies. Returns a list of disallowed dependencies.
-fn check_crate_dependencies<'a>(
- permitted_dependencies: &'a HashSet<&'static str>,
- metadata: &'a Metadata,
- visited: &mut BTreeSet<&'a PackageId>,
- krate: &'a Package,
-) -> BTreeSet<&'a PackageId> {
- // This will contain bad deps.
- let mut unapproved = BTreeSet::new();
-
- // Check if we have already visited this crate.
- if visited.contains(&krate.id) {
- return unapproved;
- }
- visited.insert(&krate.id);
+ // Get in a convenient form.
+ let permitted_dependencies: HashSet<_> = permitted_dependencies.iter().cloned().collect();
- // If this path is in-tree, we don't require it to be explicitly permitted.
- if krate.source.is_some() {
- // If this dependency is not on `PERMITTED_DEPENDENCIES`, add to bad set.
- if !permitted_dependencies.contains(krate.name.as_str()) {
- unapproved.insert(&krate.id);
+ for dep in deps {
+ let dep = pkg_from_id(metadata, dep);
+ // If this path is in-tree, we don't require it to be explicitly permitted.
+ if dep.source.is_some() {
+ if !permitted_dependencies.contains(dep.name.as_str()) {
+ tidy_error!(bad, "Dependency for {descr} not explicitly permitted: {}", dep.id);
+ }
}
}
-
- // Do a DFS in the crate graph.
- let to_check = deps_of(metadata, &krate.id);
-
- for dep in to_check {
- let mut bad = check_crate_dependencies(permitted_dependencies, metadata, visited, dep);
- unapproved.append(&mut bad);
- }
-
- unapproved
}
/// Prevents multiple versions of some expensive crates.
}
}
-/// Returns a list of dependencies for the given package.
-fn deps_of<'a>(metadata: &'a Metadata, pkg_id: &'a PackageId) -> Vec<&'a Package> {
- let resolve = metadata.resolve.as_ref().unwrap();
- let node = resolve
- .nodes
- .iter()
- .find(|n| &n.id == pkg_id)
- .unwrap_or_else(|| panic!("could not find `{pkg_id}` in resolve"));
- node.deps
- .iter()
- .map(|dep| {
- metadata.packages.iter().find(|pkg| pkg.id == dep.pkg).unwrap_or_else(|| {
- panic!("could not find dep `{}` for pkg `{}` in resolve", dep.pkg, pkg_id)
- })
- })
- .collect()
-}
-
/// Finds a package with the given name.
fn pkg_from_name<'a>(metadata: &'a Metadata, name: &'static str) -> &'a Package {
let mut i = metadata.packages.iter().filter(|p| p.name == name);
result
}
+fn pkg_from_id<'a>(metadata: &'a Metadata, id: &PackageId) -> &'a Package {
+ metadata.packages.iter().find(|p| &p.id == id).unwrap()
+}
+
/// Finds all the packages that are in the rust runtime.
fn compute_runtime_crates<'a>(metadata: &'a Metadata) -> HashSet<&'a PackageId> {
- let resolve = metadata.resolve.as_ref().unwrap();
let mut result = HashSet::new();
for name in RUNTIME_CRATES {
let id = &pkg_from_name(metadata, name).id;
- normal_deps_of_r(resolve, id, &mut result);
+ deps_of_filtered(metadata, id, &mut result, &|_| true);
}
result
}
-/// Recursively find all normal dependencies.
-fn normal_deps_of_r<'a>(
- resolve: &'a Resolve,
+/// Recursively find all dependencies.
+fn deps_of_filtered<'a>(
+ metadata: &'a Metadata,
pkg_id: &'a PackageId,
result: &mut HashSet<&'a PackageId>,
+ filter: &dyn Fn(&[DepKindInfo]) -> bool,
) {
if !result.insert(pkg_id) {
return;
}
- let node = resolve
+ let node = metadata
+ .resolve
+ .as_ref()
+ .unwrap()
.nodes
.iter()
.find(|n| &n.id == pkg_id)
.unwrap_or_else(|| panic!("could not find `{pkg_id}` in resolve"));
for dep in &node.deps {
- normal_deps_of_r(resolve, &dep.pkg, result);
+ if !filter(&dep.dep_kinds) {
+ continue;
+ }
+ deps_of_filtered(metadata, &dep.pkg, result, filter);
}
}
+fn direct_deps_of<'a>(metadata: &'a Metadata, pkg_id: &'a PackageId) -> Vec<&'a Package> {
+ let resolve = metadata.resolve.as_ref().unwrap();
+ let node = resolve.nodes.iter().find(|n| &n.id == pkg_id).unwrap();
+ node.deps.iter().map(|dep| pkg_from_id(metadata, &dep.pkg)).collect()
+}
+
fn check_rustfix(metadata: &Metadata, bad: &mut bool) {
let cargo = pkg_from_name(metadata, "cargo");
let compiletest = pkg_from_name(metadata, "compiletest");
- let cargo_deps = deps_of(metadata, &cargo.id);
- let compiletest_deps = deps_of(metadata, &compiletest.id);
+ let cargo_deps = direct_deps_of(metadata, &cargo.id);
+ let compiletest_deps = direct_deps_of(metadata, &compiletest.id);
let cargo_rustfix = cargo_deps.iter().find(|p| p.name == "rustfix").unwrap();
let compiletest_rustfix = compiletest_deps.iter().find(|p| p.name == "rustfix").unwrap();
if cargo_rustfix.version != compiletest_rustfix.version {
pub mod mir_opt_tests;
pub mod pal;
pub mod primitive_docs;
+pub mod rustdoc_gui_tests;
pub mod style;
pub mod target_specific_tests;
pub mod tests_placement;
check!(debug_artifacts, &tests_path);
check!(ui_tests, &tests_path);
check!(mir_opt_tests, &tests_path, bless);
+ check!(rustdoc_gui_tests, &tests_path);
// Checks that only make sense for the compiler.
check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose);
--- /dev/null
+//! Tidy check to ensure that rustdoc GUI tests start with a small description.
+
+use std::path::Path;
+
+pub fn check(path: &Path, bad: &mut bool) {
+ crate::walk::walk(
+ &path.join("rustdoc-gui"),
+ &mut |p| {
+ // If there is no extension, it's very likely a folder and we want to go into it.
+ p.extension().map(|e| e != "goml").unwrap_or(false)
+ },
+ &mut |entry, content| {
+ for line in content.lines() {
+ if !line.starts_with("// ") {
+ tidy_error!(
+ bad,
+ "{}: rustdoc-gui tests must start with a small description",
+ entry.path().display(),
+ );
+ return;
+ } else if line.starts_with("// ") {
+ let parts = line[2..].trim();
+ // We ignore tidy comments.
+ if parts.starts_with("// tidy-") {
+ continue;
+ }
+ // All good!
+ return;
+ }
+ }
+ },
+ );
+}
// prevent optimizing away bounds checks
// compile-flags: -O
+// ignore-debug: the debug assertions get in the way
#![crate_type="rlib"]
})
}
-static S: i32 = 5;
-static mut T: i32 = 10;
+static S: i32 = 0x05050505;
+static mut T: i32 = 0x0a0a0a0a;
// EMIT_MIR consts.statics.built.after.mir
#[custom_mir(dialect = "built")]
fn statics() {
}
alloc2 (static: T, size: 4, align: 4) {
- 0a 00 00 00 │ ....
+ 0a 0a 0a 0a │ ....
}
alloc1 (static: S, size: 4, align: 4) {
- 05 00 00 00 │ ....
+ 05 05 05 05 │ ....
}
}
alloc1 (static: STATIC, size: 4, align: 4) {
- 2a 00 00 00 │ *...
+ 42 42 42 42 │ BBBB
}
// unit-test
// compile-flags: -O
-static mut STATIC: u32 = 42;
+static mut STATIC: u32 = 0x42424242;
// EMIT_MIR mutable_variable_no_prop.main.ConstProp.diff
fn main() {
let mut _6: (); // in scope 0 at $DIR/inline_into_box_place.rs:+1:42: +1:43
let mut _7: *const std::vec::Vec<u32>; // in scope 0 at $DIR/inline_into_box_place.rs:+1:29: +1:43
+ let mut _8: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
++ let mut _9: std::vec::Vec<u32>; // in scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
scope 1 {
debug _x => _1; // in scope 1 at $DIR/inline_into_box_place.rs:+1:9: +1:11
}
scope 2 {
}
+ scope 3 (inlined Vec::<u32>::new) { // at $DIR/inline_into_box_place.rs:8:33: 8:43
-+ let mut _9: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++ let mut _10: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+ }
bb0: {
- (*_7) = Vec::<u32>::new() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
+ StorageLive(_8); // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
+ _8 = &mut (*_7); // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
-+ StorageLive(_9); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+ _9 = const _; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++ StorageLive(_9); // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
++ StorageLive(_10); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++ _10 = const _; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
// mir::Constant
- // + span: $DIR/inline_into_box_place.rs:8:33: 8:41
- // + user_ty: UserType(1)
+ // + span: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+ // + user_ty: UserType(0)
+ // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Unevaluated(alloc::raw_vec::RawVec::<T>::NEW, [u32], None) }
-+ Deinit((*_8)); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+ ((*_8).0: alloc::raw_vec::RawVec<u32>) = move _9; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+ ((*_8).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+ StorageDead(_9); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++ Deinit(_9); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++ (_9.0: alloc::raw_vec::RawVec<u32>) = move _10; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++ (_9.1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++ StorageDead(_10); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++ (*_8) = move _9; // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
++ StorageDead(_9); // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
+ StorageDead(_8); // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
_1 = move _5; // scope 0 at $DIR/inline_into_box_place.rs:+1:29: +1:43
StorageDead(_5); // scope 0 at $DIR/inline_into_box_place.rs:+1:42: +1:43
--- /dev/null
+- // MIR for `outer` before Inline
++ // MIR for `outer` after Inline
+
+ fn outer() -> usize {
+ let mut _0: usize; // return place in scope 0 at $DIR/issue_106141.rs:+0:19: +0:24
++ scope 1 (inlined inner) { // at $DIR/issue_106141.rs:2:5: 2:12
++ let mut _1: bool; // in scope 1 at $DIR/issue_106141.rs:13:8: 13:21
++ let mut _2: bool; // in scope 1 at $DIR/issue_106141.rs:13:8: 13:21
++ let mut _3: &[bool; 1]; // in scope 1 at $DIR/issue_106141.rs:11:18: 11:25
++ scope 2 {
++ debug buffer => _3; // in scope 2 at $DIR/issue_106141.rs:11:9: 11:15
++ scope 3 {
++ debug index => _0; // in scope 3 at $DIR/issue_106141.rs:12:9: 12:14
++ }
++ }
++ }
+
+ bb0: {
+- _0 = inner() -> bb1; // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12
++ StorageLive(_3); // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12
++ _3 = const _; // scope 1 at $DIR/issue_106141.rs:11:18: 11:25
+ // mir::Constant
+- // + span: $DIR/issue_106141.rs:2:5: 2:10
+- // + literal: Const { ty: fn() -> usize {inner}, val: Value(<ZST>) }
++ // + span: $DIR/issue_106141.rs:11:18: 11:25
++ // + literal: Const { ty: &[bool; 1], val: Unevaluated(inner, [], Some(promoted[0])) }
++ _0 = index() -> bb1; // scope 2 at $DIR/issue_106141.rs:12:17: 12:24
++ // mir::Constant
++ // + span: $DIR/issue_106141.rs:12:17: 12:22
++ // + literal: Const { ty: fn() -> usize {index}, val: Value(<ZST>) }
+ }
+
+ bb1: {
++ StorageLive(_1); // scope 3 at $DIR/issue_106141.rs:13:8: 13:21
++ _2 = Lt(_0, const 1_usize); // scope 3 at $DIR/issue_106141.rs:13:8: 13:21
++ assert(move _2, "index out of bounds: the length is {} but the index is {}", const 1_usize, _0) -> bb2; // scope 3 at $DIR/issue_106141.rs:13:8: 13:21
++ }
++
++ bb2: {
++ _1 = (*_3)[_0]; // scope 3 at $DIR/issue_106141.rs:13:8: 13:21
++ switchInt(move _1) -> [0: bb3, otherwise: bb4]; // scope 3 at $DIR/issue_106141.rs:13:8: 13:21
++ }
++
++ bb3: {
++ _0 = const 0_usize; // scope 3 at $DIR/issue_106141.rs:16:9: 16:10
++ goto -> bb4; // scope 3 at $DIR/issue_106141.rs:13:5: 17:6
++ }
++
++ bb4: {
++ StorageDead(_1); // scope 3 at $DIR/issue_106141.rs:17:5: 17:6
++ StorageDead(_3); // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12
+ return; // scope 0 at $DIR/issue_106141.rs:+2:2: +2:2
+ }
+ }
+
--- /dev/null
+pub fn outer() -> usize {
+ inner()
+}
+
+fn index() -> usize {
+ loop {}
+}
+
+#[inline]
+fn inner() -> usize {
+ let buffer = &[true];
+ let index = index();
+ if buffer[index] {
+ index
+ } else {
+ 0
+ }
+}
+
+fn main() {
+ outer();
+}
+
+// EMIT_MIR issue_106141.outer.Inline.diff
_3 = _1; // scope 2 at $DIR/issue_75439.rs:+2:47: +2:52
_2 = transmute::<[u8; 16], [u32; 4]>(move _3) -> bb1; // scope 2 at $DIR/issue_75439.rs:+2:37: +2:53
// mir::Constant
- // + span: $DIR/issue_75439.rs:7:37: 7:46
+ // + span: $DIR/issue_75439.rs:8:37: 8:46
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn([u8; 16]) -> [u32; 4] {transmute::<[u8; 16], [u32; 4]>}, val: Value(<ZST>) }
}
_6 = _4; // scope 4 at $DIR/issue_75439.rs:+5:33: +5:35
_5 = transmute::<u32, [u8; 4]>(move _6) -> bb7; // scope 4 at $DIR/issue_75439.rs:+5:23: +5:36
// mir::Constant
- // + span: $DIR/issue_75439.rs:10:23: 10:32
+ // + span: $DIR/issue_75439.rs:11:23: 11:32
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) -> [u8; 4] {transmute::<u32, [u8; 4]>}, val: Value(<ZST>) }
}
// EMIT_MIR issue_75439.foo.MatchBranchSimplification.diff
+// ignore-endian-big
use std::mem::transmute;
define-function: (
"check-colors",
- (theme, main_color, title_color, fqn_color, fqn_type_color, src_link_color, sidebar_link_color),
+ (theme, main_color, title_color, main_heading_color, main_heading_type_color, src_link_color, sidebar_link_color),
block {
goto: "file://" + |DOC_PATH| + "/staged_api/struct.Foo.html"
// This is needed to ensure that the text color is computed.
reload:
assert-css: ("#toggle-all-docs", {"color": |main_color|})
- assert-css: (".fqn a:nth-of-type(1)", {"color": |fqn_color|})
- assert-css: (".fqn a:nth-of-type(2)", {"color": |fqn_type_color|})
+ assert-css: (".main-heading h1 a:nth-of-type(1)", {"color": |main_heading_color|})
+ assert-css: (".main-heading a:nth-of-type(2)", {"color": |main_heading_type_color|})
assert-css: (
".rightside .srclink",
{"color": |src_link_color|, "text-decoration": "none solid " + |src_link_color|},
assert-css: ("#top-doc-prose-title", {"color": |title_color|})
assert-css: (".sidebar a", {"color": |sidebar_link_color|})
- assert-css: ("h1.fqn a", {"color": |title_color|})
+ assert-css: (".main-heading h1 a", {"color": |title_color|})
// We move the cursor over the "Implementations" title so the anchor is displayed.
move-cursor-to: "h2#implementations"
"theme": "ayu",
"main_color": "rgb(197, 197, 197)",
"title_color": "rgb(255, 255, 255)",
- "fqn_color": "rgb(255, 255, 255)",
- "fqn_type_color": "rgb(255, 160, 165)",
+ "main_heading_color": "rgb(255, 255, 255)",
+ "main_heading_type_color": "rgb(255, 160, 165)",
"src_link_color": "rgb(57, 175, 215)",
"sidebar_link_color": "rgb(83, 177, 219)",
},
"theme": "dark",
"main_color": "rgb(221, 221, 221)",
"title_color": "rgb(221, 221, 221)",
- "fqn_color": "rgb(221, 221, 221)",
- "fqn_type_color": "rgb(45, 191, 184)",
+ "main_heading_color": "rgb(221, 221, 221)",
+ "main_heading_type_color": "rgb(45, 191, 184)",
"src_link_color": "rgb(210, 153, 29)",
"sidebar_link_color": "rgb(253, 191, 53)",
},
"theme": "light",
"main_color": "rgb(0, 0, 0)",
"title_color": "rgb(0, 0, 0)",
- "fqn_color": "rgb(0, 0, 0)",
- "fqn_type_color": "rgb(173, 55, 138)",
+ "main_heading_color": "rgb(0, 0, 0)",
+ "main_heading_type_color": "rgb(173, 55, 138)",
"src_link_color": "rgb(56, 115, 173)",
"sidebar_link_color": "rgb(53, 109, 164)",
},
+// Small test to ensure the "src-line-numbers" element is only present once on
+// the page.
goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
click: ".srclink"
wait-for: ".src-line-numbers"
// 14px 0.875rem
goto: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html"
-assert-css: ("h1.fqn", {"font-size": "24px"})
+assert-css: (".main-heading h1", {"font-size": "24px"})
assert-css: ("h2#top-doc-prose-title", {"font-size": "22px"})
assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
goto: "file://" + |DOC_PATH| + "/test_docs/enum.HeavilyDocumentedEnum.html"
-assert-css: ("h1.fqn", {"font-size": "24px"})
+assert-css: (".main-heading h1", {"font-size": "24px"})
assert-css: ("h2#top-doc-prose-title", {"font-size": "22px"})
assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
goto: "file://" + |DOC_PATH| + "/test_docs/union.HeavilyDocumentedUnion.html"
-assert-css: ("h1.fqn", {"font-size": "24px"})
+assert-css: (".main-heading h1", {"font-size": "24px"})
assert-css: ("h2#top-doc-prose-title", {"font-size": "22px"})
assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
goto: "file://" + |DOC_PATH| + "/test_docs/macro.heavily_documented_macro.html"
-assert-css: ("h1.fqn", {"font-size": "24px"})
+assert-css: (".main-heading h1", {"font-size": "24px"})
assert-css: ("h2#top-doc-prose-title", {"font-size": "22px"})
assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
// This test ensures that the margins on methods are coherent inside an impl block.
goto: "file://" + |DOC_PATH| + "/test_docs/trait_members/struct.HasTrait.html#impl-TraitMembers-for-HasTrait"
-assert-count: ("#trait-implementations-list > .rustdoc-toggle", 1)
+assert-count: ("#trait-implementations-list > .toggle", 1)
compare-elements-css: (
// compare margin on type with margin on method
- "#trait-implementations-list .impl-items > .rustdoc-toggle:nth-child(1) > summary",
- "#trait-implementations-list .impl-items > .rustdoc-toggle:nth-child(2) > summary",
+ "#trait-implementations-list .impl-items > .toggle:nth-child(1) > summary",
+ "#trait-implementations-list .impl-items > .toggle:nth-child(2) > summary",
["margin"]
)
compare-elements-css: (
// compare margin on type with margin on method
- "#trait-implementations-list .impl-items > .rustdoc-toggle:nth-child(1)",
- "#trait-implementations-list .impl-items > .rustdoc-toggle:nth-child(2)",
+ "#trait-implementations-list .impl-items > .toggle:nth-child(1)",
+ "#trait-implementations-list .impl-items > .toggle:nth-child(2)",
["margin"]
)
+// This test ensures that the scraped examples buttons are working as expecting
+// when 'Enter' key is pressed when they're focused.
goto: "file://" + |DOC_PATH| + "/scrape_examples/fn.test.html"
// The next/prev buttons vertically scroll the code viewport between examples
// First, we check that the first page doesn't have the string we're looking for to ensure
// that the feature is changing page as expected.
goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
-assert-text-false: (".fqn", "Struct test_docs::Foo")
+assert-text-false: (".main-heading h1", "Struct test_docs::Foo")
// We now check that we land on the search result page if "go_to_first" isn't set.
goto: "file://" + |DOC_PATH| + "/test_docs/index.html?search=struct%3AFoo"
// Waiting for the search results to appear...
wait-for: "#search-tabs"
-assert-text-false: (".fqn", "Struct test_docs::Foo")
+assert-text-false: (".main-heading h1", "Struct test_docs::Foo")
// Ensure that the search results are displayed, not the "normal" content.
assert-css: ("#main-content", {"display": "none"})
// Now we can check that the feature is working as expected!
goto: "file://" + |DOC_PATH| + "/test_docs/index.html?search=struct%3AFoo&go_to_first=true"
// Waiting for the page to load...
-wait-for-text: (".fqn", "Struct test_docs::Foo")
+wait-for-text: (".main-heading h1", "Struct test_docs::Foo")
// We now check that clicking on the toggles' text is like clicking on the checkbox.
// To test it, we use the "Disable keyboard shortcuts".
local-storage: {"rustdoc-disable-shortcuts": "false"}
-click: ".setting-line:last-child .toggle .label"
+click: ".setting-line:last-child .settings-toggle .label"
assert-local-storage: {"rustdoc-disable-shortcuts": "true"}
// Make sure that "Disable keyboard shortcuts" actually took effect.
wait-for-css: ("#settings-menu .popover", {"display": "block"})
// Now turn keyboard shortcuts back on, and see if they work.
-click: ".setting-line:last-child .toggle .label"
+click: ".setting-line:last-child .settings-toggle .label"
assert-local-storage: {"rustdoc-disable-shortcuts": "false"}
press-key: "Escape"
press-key: "?"
// This test ensures that clicking on a method summary, but not on the "[-]",
// doesn't toggle the <details>.
goto: "file://" + |DOC_PATH| + "/lib2/struct.Foo.html"
-assert-attribute: (".impl-items .rustdoc-toggle", {"open": ""})
+assert-attribute: (".impl-items .toggle", {"open": ""})
click: "h4.code-header" // This is the position of "pub" in "pub fn a_method"
-assert-attribute: (".impl-items .rustdoc-toggle", {"open": ""})
+assert-attribute: (".impl-items .toggle", {"open": ""})
click-with-offset: (
- ".impl-items .rustdoc-toggle summary",
+ ".impl-items .toggle summary",
{"x": -24, "y": 8}, // This is the position of "[-]" next to that pub fn.
)
-assert-attribute-false: (".impl-items .rustdoc-toggle", {"open": ""})
+assert-attribute-false: (".impl-items .toggle", {"open": ""})
// Click the "Trait" part of "impl Trait" and verify it navigates.
click: "#impl-Trait-for-Foo h3 a:first-of-type"
-assert-text: (".fqn", "Trait lib2::Trait")
+assert-text: (".main-heading h1", "Trait lib2::Trait")
goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
// We first check that everything is visible.
assert-text: ("#toggle-all-docs", "[−]")
-assert-attribute: ("#implementations-list details.rustdoc-toggle", {"open": ""}, ALL)
-assert-attribute: ("#trait-implementations-list details.rustdoc-toggle", {"open": ""}, ALL)
+assert-attribute: ("#implementations-list details.toggle", {"open": ""}, ALL)
+assert-attribute: ("#trait-implementations-list details.toggle", {"open": ""}, ALL)
assert-attribute-false: (
- "#blanket-implementations-list > details.rustdoc-toggle",
+ "#blanket-implementations-list > details.toggle",
{"open": ""},
ALL,
)
click: "#toggle-all-docs"
wait-for-text: ("#toggle-all-docs", "[+]")
// We check that all <details> are collapsed (except for the impl block ones).
-assert-attribute-false: ("details.rustdoc-toggle:not(.implementors-toggle)", {"open": ""}, ALL)
+assert-attribute-false: ("details.toggle:not(.implementors-toggle)", {"open": ""}, ALL)
assert-attribute: ("#implementations-list > details.implementors-toggle", {"open": ""})
// We now check that the other impl blocks are collapsed.
assert-attribute-false: (
- "#blanket-implementations-list > details.rustdoc-toggle.implementors-toggle",
+ "#blanket-implementations-list > details.toggle.implementors-toggle",
{"open": ""},
ALL,
)
// We open them all again.
click: "#toggle-all-docs"
wait-for-text: ("#toggle-all-docs", "[−]")
-assert-attribute: ("details.rustdoc-toggle", {"open": ""}, ALL)
+assert-attribute: ("details.toggle", {"open": ""}, ALL)
// Checking the toggles style.
show-text: true
// We reload the page so the local storage settings are being used.
reload:
- assert-css: ("details.rustdoc-toggle > summary::before", {
+ assert-css: ("details.toggle > summary::before", {
"opacity": "0.5",
"filter": |filter|,
}, ALL)
- move-cursor-to: "details.rustdoc-toggle summary"
- assert-css: ("details.rustdoc-toggle > summary:hover::before", {
+ move-cursor-to: "details.toggle summary"
+ assert-css: ("details.toggle > summary:hover::before", {
"opacity": "1",
"filter": |filter|,
})
// has all the implementations toggled open by default, so users can
// find method names in those implementations with Ctrl-F.
goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
-assert-attribute: (".rustdoc-toggle.implementors-toggle", {"open": ""})
+assert-attribute: (".toggle.implementors-toggle", {"open": ""})
| ^^^
|
= note: error from rustc: unknown start of token: `
- = note: error from rustc: unknown start of token: `
- = note: error from rustc: unknown start of token: `
warning: could not parse code block as Rust code
--> $DIR/invalid-syntax.rs:64:5
-Z llvm-plugins=val -- a list LLVM plugins to enable (space separated)
-Z llvm-time-trace=val -- generate JSON tracing data file from LLVM data (default: no)
-Z location-detail=val -- what location details should be tracked when using caller_location, either `none`, or a comma separated list of location details, for which valid options are `file`, `line`, and `column` (default: `file,line,column`)
+ -Z log-backtrace=val -- add a backtrace along with logging
-Z ls=val -- list the symbols defined by a library crate (default: no)
-Z macro-backtrace=val -- show macro backtraces (default: no)
-Z maximal-hir-to-mir-coverage=val -- save as much information as possible about the correspondence between MIR and HIR as source scopes (default: no)
-<script type="text/json" id="notable-traits-data">{"&'static [SomeStruct]":"<h3>Notable traits for <code>&amp;[<a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait_slice::SomeStruct\">SomeStruct</a>]</code></h3><pre class=\"content\"><code><span class=\"where fmt-newline\">impl <a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait_slice::SomeTrait\">SomeTrait</a> for &amp;[<a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait_slice::SomeStruct\">SomeStruct</a>]</span>"}</script>
\ No newline at end of file
+<script type="text/json" id="notable-traits-data">{"&'static [SomeStruct]":"<h3>Notable traits for <code>&amp;[<a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait_slice::SomeStruct\">SomeStruct</a>]</code></h3><pre><code><span class=\"where fmt-newline\">impl <a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait_slice::SomeTrait\">SomeTrait</a> for &amp;[<a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait_slice::SomeStruct\">SomeStruct</a>]</span>"}</script>
\ No newline at end of file
-<script type="text/json" id="notable-traits-data">{"SomeStruct":"<h3>Notable traits for <code><a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\">SomeStruct</a></code></h3><pre class=\"content\"><code><span class=\"where fmt-newline\">impl <a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\">SomeTrait</a> for <a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\">SomeStruct</a></span>"}</script>
\ No newline at end of file
+<script type="text/json" id="notable-traits-data">{"SomeStruct":"<h3>Notable traits for <code><a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\">SomeStruct</a></code></h3><pre><code><span class=\"where fmt-newline\">impl <a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\">SomeTrait</a> for <a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\">SomeStruct</a></span>"}</script>
\ No newline at end of file
-<script type="text/json" id="notable-traits-data">{"SomeStruct":"<h3>Notable traits for <code><a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\">SomeStruct</a></code></h3><pre class=\"content\"><code><span class=\"where fmt-newline\">impl <a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\">SomeTrait</a> for <a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\">SomeStruct</a></span>","Wrapper<Self>":"<h3>Notable traits for <code><a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\">Wrapper</a>&lt;T&gt;</code></h3><pre class=\"content\"><code><span class=\"where fmt-newline\">impl&lt;T:&nbsp;<a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\">SomeTrait</a>&gt; <a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\">SomeTrait</a> for <a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\">Wrapper</a>&lt;T&gt;</span>"}</script>
\ No newline at end of file
+<script type="text/json" id="notable-traits-data">{"SomeStruct":"<h3>Notable traits for <code><a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\">SomeStruct</a></code></h3><pre><code><span class=\"where fmt-newline\">impl <a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\">SomeTrait</a> for <a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\">SomeStruct</a></span>","Wrapper<Self>":"<h3>Notable traits for <code><a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\">Wrapper</a>&lt;T&gt;</code></h3><pre><code><span class=\"where fmt-newline\">impl&lt;T:&nbsp;<a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\">SomeTrait</a>&gt; <a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\">SomeTrait</a> for <a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\">Wrapper</a>&lt;T&gt;</span>"}</script>
\ No newline at end of file
-<script type="text/json" id="notable-traits-data">{"Wrapper<Self>":"<h3>Notable traits for <code><a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\">Wrapper</a>&lt;T&gt;</code></h3><pre class=\"content\"><code><span class=\"where fmt-newline\">impl&lt;T:&nbsp;<a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\">SomeTrait</a>&gt; <a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\">SomeTrait</a> for <a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\">Wrapper</a>&lt;T&gt;</span>"}</script>
\ No newline at end of file
+<script type="text/json" id="notable-traits-data">{"Wrapper<Self>":"<h3>Notable traits for <code><a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\">Wrapper</a>&lt;T&gt;</code></h3><pre><code><span class=\"where fmt-newline\">impl&lt;T:&nbsp;<a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\">SomeTrait</a>&gt; <a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\">SomeTrait</a> for <a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\">Wrapper</a>&lt;T&gt;</span>"}</script>
\ No newline at end of file
#![crate_name = "foo"]
// @has foo/../index.html
-// @has - '//h1[@class="fqn"]' 'List of all crates'
+// @has - '//h1' 'List of all crates'
// @has - '//ul[@class="all-items"]//a[@href="foo/index.html"]' 'foo'
// @has - '//ul[@class="all-items"]//a[@href="all_item_types/index.html"]' 'all_item_types'
pub struct Foo;
// @!hasraw - '<span class="attr">#[outer]</span>'
// @hasraw - '#![inner]</span>'
// @!hasraw - '<span class="attr">#![inner]</span>'
-// @snapshot 'codeblock' - '//*[@class="rustdoc-toggle top-doc"]/*[@class="docblock"]//pre/code'
+// @snapshot 'codeblock' - '//*[@class="toggle top-doc"]/*[@class="docblock"]//pre/code'
/// ```no_run
/// # # space
// @has foo/index.html '//div[@class="sidebar-elems"]//li/a' 'Keywords'
// @has foo/index.html '//div[@class="sidebar-elems"]//li/a/@href' '#keywords'
// @has foo/keyword.match.html '//a[@class="keyword"]' 'match'
-// @has foo/keyword.match.html '//h1[@class="fqn"]' 'Keyword match'
+// @has foo/keyword.match.html '//h1' 'Keyword match'
// @has foo/keyword.match.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
// @has foo/index.html '//a/@href' '../foo/index.html'
// @!has foo/foo/index.html
#![crate_name = "foo"]
// @has 'foo/fn.g.html'
-// @has - '//*[@class="rustdoc-toggle top-doc"]/*[@class="docblock"]' \
+// @has - '//*[@class="toggle top-doc"]/*[@class="docblock"]' \
// 'outer module inner module'
mod inner_mod {
#![crate_name = "foo"]
// @has 'foo/struct.S1.html'
-// @snapshot S1_top-doc - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]'
+// @snapshot S1_top-doc - '//details[@class="toggle top-doc"]/div[@class="docblock"]'
#[doc = "Hello world!\n\n"]
/// Goodbye!
pub struct S1;
// @has 'foo/struct.S2.html'
-// @snapshot S2_top-doc - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]'
+// @snapshot S2_top-doc - '//details[@class="toggle top-doc"]/div[@class="docblock"]'
/// Hello world!
///
pub struct S2;
// @has 'foo/struct.S3.html'
-// @snapshot S3_top-doc - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]'
+// @snapshot S3_top-doc - '//details[@class="toggle top-doc"]/div[@class="docblock"]'
/** Par 1
*/ ///
/// Par 2
}
// @has 'foo/struct.Type.html'
-// @has - '//*[@class="rustdoc-toggle top-doc"]/*[@class="docblock"]' 'foo 2 1'
+// @has - '//*[@class="toggle top-doc"]/*[@class="docblock"]' 'foo 2 1'
/// foo
pub use b::Type;
// @has 'foo/struct.Whatever.html'
-// @has - '//*[@class="rustdoc-toggle top-doc"]/*[@class="docblock"]' 'whatever 3 2 1'
+// @has - '//*[@class="toggle top-doc"]/*[@class="docblock"]' 'whatever 3 2 1'
/// whatever
pub use c::Type as Whatever;
// @has 'foo/struct.Woof.html'
-// @has - '//*[@class="rustdoc-toggle top-doc"]/*[@class="docblock"]' 'a dog 4 2 1'
+// @has - '//*[@class="toggle top-doc"]/*[@class="docblock"]' 'a dog 4 2 1'
/// a dog
pub use c::Woof;
// @has - '//div[@class="sidebar-elems"]//li/a/@href' '#primitives'
// @has foo/primitive.reference.html
// @has - '//a[@class="primitive"]' 'reference'
-// @has - '//h1[@class="fqn"]' 'Primitive Type reference'
+// @has - '//h1' 'Primitive Type reference'
// @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
// There should be only one implementation listed.
#![feature(rustdoc_internals)]
// @has foo/primitive.slice.html '//a[@class="primitive"]' 'slice'
-// @has - '//h1[@class="fqn"]' 'Primitive Type slice'
+// @has - '//h1' 'Primitive Type slice'
// @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
// @has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations'
// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Send for [T]where T: Send'
#![feature(rustdoc_internals)]
// @has foo/primitive.tuple.html '//a[@class="primitive"]' 'tuple'
-// @has - '//h1[@class="fqn"]' 'Primitive Type tuple'
+// @has - '//h1' 'Primitive Type tuple'
// @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
// @has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations'
// @has - '//div[@id="synthetic-implementations-list"]//h3' 'Send'
#![feature(rustdoc_internals)]
// @has foo/primitive.unit.html '//a[@class="primitive"]' 'unit'
-// @has - '//h1[@class="fqn"]' 'Primitive Type unit'
+// @has - '//h1' 'Primitive Type unit'
// @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
// @has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations'
// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl Send for ()'
// @has foo/index.html '//div[@class="sidebar-elems"]//li/a' 'Primitive Types'
// @has foo/index.html '//div[@class="sidebar-elems"]//li/a/@href' '#primitives'
// @has foo/primitive.i32.html '//a[@class="primitive"]' 'i32'
-// @has foo/primitive.i32.html '//h1[@class="fqn"]' 'Primitive Type i32'
+// @has foo/primitive.i32.html '//h1' 'Primitive Type i32'
// @has foo/primitive.i32.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
// @has foo/index.html '//a/@href' '../foo/index.html'
// @!has foo/index.html '//span' '🔒'
-<script type="text/json" id="notable-traits-data">{"Odd":"<h3>Notable traits for <code><a class=\"struct\" href=\"struct.Odd.html\" title=\"struct foo::Odd\">Odd</a></code></h3><pre class=\"content\"><code><span class=\"where fmt-newline\">impl <a class=\"trait\" href=\"{{channel}}/core/iter/traits/iterator/trait.Iterator.html\" title=\"trait core::iter::traits::iterator::Iterator\">Iterator</a> for <a class=\"struct\" href=\"struct.Odd.html\" title=\"struct foo::Odd\">Odd</a></span><span class=\"where fmt-newline\"> type <a href=\"{{channel}}/core/iter/traits/iterator/trait.Iterator.html#associatedtype.Item\" class=\"associatedtype\">Item</a> = <a class=\"primitive\" href=\"{{channel}}/std/primitive.usize.html\">usize</a>;</span>"}</script>
\ No newline at end of file
+<script type="text/json" id="notable-traits-data">{"Odd":"<h3>Notable traits for <code><a class=\"struct\" href=\"struct.Odd.html\" title=\"struct foo::Odd\">Odd</a></code></h3><pre><code><span class=\"where fmt-newline\">impl <a class=\"trait\" href=\"{{channel}}/core/iter/traits/iterator/trait.Iterator.html\" title=\"trait core::iter::traits::iterator::Iterator\">Iterator</a> for <a class=\"struct\" href=\"struct.Odd.html\" title=\"struct foo::Odd\">Odd</a></span><span class=\"where fmt-newline\"> type <a href=\"{{channel}}/core/iter/traits/iterator/trait.Iterator.html#associatedtype.Item\" class=\"associatedtype\">Item</a> = <a class=\"primitive\" href=\"{{channel}}/std/primitive.usize.html\">usize</a>;</span>"}</script>
\ No newline at end of file
// block doc comments can have their lines starting with a star.
// @has foo/fn.foo.html
-// @snapshot docblock - '//*[@class="rustdoc-toggle top-doc"]//*[@class="docblock"]'
+// @snapshot docblock - '//*[@class="toggle top-doc"]//*[@class="docblock"]'
/**
* a
*/
#![allow(unused)]
// @has 'toggle_item_contents/struct.PubStruct.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
+// @count - '//details[@class="toggle type-contents-toggle"]' 0
pub struct PubStruct {
pub a: usize,
pub b: usize,
}
// @has 'toggle_item_contents/struct.BigPubStruct.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 13 fields'
+// @count - '//details[@class="toggle type-contents-toggle"]' 1
+// @has - '//details[@class="toggle type-contents-toggle"]' 'Show 13 fields'
pub struct BigPubStruct {
pub a: usize,
pub b: usize,
}
// @has 'toggle_item_contents/union.BigUnion.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 13 fields'
+// @count - '//details[@class="toggle type-contents-toggle"]' 1
+// @has - '//details[@class="toggle type-contents-toggle"]' 'Show 13 fields'
pub union BigUnion {
pub a: usize,
pub b: usize,
}
// @has 'toggle_item_contents/union.Union.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
+// @count - '//details[@class="toggle type-contents-toggle"]' 0
pub union Union {
pub a: usize,
pub b: usize,
}
// @has 'toggle_item_contents/struct.PrivStruct.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
+// @count - '//details[@class="toggle type-contents-toggle"]' 0
// @has - '//div[@class="item-decl"]' '/* private fields */'
pub struct PrivStruct {
a: usize,
}
// @has 'toggle_item_contents/enum.Enum.html'
-// @!has - '//details[@class="rustdoc-toggle type-contents-toggle"]' ''
+// @!has - '//details[@class="toggle type-contents-toggle"]' ''
pub enum Enum {
A, B, C,
D {
}
// @has 'toggle_item_contents/enum.EnumStructVariant.html'
-// @!has - '//details[@class="rustdoc-toggle type-contents-toggle"]' ''
+// @!has - '//details[@class="toggle type-contents-toggle"]' ''
pub enum EnumStructVariant {
A, B, C,
D {
}
// @has 'toggle_item_contents/enum.LargeEnum.html'
-// @count - '//*[@class="rust enum"]//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//*[@class="rust enum"]//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 13 variants'
+// @count - '//*[@class="rust enum"]//details[@class="toggle type-contents-toggle"]' 1
+// @has - '//*[@class="rust enum"]//details[@class="toggle type-contents-toggle"]' 'Show 13 variants'
pub enum LargeEnum {
A, B, C, D, E, F(u8), G, H, I, J, K, L, M
}
// @has 'toggle_item_contents/trait.Trait.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
+// @count - '//details[@class="toggle type-contents-toggle"]' 0
pub trait Trait {
type A;
#[must_use]
}
// @has 'toggle_item_contents/trait.GinormousTrait.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 16 associated items'
+// @count - '//details[@class="toggle type-contents-toggle"]' 1
+// @has - '//details[@class="toggle type-contents-toggle"]' 'Show 16 associated items'
pub trait GinormousTrait {
type A;
type B;
}
// @has 'toggle_item_contents/trait.HugeTrait.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 12 associated constants and 2 methods'
+// @count - '//details[@class="toggle type-contents-toggle"]' 1
+// @has - '//details[@class="toggle type-contents-toggle"]' 'Show 12 associated constants and 2 methods'
pub trait HugeTrait {
type A;
const M: usize = 1;
}
// @has 'toggle_item_contents/trait.GiganticTrait.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 1 associated constant and 1 method'
+// @count - '//details[@class="toggle type-contents-toggle"]' 1
+// @has - '//details[@class="toggle type-contents-toggle"]' 'Show 1 associated constant and 1 method'
pub trait GiganticTrait {
type A;
type B;
}
// @has 'toggle_item_contents/trait.BigTrait.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 14 methods'
+// @count - '//details[@class="toggle type-contents-toggle"]' 1
+// @has - '//details[@class="toggle type-contents-toggle"]' 'Show 14 methods'
pub trait BigTrait {
type A;
#[must_use]
// summary. Struct methods with no documentation should not be wrapped.
//
// @has foo/struct.Foo.html
-// @has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented()'
-// @has - '//details[@class="rustdoc-toggle method-toggle"]//*[@class="docblock"]' 'is_documented is documented'
-// @!has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented()'
+// @has - '//details[@class="toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented()'
+// @has - '//details[@class="toggle method-toggle"]//*[@class="docblock"]' 'is_documented is documented'
+// @!has - '//details[@class="toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented()'
pub struct Foo {
}
// summary. Trait methods with no documentation should not be wrapped.
//
// @has foo/trait.Foo.html
-// @has - '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'type Item'
-// @!has - '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'type Item2'
-// @has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented()'
-// @!has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented()'
-// @has - '//details[@class="rustdoc-toggle method-toggle"]//*[@class="docblock"]' 'is_documented is documented'
-// @has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented_optional()'
-// @!has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented_optional()'
-// @has - '//details[@class="rustdoc-toggle method-toggle"]//*[@class="docblock"]' 'is_documented_optional is documented'
+// @has - '//details[@class="toggle"]//summary//h4[@class="code-header"]' 'type Item'
+// @!has - '//details[@class="toggle"]//summary//h4[@class="code-header"]' 'type Item2'
+// @has - '//details[@class="toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented()'
+// @!has - '//details[@class="toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented()'
+// @has - '//details[@class="toggle method-toggle"]//*[@class="docblock"]' 'is_documented is documented'
+// @has - '//details[@class="toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented_optional()'
+// @!has - '//details[@class="toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented_optional()'
+// @has - '//details[@class="toggle method-toggle"]//*[@class="docblock"]' 'is_documented_optional is documented'
pub trait Foo {
/// is documented
type Item;
--- /dev/null
+// run-rustfix
+trait Trait<A> {}
+
+trait Assoc {
+ type Ty;
+}
+
+impl<A> Assoc for dyn Trait<A> {
+ type Ty = i32;
+}
+
+fn main() {
+ let _x: <dyn Trait<i32> as Assoc>::Ty; //~ ERROR ambiguous associated type
+}
--- /dev/null
+// run-rustfix
+trait Trait<A> {}
+
+trait Assoc {
+ type Ty;
+}
+
+impl<A> Assoc for dyn Trait<A> {
+ type Ty = i32;
+}
+
+fn main() {
+ let _x: <dyn Trait<i32>>::Ty; //~ ERROR ambiguous associated type
+}
--- /dev/null
+error[E0223]: ambiguous associated type
+ --> $DIR/ambiguous-associated-type-with-generics.rs:13:13
+ |
+LL | let _x: <dyn Trait<i32>>::Ty;
+ | ^^^^^^^^^^^^^^^^^^^^ help: use the fully-qualified path: `<dyn Trait<i32> as Assoc>::Ty`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0223`.
--> $DIR/associated-item-duplicate-names-3.rs:18:12
|
LL | let x: Baz::Bar = 5;
- | ^^^^^^^^ help: use fully-qualified syntax: `<Baz as Trait>::Bar`
+ | ^^^^^^^^ help: use the fully-qualified path: `<Baz as Foo>::Bar`
error: aborting due to 2 previous errors
--> $DIR/associated-types-in-ambiguous-context.rs:6:36
|
LL | fn get<T:Get,U:Get>(x: T, y: U) -> Get::Value {}
- | ^^^^^^^^^^ help: use fully-qualified syntax: `<Type as Get>::Value`
+ | ^^^^^^^^^^
+ |
+help: if there were a type named `Example` that implemented `Get`, you could use the fully-qualified path
+ |
+LL | fn get<T:Get,U:Get>(x: T, y: U) -> <Example as Get>::Value {}
+ | ~~~~~~~~~~~~~~~~~~~~~~~
error[E0223]: ambiguous associated type
--> $DIR/associated-types-in-ambiguous-context.rs:20:17
|
LL | trait Foo where Foo::Assoc: Bar {
- | ^^^^^^^^^^ help: use fully-qualified syntax: `<Self as Foo>::Assoc`
+ | ^^^^^^^^^^ help: use the fully-qualified path: `<Self as Foo>::Assoc`
error[E0223]: ambiguous associated type
--> $DIR/associated-types-in-ambiguous-context.rs:25:10
|
LL | type X = std::ops::Deref::Target;
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<Type as Deref>::Target`
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: if there were a type named `Example` that implemented `Deref`, you could use the fully-qualified path
+ |
+LL | type X = <Example as Deref>::Target;
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~
error[E0223]: ambiguous associated type
--> $DIR/associated-types-in-ambiguous-context.rs:11:23
|
LL | fn grab(&self) -> Grab::Value;
- | ^^^^^^^^^^^ help: use fully-qualified syntax: `<Self as Grab>::Value`
+ | ^^^^^^^^^^^ help: use the fully-qualified path: `<Self as Grab>::Value`
error[E0223]: ambiguous associated type
--> $DIR/associated-types-in-ambiguous-context.rs:14:22
|
LL | fn get(&self) -> Get::Value;
- | ^^^^^^^^^^ help: use fully-qualified syntax: `<Type as Get>::Value`
+ | ^^^^^^^^^^
+ |
+help: if there were a type named `Example` that implemented `Get`, you could use the fully-qualified path
+ |
+LL | fn get(&self) -> <Example as Get>::Value;
+ | ~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to 5 previous errors
LL | type Assoc = T;
| ^ the trait `Copy` is not implemented for `T`
|
+note: required for `<T as Complete>::Assoc` to implement `Partial<T>`
+ --> $DIR/issue-43784-associated-type.rs:1:11
+ |
+LL | pub trait Partial<X: ?Sized>: Copy {
+ | ^^^^^^^
note: required by a bound in `Complete::Assoc`
--> $DIR/issue-43784-associated-type.rs:5:17
|
--- /dev/null
+// run-pass
+//
+// This test makes sure that log-backtrace option doesn't give a compilation error.
+//
+// dont-check-compiler-stdout
+// dont-check-compiler-stderr
+// rustc-env:RUSTC_LOG=info
+// compile-flags: -Zlog-backtrace=rustc_metadata::creader
+fn main() {}
--- /dev/null
+#![feature(no_core)]
+#![feature(lang_items)]
+
+#![no_core]
+
+#[cfg(target_os = "linux")]
+#[link(name = "c")]
+extern {}
+
+#[lang = "start"]
+fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize {
+ //~^ ERROR: incorrect number of parameters for the `start` lang item
+ 40+2
+}
+
+#[lang = "sized"]
+pub trait Sized {}
+#[lang = "copy"]
+pub trait Copy {}
+
+#[lang = "drop_in_place"]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+ drop_in_place(to_drop)
+}
+
+#[lang = "add"]
+trait Add<RHS> {
+ type Output;
+ fn add(self, other: RHS) -> Self::Output;
+}
+
+impl Add<isize> for isize {
+ type Output = isize;
+ fn add(self, other: isize) -> isize {
+ self + other
+ }
+}
+
+fn main() {}
--- /dev/null
+error: incorrect number of parameters for the `start` lang item
+ --> $DIR/issue-92157.rs:11:1
+ |
+LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the `start` lang item should have four parameters, but found 3
+ = note: the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
+
+error: aborting due to previous error
+
let u = 5 as bool; //~ ERROR cannot cast as `bool`
//~| HELP compare with zero instead
//~| SUGGESTION 5 != 0
+
let t = (1 + 2) as bool; //~ ERROR cannot cast as `bool`
//~| HELP compare with zero instead
//~| SUGGESTION (1 + 2) != 0
- let v = "hello" as bool; //~ ERROR casting `&'static str` as `bool` is invalid
+
+ let v = "hello" as bool;
+ //~^ ERROR casting `&'static str` as `bool` is invalid
+ //~| HELP consider using the `is_empty` method on `&'static str` to determine if it contains anything
}
| ^^^^^^^^^ help: compare with zero instead: `5 != 0`
error[E0054]: cannot cast as `bool`
- --> $DIR/cast-as-bool.rs:5:13
+ --> $DIR/cast-as-bool.rs:6:13
|
LL | let t = (1 + 2) as bool;
| ^^^^^^^^^^^^^^^ help: compare with zero instead: `(1 + 2) != 0`
error[E0606]: casting `&'static str` as `bool` is invalid
- --> $DIR/cast-as-bool.rs:8:13
+ --> $DIR/cast-as-bool.rs:10:13
|
LL | let v = "hello" as bool;
| ^^^^^^^^^^^^^^^
+ |
+help: consider using the `is_empty` method on `&'static str` to determine if it contains anything
+ |
+LL | let v = !"hello".is_empty();
+ | + ~~~~~~~~~~~
error: aborting due to 3 previous errors
--- /dev/null
+use std::ops::Deref;
+
+struct Foo;
+
+impl Deref for Foo {
+ type Target = [u8];
+
+ fn deref(&self) -> &Self::Target {
+ &[]
+ }
+}
+
+fn main() {
+ let _ = "foo" as bool;
+ //~^ ERROR casting `&'static str` as `bool` is invalid [E0606]
+
+ let _ = String::from("foo") as bool;
+ //~^ ERROR non-primitive cast: `String` as `bool` [E0605]
+
+ let _ = Foo as bool;
+ //~^ ERROR non-primitive cast: `Foo` as `bool` [E0605]
+}
+
+fn _slice(bar: &[i32]) -> bool {
+ bar as bool
+ //~^ ERROR casting `&[i32]` as `bool` is invalid [E0606]
+}
--- /dev/null
+error[E0606]: casting `&'static str` as `bool` is invalid
+ --> $DIR/issue-106883-is-empty.rs:14:13
+ |
+LL | let _ = "foo" as bool;
+ | ^^^^^^^^^^^^^
+ |
+help: consider using the `is_empty` method on `&'static str` to determine if it contains anything
+ |
+LL | let _ = !"foo".is_empty();
+ | + ~~~~~~~~~~~
+
+error[E0605]: non-primitive cast: `String` as `bool`
+ --> $DIR/issue-106883-is-empty.rs:17:13
+ |
+LL | let _ = String::from("foo") as bool;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+ |
+note: this expression `Deref`s to `str` which implements `is_empty`
+ --> $DIR/issue-106883-is-empty.rs:17:13
+ |
+LL | let _ = String::from("foo") as bool;
+ | ^^^^^^^^^^^^^^^^^^^
+help: consider using the `is_empty` method on `String` to determine if it contains anything
+ |
+LL | let _ = !String::from("foo").is_empty();
+ | + ~~~~~~~~~~~
+
+error[E0605]: non-primitive cast: `Foo` as `bool`
+ --> $DIR/issue-106883-is-empty.rs:20:13
+ |
+LL | let _ = Foo as bool;
+ | ^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+ |
+note: this expression `Deref`s to `[u8]` which implements `is_empty`
+ --> $DIR/issue-106883-is-empty.rs:20:13
+ |
+LL | let _ = Foo as bool;
+ | ^^^
+help: consider using the `is_empty` method on `Foo` to determine if it contains anything
+ |
+LL | let _ = !Foo.is_empty();
+ | + ~~~~~~~~~~~
+
+error[E0606]: casting `&[i32]` as `bool` is invalid
+ --> $DIR/issue-106883-is-empty.rs:25:5
+ |
+LL | bar as bool
+ | ^^^^^^^^^^^
+ |
+help: consider using the `is_empty` method on `&[i32]` to determine if it contains anything
+ |
+LL | !bar.is_empty()
+ | + ~~~~~~~~~~~
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0605, E0606.
+For more information about an error, try `rustc --explain E0605`.
// known-bug
// unset-rustc-env:RUST_BACKTRACE
// compile-flags:-Z trait-solver=chalk --edition=2021
-// error-pattern:stack backtrace:
+// error-pattern:internal compiler error
// failure-status:101
-// normalize-stderr-test "note: .*" -> ""
-// normalize-stderr-test "thread 'rustc' .*" -> ""
-// normalize-stderr-test " .*\n" -> ""
// normalize-stderr-test "DefId([^)]*)" -> "..."
+// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> ""
+// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> ""
+// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
+// normalize-stderr-test "note: compiler flags.*\n\n" -> ""
+// normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
+// normalize-stderr-test "thread.*panicked.*\n" -> ""
+// normalize-stderr-test "stack backtrace:\n" -> ""
+// normalize-stderr-test "\s\d{1,}: .*\n" -> ""
+// normalize-stderr-test "\s at .*\n" -> ""
+// normalize-stderr-test ".*note: Some details.*\n" -> ""
+// normalize-stderr-test "\n\n[ ]*\n" -> ""
+// normalize-stderr-test "compiler/.*: projection" -> "projection"
fn main() -> () {}
-error[E0277]: `[async fn body@$DIR/async.rs:14:29: 16:2]` is not a future
-LL |LL | |LL | | }
-
-
-error[E0277]: the size for values of type `<[async fn body@$DIR/async.rs:14:29: 16:2] as Future>::Output` cannot be known at compilation time
-LL |LL | |LL | | }
-
-
-error[E0277]: `[async fn body@$DIR/async.rs:14:29: 16:2]` is not a future
+error[E0277]: `[async fn body@$DIR/async.rs:23:29: 25:2]` is not a future
+ --> $DIR/async.rs:23:29
+ |
+LL | async fn foo(x: u32) -> u32 {
+ | _____________________________-
+LL | | x
+LL | | }
+ | | ^
+ | | |
+ | |_`[async fn body@$DIR/async.rs:23:29: 25:2]` is not a future
+ | required by a bound introduced by this call
+ |
+ = help: the trait `Future` is not implemented for `[async fn body@$DIR/async.rs:23:29: 25:2]`
+ = note: [async fn body@$DIR/async.rs:23:29: 25:2] must be a future or must implement `IntoFuture` to be awaited
+note: required by a bound in `identity_future`
+ --> $SRC_DIR/core/src/future/mod.rs:LL:COL
+
+error[E0277]: the size for values of type `<[async fn body@$DIR/async.rs:23:29: 25:2] as Future>::Output` cannot be known at compilation time
+ --> $DIR/async.rs:23:29
+ |
+LL | async fn foo(x: u32) -> u32 {
+ | _____________________________^
+LL | | x
+LL | | }
+ | |_^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `<[async fn body@$DIR/async.rs:23:29: 25:2] as Future>::Output`
+note: required by a bound in `identity_future`
+ --> $SRC_DIR/core/src/future/mod.rs:LL:COL
+
+error[E0277]: `[async fn body@$DIR/async.rs:23:29: 25:2]` is not a future
+ --> $DIR/async.rs:23:25
+ |
LL | async fn foo(x: u32) -> u32 {
-
-error: internal compiler error: compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs:1114:25: projection clauses should be implied from elsewhere. obligation: `Obligation(predicate=Binder(ProjectionPredicate(AliasTy { substs: [[async fn body@$DIR/async.rs:14:29: 16:2]], def_id: ...), _use_mk_alias_ty_instead: () }, Term::Ty(u32)), []), depth=0)`
+ | ^^^ `[async fn body@$DIR/async.rs:23:29: 25:2]` is not a future
+ |
+ = help: the trait `Future` is not implemented for `[async fn body@$DIR/async.rs:23:29: 25:2]`
+ = note: [async fn body@$DIR/async.rs:23:29: 25:2] must be a future or must implement `IntoFuture` to be awaited
+
+error: internal compiler error: projection clauses should be implied from elsewhere. obligation: `Obligation(predicate=Binder(ProjectionPredicate(AliasTy { substs: [[async fn body@$DIR/async.rs:23:29: 25:2]], def_id: ...), _use_mk_alias_ty_instead: () }, Term::Ty(u32)), []), depth=0)`
+ --> $DIR/async.rs:23:25
+ |
LL | async fn foo(x: u32) -> u32 {
-
-
-stack backtrace:
-
-
-
-
-
-
-
-
-
-query stack during panic:
+ | ^^^query stack during panic:
#0 [typeck] type-checking `foo`
#1 [thir_body] building THIR for `foo`
#2 [mir_built] building MIR for `foo`
| |
| arguments to this struct are incorrect
|
+help: the type constructed contains `()` due to the type of the argument passed
+ --> $DIR/issue-84128.rs:13:9
+ |
+LL | Foo(())
+ | ^^^^--^
+ | |
+ | this argument influences the type of `Foo`
note: tuple struct defined here
--> $DIR/issue-84128.rs:5:8
|
| |
| arguments to this enum variant are incorrect
|
+help: the type constructed contains `()` due to the type of the argument passed
+ --> $DIR/issue-87461.rs:10:5
+ |
+LL | Ok(())
+ | ^^^--^
+ | |
+ | this argument influences the type of `Ok`
note: tuple variant defined here
--> $SRC_DIR/core/src/result.rs:LL:COL
| |
| arguments to this enum variant are incorrect
|
+help: the type constructed contains `()` due to the type of the argument passed
+ --> $DIR/issue-87461.rs:17:5
+ |
+LL | Ok(())
+ | ^^^--^
+ | |
+ | this argument influences the type of `Ok`
note: tuple variant defined here
--> $SRC_DIR/core/src/result.rs:LL:COL
| |
| arguments to this enum variant are incorrect
|
+help: the type constructed contains `()` due to the type of the argument passed
+ --> $DIR/issue-87461.rs:26:9
+ |
+LL | Ok(())
+ | ^^^--^
+ | |
+ | this argument influences the type of `Ok`
note: tuple variant defined here
--> $SRC_DIR/core/src/result.rs:LL:COL
// run-rustfix
#![warn(unused_braces)]
+macro_rules! make_1 {
+ () => {
+ 1
+ }
+}
+
struct A<const N: usize>;
fn main() {
let _: A<7>; // ok
let _: A<7>; //~ WARN unnecessary braces
let _: A<{ 3 + 5 }>; // ok
+ let _: A<{make_1!()}>; // ok
}
// run-rustfix
#![warn(unused_braces)]
+macro_rules! make_1 {
+ () => {
+ 1
+ }
+}
+
struct A<const N: usize>;
fn main() {
let _: A<7>; // ok
let _: A<{ 7 }>; //~ WARN unnecessary braces
let _: A<{ 3 + 5 }>; // ok
+ let _: A<{make_1!()}>; // ok
}
warning: unnecessary braces around const expression
- --> $DIR/unused_braces.rs:9:14
+ --> $DIR/unused_braces.rs:15:14
|
LL | let _: A<{ 7 }>;
| ^^ ^^
| |
| doesn't satisfy `Value: Eq`
| doesn't satisfy `Value: Hash`
+ | doesn't satisfy `Value: PartialEq`
...
LL | hs.insert(Value(0));
| ^^^^^^
|
= note: the following trait bounds were not satisfied:
`Value: Eq`
+ `Value: PartialEq`
+ which is required by `Value: Eq`
`Value: Hash`
help: consider annotating `Value` with `#[derive(Eq, Hash, PartialEq)]`
|
--> $DIR/issue-91550.rs:26:9
|
LL | pub struct NoDerives;
- | -------------------- doesn't satisfy `NoDerives: Eq`
+ | --------------------
+ | |
+ | doesn't satisfy `NoDerives: Eq`
+ | doesn't satisfy `NoDerives: PartialEq`
LL |
LL | struct Object<T>(T);
| ---------------- method `use_eq` not found for this struct
| ^^ ---------
| |
| unsatisfied trait bound introduced here
+ = note: the following trait bounds were not satisfied:
+ `NoDerives: PartialEq`
+ which is required by `NoDerives: Eq`
help: consider annotating `NoDerives` with `#[derive(Eq, PartialEq)]`
|
LL | #[derive(Eq, PartialEq)]
--> $DIR/issue-91550.rs:27:9
|
LL | pub struct NoDerives;
- | -------------------- doesn't satisfy `NoDerives: Ord`
+ | --------------------
+ | |
+ | doesn't satisfy `NoDerives: Eq`
+ | doesn't satisfy `NoDerives: Ord`
+ | doesn't satisfy `NoDerives: PartialEq`
+ | doesn't satisfy `NoDerives: PartialOrd`
LL |
LL | struct Object<T>(T);
| ---------------- method `use_ord` not found for this struct
| ^^^ ---------
| |
| unsatisfied trait bound introduced here
+ = note: the following trait bounds were not satisfied:
+ `NoDerives: PartialOrd`
+ which is required by `NoDerives: Ord`
+ `NoDerives: PartialEq`
+ which is required by `NoDerives: Ord`
+ `NoDerives: Eq`
+ which is required by `NoDerives: Ord`
help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]`
|
LL | #[derive(Eq, Ord, PartialEq, PartialOrd)]
LL | pub struct NoDerives;
| --------------------
| |
+ | doesn't satisfy `NoDerives: Eq`
| doesn't satisfy `NoDerives: Ord`
+ | doesn't satisfy `NoDerives: PartialEq`
| doesn't satisfy `NoDerives: PartialOrd`
LL |
LL | struct Object<T>(T);
| | |
| | unsatisfied trait bound introduced here
| unsatisfied trait bound introduced here
+ = note: the following trait bounds were not satisfied:
+ `NoDerives: PartialEq`
+ which is required by `NoDerives: Ord`
+ `NoDerives: Eq`
+ which is required by `NoDerives: Ord`
+ `NoDerives: PartialEq`
+ which is required by `NoDerives: PartialOrd`
help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]`
|
LL | #[derive(Eq, Ord, PartialEq, PartialOrd)]
--> $DIR/bad-assoc-ty.rs:1:10
|
LL | type A = [u8; 4]::AssocTy;
- | ^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<[u8; 4] as Trait>::AssocTy`
+ | ^^^^^^^^^^^^^^^^
+ |
+help: if there were a trait named `Example` with associated type `AssocTy` implemented for `[u8; 4]`, you could use the fully-qualified path
+ |
+LL | type A = <[u8; 4] as Example>::AssocTy;
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error[E0223]: ambiguous associated type
--> $DIR/bad-assoc-ty.rs:5:10
|
LL | type B = [u8]::AssocTy;
- | ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<[u8] as Trait>::AssocTy`
+ | ^^^^^^^^^^^^^
+ |
+help: if there were a trait named `Example` with associated type `AssocTy` implemented for `[u8]`, you could use the fully-qualified path
+ |
+LL | type B = <[u8] as Example>::AssocTy;
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~
error[E0223]: ambiguous associated type
--> $DIR/bad-assoc-ty.rs:9:10
|
LL | type C = (u8)::AssocTy;
- | ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<u8 as Trait>::AssocTy`
+ | ^^^^^^^^^^^^^
+ |
+help: if there were a trait named `Example` with associated type `AssocTy` implemented for `u8`, you could use the fully-qualified path
+ |
+LL | type C = <u8 as Example>::AssocTy;
+ | ~~~~~~~~~~~~~~~~~~~~~~~~
error[E0223]: ambiguous associated type
--> $DIR/bad-assoc-ty.rs:13:10
|
LL | type D = (u8, u8)::AssocTy;
- | ^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(u8, u8) as Trait>::AssocTy`
+ | ^^^^^^^^^^^^^^^^^
+ |
+help: if there were a trait named `Example` with associated type `AssocTy` implemented for `(u8, u8)`, you could use the fully-qualified path
+ |
+LL | type D = <(u8, u8) as Example>::AssocTy;
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error[E0121]: the placeholder `_` is not allowed within types on item signatures for type aliases
--> $DIR/bad-assoc-ty.rs:17:10
--> $DIR/bad-assoc-ty.rs:21:19
|
LL | type F = &'static (u8)::AssocTy;
- | ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<u8 as Trait>::AssocTy`
+ | ^^^^^^^^^^^^^
+ |
+help: if there were a trait named `Example` with associated type `AssocTy` implemented for `u8`, you could use the fully-qualified path
+ |
+LL | type F = &'static <u8 as Example>::AssocTy;
+ | ~~~~~~~~~~~~~~~~~~~~~~~~
error[E0223]: ambiguous associated type
--> $DIR/bad-assoc-ty.rs:27:10
|
LL | type G = dyn 'static + (Send)::AssocTy;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn Send + 'static) as Trait>::AssocTy`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: if there were a trait named `Example` with associated type `AssocTy` implemented for `(dyn Send + 'static)`, you could use the fully-qualified path
+ |
+LL | type G = <(dyn Send + 'static) as Example>::AssocTy;
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
warning: trait objects without an explicit `dyn` are deprecated
--> $DIR/bad-assoc-ty.rs:33:10
--> $DIR/bad-assoc-ty.rs:33:10
|
LL | type H = Fn(u8) -> (u8)::Output;
- | ^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn Fn(u8) -> u8 + 'static) as Trait>::Output`
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: use the fully-qualified path: `<(dyn Fn(u8) -> u8 + 'static) as IntoFuture>::Output`
error[E0223]: ambiguous associated type
--> $DIR/bad-assoc-ty.rs:39:19
|
LL | ($ty: ty) => ($ty::AssocTy);
- | ^^^^^^^^^^^^ help: use fully-qualified syntax: `<u8 as Trait>::AssocTy`
+ | ^^^^^^^^^^^^
...
LL | type J = ty!(u8);
| ------- in this macro invocation
|
= note: this error originates in the macro `ty` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: if there were a trait named `Example` with associated type `AssocTy` implemented for `u8`, you could use the fully-qualified path
+ |
+LL | ($ty: ty) => (<u8 as Example>::AssocTy);
+ | ~~~~~~~~~~~~~~~~~~~~~~~~
error[E0223]: ambiguous associated type
--> $DIR/bad-assoc-ty.rs:46:10
|
LL | type I = ty!()::AssocTy;
- | ^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<u8 as Trait>::AssocTy`
+ | ^^^^^^^^^^^^^^
+ |
+help: if there were a trait named `Example` with associated type `AssocTy` implemented for `u8`, you could use the fully-qualified path
+ |
+LL | type I = <u8 as Example>::AssocTy;
+ | ~~~~~~~~~~~~~~~~~~~~~~~~
error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
--> $DIR/bad-assoc-ty.rs:51:13
trait MyTrait { type X; }
+struct MyStruct;
+impl MyTrait for MyStruct {
+ type X = ();
+}
fn main() {
let foo: MyTrait::X;
error[E0223]: ambiguous associated type
- --> $DIR/E0223.rs:4:14
+ --> $DIR/E0223.rs:8:14
|
LL | let foo: MyTrait::X;
- | ^^^^^^^^^^ help: use fully-qualified syntax: `<Type as MyTrait>::X`
+ | ^^^^^^^^^^ help: use the fully-qualified path: `<MyStruct as MyTrait>::X`
error: aborting due to previous error
--- /dev/null
+// compile-flags: --remap-path-prefix={{src-base}}/errors/auxiliary=remapped-aux
+
+pub struct SomeStruct {} // This line should be show as part of the error.
--- /dev/null
+error[E0423]: expected value, found struct `remapped_dep::SomeStruct`
+ --> $DIR/remap-path-prefix-reverse.rs:22:13
+ |
+LL | let _ = remapped_dep::SomeStruct;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `remapped_dep::SomeStruct {}`
+ |
+ ::: remapped-aux/remapped_dep.rs:3:1
+ |
+LL | pub struct SomeStruct {} // This line should be show as part of the error.
+ | --------------------- `remapped_dep::SomeStruct` defined here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0423`.
--- /dev/null
+error[E0423]: expected value, found struct `remapped_dep::SomeStruct`
+ --> remapped/errors/remap-path-prefix-reverse.rs:22:13
+ |
+LL | let _ = remapped_dep::SomeStruct;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `remapped_dep::SomeStruct {}`
+ |
+ ::: remapped-aux/remapped_dep.rs:3:1
+ |
+LL | pub struct SomeStruct {} // This line should be show as part of the error.
+ | --------------------- `remapped_dep::SomeStruct` defined here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0423`.
--- /dev/null
+// aux-build:remapped_dep.rs
+// compile-flags: --remap-path-prefix={{src-base}}/errors/auxiliary=remapped-aux
+
+// The remapped paths are not normalized by compiletest.
+// normalize-stderr-test: "\\(errors)" -> "/$1"
+
+// revisions: local-self remapped-self
+// [remapped-self]compile-flags: --remap-path-prefix={{src-base}}=remapped
+
+// The paths from `remapped-self` aren't recognized by compiletest, so we
+// cannot use line-specific patterns for the actual error.
+// error-pattern: E0423
+
+// Verify that the expected source code is shown.
+// error-pattern: pub struct SomeStruct {} // This line should be show
+
+extern crate remapped_dep;
+
+fn main() {
+ // The actual error is irrelevant. The important part it that is should show
+ // a snippet of the dependency's source.
+ let _ = remapped_dep::SomeStruct;
+}
--- /dev/null
+// compile-flags: --remap-path-prefix={{src-base}}=remapped
+
+// The remapped paths are not normalized by compiletest.
+// normalize-stderr-test: "\\(errors)" -> "/$1"
+
+// The remapped paths aren't recognized by compiletest, so we
+// cannot use line-specific patterns.
+// error-pattern: E0425
+
+fn main() {
+ // We cannot actually put an ERROR marker here because
+ // the file name in the error message is not what the
+ // test framework expects (since the filename gets remapped).
+ // We still test the expected error in the stderr file.
+ ferris
+}
--- /dev/null
+error[E0425]: cannot find value `ferris` in this scope
+ --> remapped/errors/remap-path-prefix.rs:15:5
+ |
+LL | ferris
+ | ^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
| ^^^^^^ the trait `Clone` is not implemented for `T`
|
= note: required for `Box<T>` to implement `Clone`
+ = note: required for `<Self as UnsafeCopy>::Copy<T>` to implement `Copy`
note: required by a bound in `UnsafeCopy::Copy`
--> $DIR/issue-74824.rs:6:19
|
|
= note: expected type parameter `B`
found associated type `<B as Add>::Output`
+help: the type constructed contains `<B as Add>::Output` due to the type of the argument passed
+ --> $DIR/missing-bounds.rs:11:9
+ |
+LL | A(self.0 + rhs.0)
+ | ^^--------------^
+ | |
+ | this argument influences the type of `A`
note: tuple struct defined here
--> $DIR/missing-bounds.rs:5:8
|
--- /dev/null
+// check-pass
+
+fn lifetime<'a>()
+where
+ &'a (): 'a,
+{
+ /* do nothing */
+}
+
+fn doesnt_work()
+where
+ for<'a> &'a (): 'a,
+{
+ /* do nothing */
+}
+
+fn main() {
+ lifetime();
+ doesnt_work();
+}
fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item {
//~^ ERROR `impl Trait` is not allowed in path parameters
-//~^^ ERROR ambiguous associated type
+//~| ERROR `impl Trait` is not allowed in path parameters
x.next().unwrap()
}
LL | -> <dyn Iterator<Item = impl Debug> as Iterator>::Item
| ^^^^^^^^^^
-error[E0223]: ambiguous associated type
- --> $DIR/impl_trait_projections.rs:12:50
+error[E0667]: `impl Trait` is not allowed in path parameters
+ --> $DIR/impl_trait_projections.rs:12:51
|
LL | fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item {
- | ^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<impl Iterator as Trait>::Item`
+ | ^^^^^^^^^^^^^
error: aborting due to 5 previous errors
-Some errors have detailed explanations: E0223, E0667.
-For more information about an error, try `rustc --explain E0223`.
+For more information about this error, try `rustc --explain E0667`.
error: impl method assumes more implied bounds than the corresponding trait method
- --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:13:5
+ --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:13:31
|
LL | fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `()`
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #105572 <https://github.com/rust-lang/rust/issues/105572>
error: aborting due to previous error
+Future incompatibility report: Future breakage diagnostic:
+error: impl method assumes more implied bounds than the corresponding trait method
+ --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:13:31
+ |
+LL | fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `()`
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #105572 <https://github.com/rust-lang/rust/issues/105572>
+note: the lint level is defined here
+ --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:1:9
+ |
+LL | #![deny(implied_bounds_entailment)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
error: impl method assumes more implied bounds than the corresponding trait method
- --> $DIR/impl-implied-bounds-compatibility.rs:14:5
+ --> $DIR/impl-implied-bounds-compatibility.rs:14:35
|
LL | fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `&'b MessageListeners<'b>`
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #105572 <https://github.com/rust-lang/rust/issues/105572>
error: aborting due to previous error
+Future incompatibility report: Future breakage diagnostic:
+error: impl method assumes more implied bounds than the corresponding trait method
+ --> $DIR/impl-implied-bounds-compatibility.rs:14:35
+ |
+LL | fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `&'b MessageListeners<'b>`
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #105572 <https://github.com/rust-lang/rust/issues/105572>
+note: the lint level is defined here
+ --> $DIR/impl-implied-bounds-compatibility.rs:1:9
+ |
+LL | #![deny(implied_bounds_entailment)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
error[E0282]: type annotations needed
--> $DIR/cannot-infer-partial-try-return.rs:20:9
|
-LL | infallible()?;
- | ------------- type must be known at this point
LL | Ok(())
| ^^ cannot infer type of the type parameter `E` declared on the enum `Result`
|
error[E0282]: type annotations needed
- --> $DIR/question-mark-type-infer.rs:10:30
+ --> $DIR/question-mark-type-infer.rs:10:21
|
LL | l.iter().map(f).collect()?
- | ^ cannot infer type
+ | ^^^^^^^ cannot infer type of the type parameter `B` declared on the associated function `collect`
+ |
+help: consider specifying the generic argument
+ |
+LL | l.iter().map(f).collect::<Vec<_>>()?
+ | ++++++++++
error: aborting due to previous error
--> $DIR/issue-23073.rs:6:17
|
LL | type FooT = <<Self as Bar>::Foo>::T;
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<<Self as Bar>::Foo as Trait>::T`
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: if there were a trait named `Example` with associated type `T` implemented for `<Self as Bar>::Foo`, you could use the fully-qualified path
+ |
+LL | type FooT = <<Self as Bar>::Foo as Example>::T;
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
-error[E0282]: type annotations needed
- --> $DIR/issue-69455.rs:29:20
+error[E0284]: type annotations needed
+ --> $DIR/issue-69455.rs:29:41
|
LL | println!("{}", 23u64.test(xs.iter().sum()));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the associated function `new_display`
+ | ---- ^^^ cannot infer type of the type parameter `S` declared on the associated function `sum`
+ | |
+ | type must be known at this point
|
- = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: cannot satisfy `<u64 as Test<_>>::Output == _`
help: consider specifying the generic argument
|
-LL | println!("{}", 23u64.test(xs.iter().sum())::<T>);
- | +++++
+LL | println!("{}", 23u64.test(xs.iter().sum::<S>()));
+ | +++++
error[E0283]: type annotations needed
--> $DIR/issue-69455.rs:29:41
error: aborting due to 2 previous errors
-Some errors have detailed explanations: E0282, E0283.
-For more information about an error, try `rustc --explain E0282`.
+Some errors have detailed explanations: E0283, E0284.
+For more information about an error, try `rustc --explain E0283`.
--> $DIR/issue-78622.rs:5:5
|
LL | S::A::<f> {}
- | ^^^^ help: use fully-qualified syntax: `<S as Trait>::A`
+ | ^^^^
+ |
+help: if there were a trait named `Example` with associated type `A` implemented for `S`, you could use the fully-qualified path
+ |
+LL | <S as Example>::A::<f> {}
+ | ~~~~~~~~~~~~~~~~~
error: aborting due to previous error
--> $DIR/bare-trait-objects-path.rs:23:12
|
LL | let _: Dyn::Ty;
- | ^^^^^^^ help: use fully-qualified syntax: `<dyn Dyn as Trait>::Ty`
+ | ^^^^^^^ help: use the fully-qualified path: `<dyn Dyn as Assoc>::Ty`
warning: trait objects without an explicit `dyn` are deprecated
--> $DIR/bare-trait-objects-path.rs:14:5
if { return } {
}
+
+ // regression test for https://github.com/rust-lang/rust/issues/106899
+ return println!("!");
+ //~^ WARN unnecessary braces
}
if { return } {
}
+
+ // regression test for https://github.com/rust-lang/rust/issues/106899
+ return { println!("!") };
+ //~^ WARN unnecessary braces
}
LL + consume(7);
|
-warning: 5 warnings emitted
+warning: unnecessary braces around `return` value
+ --> $DIR/unused_braces.rs:55:12
+ |
+LL | return { println!("!") };
+ | ^^ ^^
+ |
+help: remove these braces
+ |
+LL - return { println!("!") };
+LL + return println!("!");
+ |
+
+warning: 6 warnings emitted
|
= note: expected type parameter `bool` (type parameter `bool`)
found type `bool` (`bool`)
+help: the type constructed contains `bool` due to the type of the argument passed
+ --> $DIR/issue-35030.rs:9:9
+ |
+LL | Some(true)
+ | ^^^^^----^
+ | |
+ | this argument influences the type of `Some`
note: tuple variant defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
|
= note: the following trait bounds were not satisfied:
`T: Eq`
+ `T: PartialEq`
+ which is required by `T: Eq`
`T: Hash`
help: consider restricting the type parameters to satisfy the trait bounds
|
let y = 0;
//~^ ERROR unknown start of token: \u{37e}
//~^^ HELP Unicode character ';' (Greek Question Mark) looks like ';' (Semicolon), but it is not
+ let x = 0;
+ //~^ ERROR unknown start of token: \u{a0}
+ //~^^ NOTE character appears 3 more times
+ //~^^^ HELP Unicode character ' ' (No-Break Space) looks like ' ' (Space), but it is not
}
LL | let y = 0;
| ~
-error: aborting due to previous error
+error: unknown start of token: \u{a0}
+ --> $DIR/unicode-chars.rs:5:5
+ |
+LL | let x = 0;
+ | ^^^^
+ |
+ = note: character appears 3 more times
+help: Unicode character ' ' (No-Break Space) looks like ' ' (Space), but it is not
+ |
+LL | let x = 0;
+ | ++++
+
+error: aborting due to 2 previous errors
--- /dev/null
+// error-pattern: building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic
+// compile-flags: --crate-type proc-macro -Cpanic=abort
+// force-host
+// check-pass
--- /dev/null
+warning: building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic
+
+warning: 1 warning emitted
+
--- /dev/null
+error: using an old version of `rental`
+ --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+ = note: `#[deny(proc_macro_back_compat)]` on by default
+
+error: using an old version of `rental`
+ --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+
+error: using an old version of `rental`
+ --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+
+error: using an old version of `rental`
+ --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+
+error: using an old version of `rental`
+ --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+
+error: using an old version of `rental`
+ --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+
+error: using an old version of `rental`
+ --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+
+error: using an old version of `rental`
+ --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+
+error: aborting due to 8 previous errors
+
+Future incompatibility report: Future breakage diagnostic:
+error: using an old version of `rental`
+ --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+ = note: `#[deny(proc_macro_back_compat)]` on by default
+
+Future breakage diagnostic:
+error: using an old version of `rental`
+ --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+ = note: `#[deny(proc_macro_back_compat)]` on by default
+
+Future breakage diagnostic:
+error: using an old version of `rental`
+ --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+ = note: `#[deny(proc_macro_back_compat)]` on by default
+
+Future breakage diagnostic:
+error: using an old version of `rental`
+ --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+ = note: `#[deny(proc_macro_back_compat)]` on by default
+
+Future breakage diagnostic:
+error: using an old version of `rental`
+ --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+ = note: `#[deny(proc_macro_back_compat)]` on by default
+
+Future breakage diagnostic:
+error: using an old version of `rental`
+ --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+ = note: `#[deny(proc_macro_back_compat)]` on by default
+
+Future breakage diagnostic:
+error: using an old version of `rental`
+ --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+ = note: `#[deny(proc_macro_back_compat)]` on by default
+
+Future breakage diagnostic:
+error: using an old version of `rental`
+ --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+ = note: `#[deny(proc_macro_back_compat)]` on by default
+
--- /dev/null
+PRINT-DERIVE INPUT (DISPLAY): enum ProceduralMasqueradeDummyType { Input, }
+PRINT-DERIVE RE-COLLECTED (DISPLAY): enum ProceduralMasqueradeDummyType { Input }
+PRINT-DERIVE INPUT (DEBUG): TokenStream [
+ Ident {
+ ident: "enum",
+ span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:1: 4:5 (#0),
+ },
+ Ident {
+ ident: "ProceduralMasqueradeDummyType",
+ span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6: 4:35 (#0),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Ident {
+ ident: "Input",
+ span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:13:5: 13:10 (#0),
+ },
+ ],
+ span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:36: 14:2 (#0),
+ },
+]
+PRINT-DERIVE INPUT (DISPLAY): enum ProceduralMasqueradeDummyType { Input, }
+PRINT-DERIVE RE-COLLECTED (DISPLAY): enum ProceduralMasqueradeDummyType { Input }
+PRINT-DERIVE INPUT (DEBUG): TokenStream [
+ Ident {
+ ident: "enum",
+ span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:1: 4:5 (#0),
+ },
+ Ident {
+ ident: "ProceduralMasqueradeDummyType",
+ span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6: 4:35 (#0),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Ident {
+ ident: "Input",
+ span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:13:5: 13:10 (#0),
+ },
+ ],
+ span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:36: 14:2 (#0),
+ },
+]
--- /dev/null
+error: using an old version of `rental`
+ --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+ = note: `#[deny(proc_macro_back_compat)]` on by default
+
+error: using an old version of `rental`
+ --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+
+error: using an old version of `rental`
+ --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+
+error: using an old version of `rental`
+ --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+
+error: using an old version of `rental`
+ --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+
+error: using an old version of `rental`
+ --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+
+error: using an old version of `rental`
+ --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+
+error: using an old version of `rental`
+ --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+
+error: aborting due to 8 previous errors
+
+Future incompatibility report: Future breakage diagnostic:
+error: using an old version of `rental`
+ --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+ = note: `#[deny(proc_macro_back_compat)]` on by default
+
+Future breakage diagnostic:
+error: using an old version of `rental`
+ --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+ = note: `#[deny(proc_macro_back_compat)]` on by default
+
+Future breakage diagnostic:
+error: using an old version of `rental`
+ --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+ = note: `#[deny(proc_macro_back_compat)]` on by default
+
+Future breakage diagnostic:
+error: using an old version of `rental`
+ --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+ = note: `#[deny(proc_macro_back_compat)]` on by default
+
+Future breakage diagnostic:
+error: using an old version of `rental`
+ --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+ = note: `#[deny(proc_macro_back_compat)]` on by default
+
+Future breakage diagnostic:
+error: using an old version of `rental`
+ --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+ = note: `#[deny(proc_macro_back_compat)]` on by default
+
+Future breakage diagnostic:
+error: using an old version of `rental`
+ --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+ = note: `#[deny(proc_macro_back_compat)]` on by default
+
+Future breakage diagnostic:
+error: using an old version of `rental`
+ --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+ |
+LL | enum ProceduralMasqueradeDummyType {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
+ = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+ = note: `#[deny(proc_macro_back_compat)]` on by default
+
--- /dev/null
+PRINT-DERIVE INPUT (DISPLAY): enum ProceduralMasqueradeDummyType { Input, }
+PRINT-DERIVE RE-COLLECTED (DISPLAY): enum ProceduralMasqueradeDummyType { Input }
+PRINT-DERIVE INPUT (DEBUG): TokenStream [
+ Ident {
+ ident: "enum",
+ span: remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:1: 4:5 (#0),
+ },
+ Ident {
+ ident: "ProceduralMasqueradeDummyType",
+ span: remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6: 4:35 (#0),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Ident {
+ ident: "Input",
+ span: remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:13:5: 13:10 (#0),
+ },
+ ],
+ span: remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:36: 14:2 (#0),
+ },
+]
+PRINT-DERIVE INPUT (DISPLAY): enum ProceduralMasqueradeDummyType { Input, }
+PRINT-DERIVE RE-COLLECTED (DISPLAY): enum ProceduralMasqueradeDummyType { Input }
+PRINT-DERIVE INPUT (DEBUG): TokenStream [
+ Ident {
+ ident: "enum",
+ span: remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:1: 4:5 (#0),
+ },
+ Ident {
+ ident: "ProceduralMasqueradeDummyType",
+ span: remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6: 4:35 (#0),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Ident {
+ ident: "Input",
+ span: remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:13:5: 13:10 (#0),
+ },
+ ],
+ span: remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:36: 14:2 (#0),
+ },
+]
// aux-build:test-macros.rs
// compile-flags: -Z span-debug
+// revisions: local remapped
+// [remapped]compile-flags: --remap-path-prefix={{src-base}}=remapped
+
+// The remapped paths are not normalized by compiletest.
+// normalize-stdout-test: "\\(proc-macro|pretty-print-hack)" -> "/$1"
+// normalize-stderr-test: "\\(proc-macro|pretty-print-hack)" -> "/$1"
#![no_std] // Don't load unnecessary hygiene information from std
extern crate std;
+++ /dev/null
-error: using an old version of `rental`
- --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
- |
-LL | enum ProceduralMasqueradeDummyType {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
- = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
- = note: `#[deny(proc_macro_back_compat)]` on by default
-
-error: using an old version of `rental`
- --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
- |
-LL | enum ProceduralMasqueradeDummyType {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
- = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
-
-error: using an old version of `rental`
- --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
- |
-LL | enum ProceduralMasqueradeDummyType {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
- = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
-
-error: using an old version of `rental`
- --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
- |
-LL | enum ProceduralMasqueradeDummyType {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
- = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
-
-error: using an old version of `rental`
- --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
- |
-LL | enum ProceduralMasqueradeDummyType {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
- = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
-
-error: using an old version of `rental`
- --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
- |
-LL | enum ProceduralMasqueradeDummyType {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
- = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
-
-error: using an old version of `rental`
- --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
- |
-LL | enum ProceduralMasqueradeDummyType {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
- = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
-
-error: using an old version of `rental`
- --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
- |
-LL | enum ProceduralMasqueradeDummyType {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
- = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
-
-error: aborting due to 8 previous errors
-
-Future incompatibility report: Future breakage diagnostic:
-error: using an old version of `rental`
- --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
- |
-LL | enum ProceduralMasqueradeDummyType {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
- = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
- = note: `#[deny(proc_macro_back_compat)]` on by default
-
-Future breakage diagnostic:
-error: using an old version of `rental`
- --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
- |
-LL | enum ProceduralMasqueradeDummyType {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
- = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
- = note: `#[deny(proc_macro_back_compat)]` on by default
-
-Future breakage diagnostic:
-error: using an old version of `rental`
- --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
- |
-LL | enum ProceduralMasqueradeDummyType {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
- = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
- = note: `#[deny(proc_macro_back_compat)]` on by default
-
-Future breakage diagnostic:
-error: using an old version of `rental`
- --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
- |
-LL | enum ProceduralMasqueradeDummyType {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
- = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
- = note: `#[deny(proc_macro_back_compat)]` on by default
-
-Future breakage diagnostic:
-error: using an old version of `rental`
- --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
- |
-LL | enum ProceduralMasqueradeDummyType {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
- = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
- = note: `#[deny(proc_macro_back_compat)]` on by default
-
-Future breakage diagnostic:
-error: using an old version of `rental`
- --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
- |
-LL | enum ProceduralMasqueradeDummyType {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
- = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
- = note: `#[deny(proc_macro_back_compat)]` on by default
-
-Future breakage diagnostic:
-error: using an old version of `rental`
- --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
- |
-LL | enum ProceduralMasqueradeDummyType {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
- = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
- = note: `#[deny(proc_macro_back_compat)]` on by default
-
-Future breakage diagnostic:
-error: using an old version of `rental`
- --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
- |
-LL | enum ProceduralMasqueradeDummyType {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
- = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
- = note: `#[deny(proc_macro_back_compat)]` on by default
-
+++ /dev/null
-PRINT-DERIVE INPUT (DISPLAY): enum ProceduralMasqueradeDummyType { Input, }
-PRINT-DERIVE RE-COLLECTED (DISPLAY): enum ProceduralMasqueradeDummyType { Input }
-PRINT-DERIVE INPUT (DEBUG): TokenStream [
- Ident {
- ident: "enum",
- span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:1: 4:5 (#0),
- },
- Ident {
- ident: "ProceduralMasqueradeDummyType",
- span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6: 4:35 (#0),
- },
- Group {
- delimiter: Brace,
- stream: TokenStream [
- Ident {
- ident: "Input",
- span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:13:5: 13:10 (#0),
- },
- ],
- span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:36: 14:2 (#0),
- },
-]
-PRINT-DERIVE INPUT (DISPLAY): enum ProceduralMasqueradeDummyType { Input, }
-PRINT-DERIVE RE-COLLECTED (DISPLAY): enum ProceduralMasqueradeDummyType { Input }
-PRINT-DERIVE INPUT (DEBUG): TokenStream [
- Ident {
- ident: "enum",
- span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:1: 4:5 (#0),
- },
- Ident {
- ident: "ProceduralMasqueradeDummyType",
- span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6: 4:35 (#0),
- },
- Group {
- delimiter: Brace,
- stream: TokenStream [
- Ident {
- ident: "Input",
- span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:13:5: 13:10 (#0),
- },
- ],
- span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:36: 14:2 (#0),
- },
-]
--> $DIR/qualified-path-params-2.rs:18:10
|
LL | type A = <S as Tr>::A::f<u8>;
- | ^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<<S as Tr>::A as Trait>::f`
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+help: if there were a trait named `Example` with associated type `f` implemented for `<S as Tr>::A`, you could use the fully-qualified path
+ |
+LL | type A = <<S as Tr>::A as Example>::f;
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
+++ /dev/null
-// compile-flags: --remap-path-prefix={{src-base}}=remapped
-
-fn main() {
- // We cannot actually put an ERROR marker here because
- // the file name in the error message is not what the
- // test framework expects (since the filename gets remapped).
- // We still test the expected error in the stderr file.
- ferris
-}
+++ /dev/null
-error[E0425]: cannot find value `ferris` in this scope
- --> remapped/remap-path-prefix.rs:8:5
- |
-LL | ferris
- | ^^^^^^ not found in this scope
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0425`.
--> $DIR/issue-103202.rs:4:17
|
LL | fn f(self: &S::x) {}
- | ^^^^ help: use fully-qualified syntax: `<S as Trait>::x`
+ | ^^^^
+ |
+help: if there were a trait named `Example` with associated type `x` implemented for `S`, you could use the fully-qualified path
+ |
+LL | fn f(self: &<S as Example>::x) {}
+ | ~~~~~~~~~~~~~~~~~
error: aborting due to previous error
--> $DIR/self-impl.rs:23:16
|
LL | let _: <Self>::Baz = true;
- | ^^^^^^^^^^^ help: use fully-qualified syntax: `<Bar as Trait>::Baz`
+ | ^^^^^^^^^^^ help: use the fully-qualified path: `<Bar as Foo>::Baz`
error[E0223]: ambiguous associated type
--> $DIR/self-impl.rs:25:16
|
LL | let _: Self::Baz = true;
- | ^^^^^^^^^ help: use fully-qualified syntax: `<Bar as Trait>::Baz`
+ | ^^^^^^^^^ help: use the fully-qualified path: `<Bar as Foo>::Baz`
error: aborting due to 2 previous errors
--> $DIR/struct-path-associated-type.rs:32:13
|
LL | let s = S::A {};
- | ^^^^ help: use fully-qualified syntax: `<S as Trait>::A`
+ | ^^^^ help: use the fully-qualified path: `<S as Tr>::A`
error[E0223]: ambiguous associated type
--> $DIR/struct-path-associated-type.rs:33:13
|
LL | let z = S::A::<u8> {};
- | ^^^^ help: use fully-qualified syntax: `<S as Trait>::A`
+ | ^^^^ help: use the fully-qualified path: `<S as Tr>::A`
error[E0223]: ambiguous associated type
--> $DIR/struct-path-associated-type.rs:35:9
|
LL | S::A {} => {}
- | ^^^^ help: use fully-qualified syntax: `<S as Trait>::A`
+ | ^^^^ help: use the fully-qualified path: `<S as Tr>::A`
error: aborting due to 8 previous errors
| ^
= note: expected tuple `(i32, bool)`
found type `{integer}`
+help: the type constructed contains `{integer}` due to the type of the argument passed
+ --> $DIR/args-instead-of-tuple-errors.rs:6:34
+ |
+LL | let _: Option<(i32, bool)> = Some(1, 2);
+ | ^^^^^-^^^^
+ | |
+ | this argument influences the type of `Some`
note: tuple variant defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
help: remove the extra argument
|
= note: expected tuple `(i32,)`
found type `usize`
+help: the type constructed contains `usize` due to the type of the argument passed
+ --> $DIR/args-instead-of-tuple-errors.rs:14:29
+ |
+LL | let _: Option<(i32,)> = Some(5_usize);
+ | ^^^^^-------^
+ | |
+ | this argument influences the type of `Some`
note: tuple variant defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
|
= note: expected tuple `(i32,)`
found type `usize`
+help: the type constructed contains `usize` due to the type of the argument passed
+ --> $DIR/args-instead-of-tuple-errors.rs:17:29
+ |
+LL | let _: Option<(i32,)> = Some((5_usize));
+ | ^^^^^---------^
+ | |
+ | this argument influences the type of `Some`
note: tuple variant defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
--- /dev/null
+trait Foo {}
+
+impl Foo for i32 {}
+
+fn needs_foo(_: impl Foo) {}
+
+fn test(x: &Box<dyn Fn() -> i32>) {
+ needs_foo(x);
+ //~^ ERROR the trait bound
+ //~| HELP use parentheses to call this trait object
+}
+
+fn main() {}
--- /dev/null
+error[E0277]: the trait bound `&Box<dyn Fn() -> i32>: Foo` is not satisfied
+ --> $DIR/call-on-unimplemented-with-autoderef.rs:8:15
+ |
+LL | needs_foo(x);
+ | --------- ^ the trait `Foo` is not implemented for `&Box<dyn Fn() -> i32>`
+ | |
+ | required by a bound introduced by this call
+ |
+note: required by a bound in `needs_foo`
+ --> $DIR/call-on-unimplemented-with-autoderef.rs:5:22
+ |
+LL | fn needs_foo(_: impl Foo) {}
+ | ^^^ required by this bound in `needs_foo`
+help: use parentheses to call this trait object
+ |
+LL | needs_foo(x());
+ | ++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--> $DIR/constrain-suggest-ice.rs:6:9
|
LL | F
- | ^
- |
-help: a local variable with a similar name exists
- |
-LL | x
- | ~
-help: you might be missing a type parameter
- |
-LL | struct Bug<S, F>{
- | +++
+ | ^ help: a local variable with a similar name exists: `x`
error: generic `Self` types are currently not permitted in anonymous constants
--> $DIR/constrain-suggest-ice.rs:3:21
--- /dev/null
+//run-rustfix
+#![allow(unused)]
+
+struct S;
+impl S {
+ fn foo(&mut self) {
+ let x = |this: &Self, v: i32| {
+ this.bar();
+ this.hel();
+ };
+ self.qux(); //~ ERROR cannot borrow `*self` as mutable because it is also borrowed as immutable
+ x(self, 1);
+ x(self, 3);
+ }
+ fn bar(&self) {}
+ fn hel(&self) {}
+ fn qux(&mut self) {}
+
+ fn hello(&mut self) {
+ let y = |this: &Self| {
+ this.bar();
+ };
+ self.qux(); //~ ERROR cannot borrow `*self` as mutable because it is also borrowed as immutable
+ y(self);
+ }
+}
+
+fn main() {}
--- /dev/null
+//run-rustfix
+#![allow(unused)]
+
+struct S;
+impl S {
+ fn foo(&mut self) {
+ let x = |v: i32| {
+ self.bar();
+ self.hel();
+ };
+ self.qux(); //~ ERROR cannot borrow `*self` as mutable because it is also borrowed as immutable
+ x(1);
+ x(3);
+ }
+ fn bar(&self) {}
+ fn hel(&self) {}
+ fn qux(&mut self) {}
+
+ fn hello(&mut self) {
+ let y = || {
+ self.bar();
+ };
+ self.qux(); //~ ERROR cannot borrow `*self` as mutable because it is also borrowed as immutable
+ y();
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
+ --> $DIR/issue-105761-suggest-self-for-closure.rs:11:9
+ |
+LL | let x = |v: i32| {
+ | -------- immutable borrow occurs here
+LL | self.bar();
+ | ---- first borrow occurs due to use of `self` in closure
+...
+LL | self.qux();
+ | ^^^^^^^^^^ mutable borrow occurs here
+LL | x(1);
+ | - immutable borrow later used here
+ |
+help: try explicitly pass `&Self` into the Closure as an argument
+ |
+LL ~ let x = |this: &Self, v: i32| {
+LL ~ this.bar();
+LL ~ this.hel();
+LL | };
+LL | self.qux();
+LL ~ x(self, 1);
+LL ~ x(self, 3);
+ |
+
+error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
+ --> $DIR/issue-105761-suggest-self-for-closure.rs:23:9
+ |
+LL | let y = || {
+ | -- immutable borrow occurs here
+LL | self.bar();
+ | ---- first borrow occurs due to use of `self` in closure
+LL | };
+LL | self.qux();
+ | ^^^^^^^^^^ mutable borrow occurs here
+LL | y();
+ | - immutable borrow later used here
+ |
+help: try explicitly pass `&Self` into the Closure as an argument
+ |
+LL ~ let y = |this: &Self| {
+LL ~ this.bar();
+LL | };
+LL | self.qux();
+LL ~ y(self);
+ |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
--> $DIR/let-binding-init-expr-as-ty.rs:2:14
|
LL | let foo: i32::from_be(num);
- | ^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<i32 as Trait>::from_be`
+ | ^^^^^^^^^^^^^^^^^
+ |
+help: if there were a trait named `Example` with associated type `from_be` implemented for `i32`, you could use the fully-qualified path
+ |
+LL | let foo: <i32 as Example>::from_be;
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to 3 previous errors
|
= note: expected reference `&str`
found closure `[closure@$DIR/sugg-else-for-closure.rs:6:26: 6:28]`
+help: the return type of this call is `[closure@$DIR/sugg-else-for-closure.rs:6:26: 6:28]` due to the type of the argument passed
+ --> $DIR/sugg-else-for-closure.rs:6:14
+ |
+LL | let _s = y.unwrap_or(|| x.split('.').nth(1).unwrap());
+ | ^^^^^^^^^^^^-------------------------------^
+ | |
+ | this argument influences the return type of `unwrap_or`
note: associated function defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
help: try calling `unwrap_or_else` instead
--- /dev/null
+// Tests that a suggestion is issued for type mismatch errors when a
+// u8 is expected and a char literal which is ASCII is supplied.
+
+fn foo(_t: u8) {}
+
+fn main() {
+ let _x: u8 = 'X';
+ //~^ ERROR: mismatched types [E0308]
+ //~| HELP: if you meant to write a byte literal, prefix with `b`
+
+ foo('#');
+ //~^ ERROR: mismatched types [E0308]
+ //~| HELP: if you meant to write a byte literal, prefix with `b`
+
+ // Do not issue the suggestion if the char literal isn't ASCII
+ let _t: u8 = '€';
+ //~^ ERROR: mismatched types [E0308]
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/type-mismatch-byte-literal.rs:7:18
+ |
+LL | let _x: u8 = 'X';
+ | -- ^^^ expected `u8`, found `char`
+ | |
+ | expected due to this
+ |
+help: if you meant to write a byte literal, prefix with `b`
+ |
+LL | let _x: u8 = b'X';
+ | ~~~~
+
+error[E0308]: mismatched types
+ --> $DIR/type-mismatch-byte-literal.rs:11:9
+ |
+LL | foo('#');
+ | --- ^^^ expected `u8`, found `char`
+ | |
+ | arguments to this function are incorrect
+ |
+note: function defined here
+ --> $DIR/type-mismatch-byte-literal.rs:4:4
+ |
+LL | fn foo(_t: u8) {}
+ | ^^^ ------
+help: if you meant to write a byte literal, prefix with `b`
+ |
+LL | foo(b'#');
+ | ~~~~
+
+error[E0308]: mismatched types
+ --> $DIR/type-mismatch-byte-literal.rs:16:18
+ |
+LL | let _t: u8 = '€';
+ | -- ^^^ expected `u8`, found `char`
+ | |
+ | expected due to this
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// There are two different instances to check that even if
+// the trait is implemented for the output of a function,
+// it will still be displayed if the function itself implements a trait.
+trait Foo {}
+
+impl Foo for fn() -> bool {}
+impl Foo for bool {}
+
+fn example() -> bool {
+ true
+}
+
+trait NoOtherFoo {}
+
+impl NoOtherFoo for fn() -> bool {}
+
+fn do_on_foo(v: impl Foo) {}
+fn do_on_single_foo(v: impl NoOtherFoo) {}
+
+fn main() {
+ do_on_foo(example);
+ //~^ ERROR the trait bound
+
+ do_on_single_foo(example);
+ //~^ ERROR the trait bound
+}
--- /dev/null
+error[E0277]: the trait bound `fn() -> bool {example}: Foo` is not satisfied
+ --> $DIR/fn-trait-cast-diagnostic.rs:21:15
+ |
+LL | do_on_foo(example);
+ | --------- ^^^^^^^ the trait `Foo` is not implemented for fn item `fn() -> bool {example}`
+ | |
+ | required by a bound introduced by this call
+ |
+note: required by a bound in `do_on_foo`
+ --> $DIR/fn-trait-cast-diagnostic.rs:17:22
+ |
+LL | fn do_on_foo(v: impl Foo) {}
+ | ^^^ required by this bound in `do_on_foo`
+help: use parentheses to call this function
+ |
+LL | do_on_foo(example());
+ | ++
+help: the trait `Foo` is implemented for fn pointer `fn() -> bool`, try casting using `as`
+ |
+LL | do_on_foo(example as fn() -> bool);
+ | +++++++++++++++
+
+error[E0277]: the trait bound `fn() -> bool {example}: NoOtherFoo` is not satisfied
+ --> $DIR/fn-trait-cast-diagnostic.rs:24:22
+ |
+LL | do_on_single_foo(example);
+ | ---------------- ^^^^^^^ the trait `NoOtherFoo` is not implemented for fn item `fn() -> bool {example}`
+ | |
+ | required by a bound introduced by this call
+ |
+note: required by a bound in `do_on_single_foo`
+ --> $DIR/fn-trait-cast-diagnostic.rs:18:29
+ |
+LL | fn do_on_single_foo(v: impl NoOtherFoo) {}
+ | ^^^^^^^^^^ required by this bound in `do_on_single_foo`
+help: the trait `NoOtherFoo` is implemented for fn pointer `fn() -> bool`, try casting using `as`
+ |
+LL | do_on_single_foo(example as fn() -> bool);
+ | +++++++++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+#[derive(Clone)] //~ trait objects must include the `dyn` keyword
+ //~| trait objects must include the `dyn` keyword
+struct Foo;
+trait Foo {} //~ the name `Foo` is defined multiple times
+fn main() {}
--- /dev/null
+error[E0428]: the name `Foo` is defined multiple times
+ --> $DIR/issue-106072.rs:4:1
+ |
+LL | struct Foo;
+ | ----------- previous definition of the type `Foo` here
+LL | trait Foo {}
+ | ^^^^^^^^^ `Foo` redefined here
+ |
+ = note: `Foo` must be defined only once in the type namespace of this module
+
+error[E0782]: trait objects must include the `dyn` keyword
+ --> $DIR/issue-106072.rs:1:10
+ |
+LL | #[derive(Clone)]
+ | ^^^^^
+ |
+ = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0782]: trait objects must include the `dyn` keyword
+ --> $DIR/issue-106072.rs:1:10
+ |
+LL | #[derive(Clone)]
+ | ^^^^^
+ |
+ = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0428, E0782.
+For more information about an error, try `rustc --explain E0428`.
LL | impl<T> Complete for T {}
| ^ the trait `Copy` is not implemented for `T`
|
+note: required for `T` to implement `Partial`
+ --> $DIR/issue-43784-supertrait.rs:1:11
+ |
+LL | pub trait Partial: Copy {
+ | ^^^^^^^
note: required by a bound in `Complete`
--> $DIR/issue-43784-supertrait.rs:4:21
|
|
= note: expected type parameter `F`
found struct `Class<P>`
+help: the return type of this call is `Class<P>` due to the type of the argument passed
+ --> $DIR/issue-52893.rs:53:9
+ |
+LL | builder.push(output);
+ | ^^^^^^^^^^^^^------^
+ | |
+ | this argument influences the return type of `push`
note: associated function defined here
--> $DIR/issue-52893.rs:11:8
|
| |
| required by a bound introduced by this call
|
- = help: the trait `Trait` is implemented for fn pointer `fn(Argument) -> Return`
note: required by a bound in `takes`
--> $DIR/issue-99875.rs:9:18
|
LL | fn takes(_: impl Trait) {}
| ^^^^^ required by this bound in `takes`
+help: the trait `Trait` is implemented for fn pointer `fn(Argument) -> Return`, try casting using `as`
+ |
+LL | takes(function as fn(Argument) -> Return);
+ | +++++++++++++++++++++++++
error[E0277]: the trait bound `[closure@$DIR/issue-99875.rs:14:11: 14:34]: Trait` is not satisfied
--> $DIR/issue-99875.rs:14:11
--> $DIR/item-privacy.rs:115:12
|
LL | let _: S::A;
- | ^^^^ help: use fully-qualified syntax: `<S as Trait>::A`
+ | ^^^^
+ |
+help: if there were a trait named `Example` with associated type `A` implemented for `S`, you could use the fully-qualified path
+ |
+LL | let _: <S as Example>::A;
+ | ~~~~~~~~~~~~~~~~~
error[E0223]: ambiguous associated type
--> $DIR/item-privacy.rs:116:12
|
LL | let _: S::B;
- | ^^^^ help: use fully-qualified syntax: `<S as Trait>::B`
+ | ^^^^ help: use the fully-qualified path: `<S as assoc_ty::B>::B`
error[E0223]: ambiguous associated type
--> $DIR/item-privacy.rs:117:12
|
LL | let _: S::C;
- | ^^^^ help: use fully-qualified syntax: `<S as Trait>::C`
+ | ^^^^ help: use the fully-qualified path: `<S as assoc_ty::C>::C`
error[E0624]: associated type `A` is private
--> $DIR/item-privacy.rs:119:12
--- /dev/null
+// These are simplifications of the tower traits by the same name:
+
+pub trait Service<Request> {
+ type Response;
+}
+
+pub trait Layer<C> {
+ type Service;
+}
+
+// Any type will do here:
+
+pub struct Req;
+pub struct Res;
+
+// This is encoding a trait alias.
+
+pub trait ParticularService:
+ Service<Req, Response = Res> {
+}
+
+impl<T> ParticularService for T
+where
+ T: Service<Req, Response = Res>,
+{
+}
+
+// This is also a trait alias.
+// The weird = <Self as ...> bound is there so that users of the trait do not
+// need to repeat the bounds. See https://github.com/rust-lang/rust/issues/20671
+// for context, and in particular the workaround in:
+// https://github.com/rust-lang/rust/issues/20671#issuecomment-529752828
+
+pub trait ParticularServiceLayer<C>:
+ Layer<C, Service = <Self as ParticularServiceLayer<C>>::Service>
+{
+ type Service: ParticularService;
+}
+
+impl<T, C> ParticularServiceLayer<C> for T
+where
+ T: Layer<C>,
+ T::Service: ParticularService,
+{
+ type Service = T::Service;
+}
+
+// These are types that implement the traits that the trait aliases refer to.
+// They should also implement the alias traits due to the blanket impls.
+
+struct ALayer<C>(C);
+impl<C> Layer<C> for ALayer<C> {
+ type Service = AService;
+}
+
+struct AService;
+impl Service<Req> for AService {
+ // However, AService does _not_ meet the blanket implementation,
+ // since its Response type is bool, not Res as it should be.
+ type Response = bool;
+}
+
+// This is a wrapper type around ALayer that uses the trait alias
+// as a way to communicate the requirements of the provided types.
+struct Client<C>(C);
+
+// The method and the free-standing function below both have the same bounds.
+
+impl<C> Client<C>
+where
+ ALayer<C>: ParticularServiceLayer<C>,
+{
+ fn check(&self) {}
+}
+
+fn check<C>(_: C) where ALayer<C>: ParticularServiceLayer<C> {}
+
+// But, they give very different error messages.
+
+fn main() {
+ // This gives a very poor error message that does nothing to point the user
+ // at the underlying cause of why the types involved do not meet the bounds.
+ Client(()).check(); //~ ERROR E0599
+
+ // This gives a good(ish) error message that points the user at _why_ the
+ // bound isn't met, and thus how they might fix it.
+ check(()); //~ ERROR E0271
+}
--- /dev/null
+error[E0599]: the method `check` exists for struct `Client<()>`, but its trait bounds were not satisfied
+ --> $DIR/track-obligations.rs:83:16
+ |
+LL | struct ALayer<C>(C);
+ | ----------------
+ | |
+ | doesn't satisfy `<_ as Layer<()>>::Service = <ALayer<()> as ParticularServiceLayer<()>>::Service`
+ | doesn't satisfy `ALayer<()>: ParticularServiceLayer<()>`
+...
+LL | struct Client<C>(C);
+ | ---------------- method `check` not found for this struct
+...
+LL | Client(()).check();
+ | ^^^^^ method cannot be called on `Client<()>` due to unsatisfied trait bounds
+ |
+note: trait bound `<ALayer<()> as Layer<()>>::Service = <ALayer<()> as ParticularServiceLayer<()>>::Service` was not satisfied
+ --> $DIR/track-obligations.rs:35:14
+ |
+LL | pub trait ParticularServiceLayer<C>:
+ | ----------------------
+LL | Layer<C, Service = <Self as ParticularServiceLayer<C>>::Service>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here
+note: trait bound `ALayer<()>: ParticularServiceLayer<()>` was not satisfied
+ --> $DIR/track-obligations.rs:71:16
+ |
+LL | impl<C> Client<C>
+ | ---------
+LL | where
+LL | ALayer<C>: ParticularServiceLayer<C>,
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here
+note: the trait `ParticularServiceLayer` must be implemented
+ --> $DIR/track-obligations.rs:34:1
+ |
+LL | / pub trait ParticularServiceLayer<C>:
+LL | | Layer<C, Service = <Self as ParticularServiceLayer<C>>::Service>
+ | |____________________________________________________________________^
+
+error[E0271]: type mismatch resolving `<AService as Service<Req>>::Response == Res`
+ --> $DIR/track-obligations.rs:87:11
+ |
+LL | check(());
+ | ----- ^^ type mismatch resolving `<AService as Service<Req>>::Response == Res`
+ | |
+ | required by a bound introduced by this call
+ |
+note: expected this to be `Res`
+ --> $DIR/track-obligations.rs:60:21
+ |
+LL | type Response = bool;
+ | ^^^^
+note: required for `AService` to implement `ParticularService`
+ --> $DIR/track-obligations.rs:22:9
+ |
+LL | impl<T> ParticularService for T
+ | ^^^^^^^^^^^^^^^^^ ^
+LL | where
+LL | T: Service<Req, Response = Res>,
+ | -------------- unsatisfied trait bound introduced here
+note: required for `ALayer<_>` to implement `ParticularServiceLayer<_>`
+ --> $DIR/track-obligations.rs:40:12
+ |
+LL | impl<T, C> ParticularServiceLayer<C> for T
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ ^
+...
+LL | T::Service: ParticularService,
+ | ----------------- unsatisfied trait bound introduced here
+note: required by a bound in `check`
+ --> $DIR/track-obligations.rs:76:36
+ |
+LL | fn check<C>(_: C) where ALayer<C>: ParticularServiceLayer<C> {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0271, E0599.
+For more information about an error, try `rustc --explain E0271`.
--> $DIR/cannot_infer_local_or_vec_in_tuples.rs:2:9
|
LL | let (x, ) = (vec![], );
- | ^^^^^
+ | ^^^^^ ---------- type must be known at this point
|
help: consider giving this pattern a type, where the type for type parameter `T` is specified
|
--- /dev/null
+fn function<T>(x: T, y: bool) -> T {
+ x
+}
+
+struct S {}
+impl S {
+ fn method<T>(&self, x: T) -> T {
+ x
+ }
+}
+
+fn wrong_arg_type(x: u32) -> u32 {
+ x
+}
+
+fn main() {
+ // Should not trigger.
+ let x = wrong_arg_type(0u16); //~ ERROR mismatched types
+ let x: u16 = function(0, 0u8); //~ ERROR mismatched types
+
+ // Should trigger exactly once for the first argument.
+ let x: u16 = function(0u32, 0u8); //~ ERROR arguments to this function are incorrect
+
+ // Should trigger.
+ let x: u16 = function(0u32, true); //~ ERROR mismatched types
+ let x: u16 = (S {}).method(0u32); //~ ERROR mismatched types
+ function(0u32, 8u8) //~ ERROR arguments to this function are incorrect
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:18:28
+ |
+LL | let x = wrong_arg_type(0u16);
+ | -------------- ^^^^ expected `u32`, found `u16`
+ | |
+ | arguments to this function are incorrect
+ |
+note: function defined here
+ --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:12:4
+ |
+LL | fn wrong_arg_type(x: u32) -> u32 {
+ | ^^^^^^^^^^^^^^ ------
+help: change the type of the numeric literal from `u16` to `u32`
+ |
+LL | let x = wrong_arg_type(0u32);
+ | ~~~
+
+error[E0308]: mismatched types
+ --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:19:30
+ |
+LL | let x: u16 = function(0, 0u8);
+ | -------- ^^^ expected `bool`, found `u8`
+ | |
+ | arguments to this function are incorrect
+ |
+note: function defined here
+ --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:1:4
+ |
+LL | fn function<T>(x: T, y: bool) -> T {
+ | ^^^^^^^^ -------
+
+error[E0308]: arguments to this function are incorrect
+ --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:22:18
+ |
+LL | let x: u16 = function(0u32, 0u8);
+ | ^^^^^^^^ ---- --- expected `bool`, found `u8`
+ | |
+ | expected `u16`, found `u32`
+ |
+help: the return type of this call is `u32` due to the type of the argument passed
+ --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:22:18
+ |
+LL | let x: u16 = function(0u32, 0u8);
+ | ^^^^^^^^^----^^^^^^
+ | |
+ | this argument influences the return type of `function`
+note: function defined here
+ --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:1:4
+ |
+LL | fn function<T>(x: T, y: bool) -> T {
+ | ^^^^^^^^ ---- -------
+help: change the type of the numeric literal from `u32` to `u16`
+ |
+LL | let x: u16 = function(0u16, 0u8);
+ | ~~~
+
+error[E0308]: mismatched types
+ --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:25:27
+ |
+LL | let x: u16 = function(0u32, true);
+ | -------- ^^^^ expected `u16`, found `u32`
+ | |
+ | arguments to this function are incorrect
+ |
+help: the return type of this call is `u32` due to the type of the argument passed
+ --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:25:18
+ |
+LL | let x: u16 = function(0u32, true);
+ | ^^^^^^^^^----^^^^^^^
+ | |
+ | this argument influences the return type of `function`
+note: function defined here
+ --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:1:4
+ |
+LL | fn function<T>(x: T, y: bool) -> T {
+ | ^^^^^^^^ ----
+help: change the type of the numeric literal from `u32` to `u16`
+ |
+LL | let x: u16 = function(0u16, true);
+ | ~~~
+
+error[E0308]: mismatched types
+ --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:26:32
+ |
+LL | let x: u16 = (S {}).method(0u32);
+ | ------ ^^^^ expected `u16`, found `u32`
+ | |
+ | arguments to this method are incorrect
+ |
+help: the return type of this call is `u32` due to the type of the argument passed
+ --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:26:18
+ |
+LL | let x: u16 = (S {}).method(0u32);
+ | ^^^^^^^^^^^^^^----^
+ | |
+ | this argument influences the return type of `method`
+note: associated function defined here
+ --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:7:8
+ |
+LL | fn method<T>(&self, x: T) -> T {
+ | ^^^^^^ ----
+help: change the type of the numeric literal from `u32` to `u16`
+ |
+LL | let x: u16 = (S {}).method(0u16);
+ | ~~~
+
+error[E0308]: arguments to this function are incorrect
+ --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:27:5
+ |
+LL | function(0u32, 8u8)
+ | ^^^^^^^^ ---- --- expected `bool`, found `u8`
+ | |
+ | expected `()`, found `u32`
+ |
+help: the return type of this call is `u32` due to the type of the argument passed
+ --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:27:5
+ |
+LL | function(0u32, 8u8)
+ | ^^^^^^^^^----^^^^^^
+ | |
+ | this argument influences the return type of `function`
+note: function defined here
+ --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:1:4
+ |
+LL | fn function<T>(x: T, y: bool) -> T {
+ | ^^^^^^^^ ---- -------
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
|
LL | let _: S<impl Oops> = S;
| ^^^^ not found in this scope
- |
-help: you might be missing a type parameter
- |
-LL | fn f<Oops>() {
- | ++++++
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding
--> $DIR/issue-104513-ice.rs:3:14
|
= note: expected enum `Option<()>`
found unit type `()`
+help: the type constructed contains `()` due to the type of the argument passed
+ --> $DIR/issue-46112.rs:9:18
+ |
+LL | fn main() { test(Ok(())); }
+ | ^^^--^
+ | |
+ | this argument influences the type of `Ok`
note: tuple variant defined here
--> $SRC_DIR/core/src/result.rs:LL:COL
help: try wrapping the expression in `Some`
|
= note: expected tuple `(&mut u8,)`
found type `{integer}`
+help: the return type of this call is `{integer}` due to the type of the argument passed
+ --> $DIR/issue-84768.rs:7:5
+ |
+LL | <F as FnOnce(&mut u8)>::call_once(f, 1)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^
+ | |
+ | this argument influences the return type of `FnOnce`
note: associated function defined here
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
--> $DIR/ufcs-partially-resolved.rs:36:12
|
LL | let _: <u8 as Tr>::Y::NN;
- | ^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<<u8 as Tr>::Y as Trait>::NN`
+ | ^^^^^^^^^^^^^^^^^
+ |
+help: if there were a trait named `Example` with associated type `NN` implemented for `<u8 as Tr>::Y`, you could use the fully-qualified path
+ |
+LL | let _: <<u8 as Tr>::Y as Example>::NN;
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error[E0599]: no associated item named `NN` found for type `u16` in the current scope
--> $DIR/ufcs-partially-resolved.rs:38:20
| |
| arguments to this function are incorrect
|
+help: the return type of this call is `u32` due to the type of the argument passed
+ --> $DIR/ufcs-qpath-self-mismatch.rs:7:5
+ |
+LL | <i32 as Add<i32>>::add(1u32, 2);
+ | ^^^^^^^^^^^^^^^^^^^^^^^----^^^^
+ | |
+ | this argument influences the return type of `Add`
note: associated function defined here
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
help: change the type of the numeric literal from `u32` to `i32`
| |
| arguments to this function are incorrect
|
+help: the return type of this call is `u32` due to the type of the argument passed
+ --> $DIR/ufcs-qpath-self-mismatch.rs:9:5
+ |
+LL | <i32 as Add<i32>>::add(1, 2u32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^----^
+ | |
+ | this argument influences the return type of `Add`
note: associated function defined here
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
help: change the type of the numeric literal from `u32` to `i32`
[autolabel."WG-trait-system-refactor"]
trigger_files = [
- "compiler/rustc_trait_selection/solve"
+ "compiler/rustc_trait_selection/src/solve"
]
[notify-zulip."I-prioritize"]