mirror of
https://git.proxmox.com/git/rustc
synced 2026-01-16 09:27:07 +00:00
Update upstream source from tag 'upstream/1.78.0+dfsg1'
Update to upstream version '1.78.0+dfsg1'
with Debian dir 75a0bc05c6
This commit is contained in:
commit
cfcf1d8c6a
1688
Cargo.lock
generated
1688
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -10,6 +10,7 @@ members = [
|
||||
"src/tools/clippy",
|
||||
"src/tools/clippy/clippy_dev",
|
||||
"src/tools/compiletest",
|
||||
"src/tools/run-make-support",
|
||||
"src/tools/error_index_generator",
|
||||
"src/tools/linkchecker",
|
||||
"src/tools/lint-docs",
|
||||
@ -33,6 +34,7 @@ members = [
|
||||
"src/tools/expand-yaml-anchors",
|
||||
"src/tools/jsondocck",
|
||||
"src/tools/jsondoclint",
|
||||
"src/tools/llvm-bitcode-linker",
|
||||
"src/tools/html-checker",
|
||||
"src/tools/bump-stage0",
|
||||
"src/tools/replace-version-placeholder",
|
||||
|
||||
122
RELEASES.md
122
RELEASES.md
@ -1,3 +1,123 @@
|
||||
Version 1.78.0 (2024-05-02)
|
||||
==========================
|
||||
|
||||
<a id="1.78.0-Language"></a>
|
||||
|
||||
Language
|
||||
--------
|
||||
- [Stabilize `#[cfg(target_abi = ...)]`](https://github.com/rust-lang/rust/pull/119590/)
|
||||
- [Stabilize the `#[diagnostic]` namespace and `#[diagnostic::on_unimplemented]` attribute](https://github.com/rust-lang/rust/pull/119888/)
|
||||
- [Make async-fn-in-trait implementable with concrete signatures](https://github.com/rust-lang/rust/pull/120103/)
|
||||
- [Make matching on NaN a hard error, and remove the rest of `illegal_floating_point_literal_pattern`](https://github.com/rust-lang/rust/pull/116284/)
|
||||
- [static mut: allow mutable reference to arbitrary types, not just slices and arrays](https://github.com/rust-lang/rust/pull/117614/)
|
||||
- [Extend `invalid_reference_casting` to include references casting to bigger memory layout](https://github.com/rust-lang/rust/pull/118983/)
|
||||
- [Add `non_contiguous_range_endpoints` lint for singleton gaps after exclusive ranges](https://github.com/rust-lang/rust/pull/118879/)
|
||||
- [Add `wasm_c_abi` lint for use of older wasm-bindgen versions](https://github.com/rust-lang/rust/pull/117918/)
|
||||
This lint currently only works when using Cargo.
|
||||
- [Update `indirect_structural_match` and `pointer_structural_match` lints to match RFC](https://github.com/rust-lang/rust/pull/120423/)
|
||||
- [Make non-`PartialEq`-typed consts as patterns a hard error](https://github.com/rust-lang/rust/pull/120805/)
|
||||
- [Split `refining_impl_trait` lint into `_reachable`, `_internal` variants](https://github.com/rust-lang/rust/pull/121720/)
|
||||
- [Remove unnecessary type inference when using associated types inside of higher ranked `where`-bounds](https://github.com/rust-lang/rust/pull/119849)
|
||||
- [Weaken eager detection of cyclic types during type inference](https://github.com/rust-lang/rust/pull/119989)
|
||||
- [`trait Trait: Auto {}`: allow upcasting from `dyn Trait` to `dyn Auto`](https://github.com/rust-lang/rust/pull/119338)
|
||||
|
||||
<a id="1.78.0-Compiler"></a>
|
||||
|
||||
Compiler
|
||||
--------
|
||||
|
||||
- [Made `INVALID_DOC_ATTRIBUTES` lint deny by default](https://github.com/rust-lang/rust/pull/111505/)
|
||||
- [Increase accuracy of redundant `use` checking](https://github.com/rust-lang/rust/pull/117772/)
|
||||
- [Suggest moving definition if non-found macro_rules! is defined later](https://github.com/rust-lang/rust/pull/121130/)
|
||||
- [Lower transmutes from int to pointer type as gep on null](https://github.com/rust-lang/rust/pull/121282/)
|
||||
|
||||
Target changes:
|
||||
|
||||
- [Windows tier 1 targets now require at least Windows 10](https://github.com/rust-lang/rust/pull/115141/)
|
||||
- [Enable CMPXCHG16B, SSE3, SAHF/LAHF and 128-bit Atomics in tier 1 Windows](https://github.com/rust-lang/rust/pull/120820/)
|
||||
- [Add `wasm32-wasip1` tier 2 (without host tools) target](https://github.com/rust-lang/rust/pull/120468/)
|
||||
- [Add `wasm32-wasip2` tier 3 target](https://github.com/rust-lang/rust/pull/119616/)
|
||||
- [Rename `wasm32-wasi-preview1-threads` to `wasm32-wasip1-threads`](https://github.com/rust-lang/rust/pull/122170/)
|
||||
- [Add `arm64ec-pc-windows-msvc` tier 3 target](https://github.com/rust-lang/rust/pull/119199/)
|
||||
- [Add `armv8r-none-eabihf` tier 3 target for the Cortex-R52](https://github.com/rust-lang/rust/pull/110482/)
|
||||
- [Add `loongarch64-unknown-linux-musl` tier 3 target](https://github.com/rust-lang/rust/pull/121832/)
|
||||
|
||||
Refer to Rust's [platform support page][platform-support-doc]
|
||||
for more information on Rust's tiered platform support.
|
||||
|
||||
<a id="1.78.0-Libraries"></a>
|
||||
|
||||
Libraries
|
||||
---------
|
||||
|
||||
- [Bump Unicode to version 15.1.0, regenerate tables](https://github.com/rust-lang/rust/pull/120777/)
|
||||
- [Make align_offset, align_to well-behaved in all cases](https://github.com/rust-lang/rust/pull/121201/)
|
||||
- [PartialEq, PartialOrd: document expectations for transitive chains](https://github.com/rust-lang/rust/pull/115386/)
|
||||
- [Optimize away poison guards when std is built with panic=abort](https://github.com/rust-lang/rust/pull/100603/)
|
||||
- [Replace pthread `RwLock` with custom implementation](https://github.com/rust-lang/rust/pull/110211/)
|
||||
- [Implement unwind safety for Condvar on all platforms](https://github.com/rust-lang/rust/pull/121768/)
|
||||
- [Add ASCII fast-path for `char::is_grapheme_extended`](https://github.com/rust-lang/rust/pull/121138/)
|
||||
|
||||
<a id="1.78.0-Stabilized-APIs"></a>
|
||||
|
||||
Stabilized APIs
|
||||
---------------
|
||||
|
||||
- [`impl Read for &Stdin`](https://doc.rust-lang.org/stable/std/io/struct.Stdin.html#impl-Read-for-%26Stdin)
|
||||
- [Accept non `'static` lifetimes for several `std::error::Error` related implementations](https://github.com/rust-lang/rust/pull/113833/)
|
||||
- [Make `impl<Fd: AsFd>` impl take `?Sized`](https://github.com/rust-lang/rust/pull/114655/)
|
||||
- [`impl From<TryReserveError> for io::Error`](https://doc.rust-lang.org/stable/std/io/struct.Error.html#impl-From%3CTryReserveError%3E-for-Error)
|
||||
|
||||
These APIs are now stable in const contexts:
|
||||
|
||||
- [`Barrier::new()`](https://doc.rust-lang.org/stable/std/sync/struct.Barrier.html#method.new)
|
||||
|
||||
<a id="1.78.0-Cargo"></a>
|
||||
|
||||
Cargo
|
||||
-----
|
||||
|
||||
- [Stabilize lockfile v4](https://github.com/rust-lang/cargo/pull/12852/)
|
||||
- [Respect `rust-version` when generating lockfile](https://github.com/rust-lang/cargo/pull/12861/)
|
||||
- [Control `--charset` via auto-detecting config value](https://github.com/rust-lang/cargo/pull/13337/)
|
||||
- [Support `target.<triple>.rustdocflags` officially](https://github.com/rust-lang/cargo/pull/13197/)
|
||||
- [Stabilize global cache data tracking](https://github.com/rust-lang/cargo/pull/13492/)
|
||||
|
||||
<a id="1.78.0-Misc"></a>
|
||||
|
||||
Misc
|
||||
----
|
||||
|
||||
- [rustdoc: add `--test-builder-wrapper` arg to support wrappers such as RUSTC_WRAPPER when building doctests](https://github.com/rust-lang/rust/pull/114651/)
|
||||
|
||||
<a id="1.78.0-Compatibility-Notes"></a>
|
||||
|
||||
Compatibility Notes
|
||||
-------------------
|
||||
|
||||
- [Many unsafe precondition checks now run for user code with debug assertions enabled](https://github.com/rust-lang/rust/pull/120594/)
|
||||
This change helps users catch undefined behavior in their code, though the details of how much is checked are generally not stable.
|
||||
- [riscv only supports split_debuginfo=off for now](https://github.com/rust-lang/rust/pull/120518/)
|
||||
- [Consistently check bounds on hidden types of `impl Trait`](https://github.com/rust-lang/rust/pull/121679)
|
||||
- [Change equality of higher ranked types to not rely on subtyping](https://github.com/rust-lang/rust/pull/118247)
|
||||
- [When called, additionally check bounds on normalized function return type](https://github.com/rust-lang/rust/pull/118882)
|
||||
- [Expand coverage for `arithmetic_overflow` lint](https://github.com/rust-lang/rust/pull/119432/)
|
||||
|
||||
<a id="1.78.0-Internal-Changes"></a>
|
||||
|
||||
Internal Changes
|
||||
----------------
|
||||
|
||||
These changes do not affect any public interfaces of Rust, but they represent
|
||||
significant improvements to the performance or internals of rustc and related
|
||||
tools.
|
||||
|
||||
- [Update to LLVM 18](https://github.com/rust-lang/rust/pull/120055/)
|
||||
- [Build `rustc` with 1CGU on `x86_64-pc-windows-msvc`](https://github.com/rust-lang/rust/pull/112267/)
|
||||
- [Build `rustc` with 1CGU on `x86_64-apple-darwin`](https://github.com/rust-lang/rust/pull/112268/)
|
||||
- [Introduce `run-make` V2 infrastructure, a `run_make_support` library and port over 2 tests as example](https://github.com/rust-lang/rust/pull/113026/)
|
||||
- [Windows: Implement condvar, mutex and rwlock using futex](https://github.com/rust-lang/rust/pull/121956/)
|
||||
|
||||
Version 1.77.2 (2024-04-09)
|
||||
===========================
|
||||
|
||||
@ -99,7 +219,7 @@ Cargo
|
||||
|
||||
- [Extend the build directive syntax with `cargo::`.](https://github.com/rust-lang/cargo/pull/12201/)
|
||||
- [Stabilize metadata `id` format as `PackageIDSpec`.](https://github.com/rust-lang/cargo/pull/12914/)
|
||||
- [Pull out as `cargo-util-schemas` as a crate.](https://github.com/rust-lang/cargo/pull/13178/)
|
||||
- [Pull out `cargo-util-schemas` as a crate.](https://github.com/rust-lang/cargo/pull/13178/)
|
||||
- [Strip all debuginfo when debuginfo is not requested.](https://github.com/rust-lang/cargo/pull/13257/)
|
||||
- [Inherit jobserver from env for all kinds of runners.](https://github.com/rust-lang/cargo/pull/12776/)
|
||||
- [Deprecate rustc plugin support in cargo.](https://github.com/rust-lang/cargo/pull/13248/)
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
use std::borrow::{Borrow, Cow};
|
||||
use std::cmp;
|
||||
use std::fmt::{self, Write};
|
||||
use std::iter;
|
||||
use std::ops::Bound;
|
||||
use std::ops::Deref;
|
||||
use std::{borrow::Borrow, cmp, iter, ops::Bound};
|
||||
|
||||
use rustc_index::Idx;
|
||||
use tracing::debug;
|
||||
@ -32,7 +35,7 @@ where
|
||||
pub trait LayoutCalculator {
|
||||
type TargetDataLayoutRef: Borrow<TargetDataLayout>;
|
||||
|
||||
fn delayed_bug(&self, txt: String);
|
||||
fn delayed_bug(&self, txt: impl Into<Cow<'static, str>>);
|
||||
fn current_data_layout(&self) -> Self::TargetDataLayoutRef;
|
||||
|
||||
fn scalar_pair<FieldIdx: Idx, VariantIdx: Idx>(
|
||||
@ -813,15 +816,37 @@ where
|
||||
break;
|
||||
}
|
||||
};
|
||||
if let Some(pair) = common_prim {
|
||||
// This is pretty conservative. We could go fancier
|
||||
// by conflating things like i32 and u32, or even
|
||||
// realising that (u8, u8) could just cohabit with
|
||||
// u16 or even u32.
|
||||
if pair != (prim, offset) {
|
||||
if let Some((old_prim, common_offset)) = common_prim {
|
||||
// All variants must be at the same offset
|
||||
if offset != common_offset {
|
||||
common_prim = None;
|
||||
break;
|
||||
}
|
||||
// This is pretty conservative. We could go fancier
|
||||
// by realising that (u8, u8) could just cohabit with
|
||||
// u16 or even u32.
|
||||
let new_prim = match (old_prim, prim) {
|
||||
// Allow all identical primitives.
|
||||
(x, y) if x == y => x,
|
||||
// Allow integers of the same size with differing signedness.
|
||||
// We arbitrarily choose the signedness of the first variant.
|
||||
(p @ Primitive::Int(x, _), Primitive::Int(y, _)) if x == y => p,
|
||||
// Allow integers mixed with pointers of the same layout.
|
||||
// We must represent this using a pointer, to avoid
|
||||
// roundtripping pointers through ptrtoint/inttoptr.
|
||||
(p @ Primitive::Pointer(_), i @ Primitive::Int(..))
|
||||
| (i @ Primitive::Int(..), p @ Primitive::Pointer(_))
|
||||
if p.size(dl) == i.size(dl) && p.align(dl) == i.align(dl) =>
|
||||
{
|
||||
p
|
||||
}
|
||||
_ => {
|
||||
common_prim = None;
|
||||
break;
|
||||
}
|
||||
};
|
||||
// We may be updating the primitive here, for example from int->ptr.
|
||||
common_prim = Some((new_prim, common_offset));
|
||||
} else {
|
||||
common_prim = Some((prim, offset));
|
||||
}
|
||||
@ -958,7 +983,7 @@ fn univariant<
|
||||
#[cfg(feature = "randomize")]
|
||||
{
|
||||
use rand::{seq::SliceRandom, SeedableRng};
|
||||
// `ReprOptions.layout_seed` is a deterministic seed we can use to randomize field
|
||||
// `ReprOptions.field_shuffle_seed` is a deterministic seed we can use to randomize field
|
||||
// ordering.
|
||||
let mut rng =
|
||||
rand_xoshiro::Xoshiro128StarStar::seed_from_u64(repr.field_shuffle_seed);
|
||||
|
||||
@ -41,7 +41,7 @@ bitflags! {
|
||||
// Internal only for now. If true, don't reorder fields.
|
||||
const IS_LINEAR = 1 << 3;
|
||||
// If true, the type's layout can be randomized using
|
||||
// the seed stored in `ReprOptions.layout_seed`
|
||||
// the seed stored in `ReprOptions.field_shuffle_seed`
|
||||
const RANDOMIZE_LAYOUT = 1 << 4;
|
||||
// Any of these flags being set prevent field reordering optimisation.
|
||||
const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits()
|
||||
@ -171,8 +171,10 @@ pub struct TargetDataLayout {
|
||||
pub i32_align: AbiAndPrefAlign,
|
||||
pub i64_align: AbiAndPrefAlign,
|
||||
pub i128_align: AbiAndPrefAlign,
|
||||
pub f16_align: AbiAndPrefAlign,
|
||||
pub f32_align: AbiAndPrefAlign,
|
||||
pub f64_align: AbiAndPrefAlign,
|
||||
pub f128_align: AbiAndPrefAlign,
|
||||
pub pointer_size: Size,
|
||||
pub pointer_align: AbiAndPrefAlign,
|
||||
pub aggregate_align: AbiAndPrefAlign,
|
||||
@ -200,8 +202,10 @@ impl Default for TargetDataLayout {
|
||||
i32_align: AbiAndPrefAlign::new(align(32)),
|
||||
i64_align: AbiAndPrefAlign { abi: align(32), pref: align(64) },
|
||||
i128_align: AbiAndPrefAlign { abi: align(32), pref: align(64) },
|
||||
f16_align: AbiAndPrefAlign::new(align(16)),
|
||||
f32_align: AbiAndPrefAlign::new(align(32)),
|
||||
f64_align: AbiAndPrefAlign::new(align(64)),
|
||||
f128_align: AbiAndPrefAlign::new(align(128)),
|
||||
pointer_size: Size::from_bits(64),
|
||||
pointer_align: AbiAndPrefAlign::new(align(64)),
|
||||
aggregate_align: AbiAndPrefAlign { abi: align(0), pref: align(64) },
|
||||
@ -281,8 +285,10 @@ impl TargetDataLayout {
|
||||
dl.instruction_address_space = parse_address_space(&p[1..], "P")?
|
||||
}
|
||||
["a", ref a @ ..] => dl.aggregate_align = parse_align(a, "a")?,
|
||||
["f16", ref a @ ..] => dl.f16_align = parse_align(a, "f16")?,
|
||||
["f32", ref a @ ..] => dl.f32_align = parse_align(a, "f32")?,
|
||||
["f64", ref a @ ..] => dl.f64_align = parse_align(a, "f64")?,
|
||||
["f128", ref a @ ..] => dl.f128_align = parse_align(a, "f128")?,
|
||||
// FIXME(erikdesjardins): we should be parsing nonzero address spaces
|
||||
// this will require replacing TargetDataLayout::{pointer_size,pointer_align}
|
||||
// with e.g. `fn pointer_size_in(AddressSpace)`
|
||||
@ -919,8 +925,10 @@ pub enum Primitive {
|
||||
/// a negative integer passed by zero-extension will appear positive in
|
||||
/// the callee, and most operations on it will produce the wrong values.
|
||||
Int(Integer, bool),
|
||||
F16,
|
||||
F32,
|
||||
F64,
|
||||
F128,
|
||||
Pointer(AddressSpace),
|
||||
}
|
||||
|
||||
@ -931,8 +939,10 @@ impl Primitive {
|
||||
|
||||
match self {
|
||||
Int(i, _) => i.size(),
|
||||
F16 => Size::from_bits(16),
|
||||
F32 => Size::from_bits(32),
|
||||
F64 => Size::from_bits(64),
|
||||
F128 => Size::from_bits(128),
|
||||
// FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
|
||||
// different address spaces can have different sizes
|
||||
// (but TargetDataLayout doesn't currently parse that part of the DL string)
|
||||
@ -946,8 +956,10 @@ impl Primitive {
|
||||
|
||||
match self {
|
||||
Int(i, _) => i.align(dl),
|
||||
F16 => dl.f16_align,
|
||||
F32 => dl.f32_align,
|
||||
F64 => dl.f64_align,
|
||||
F128 => dl.f128_align,
|
||||
// FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
|
||||
// different address spaces can have different alignments
|
||||
// (but TargetDataLayout doesn't currently parse that part of the DL string)
|
||||
@ -1600,8 +1612,9 @@ pub enum PointerKind {
|
||||
SharedRef { frozen: bool },
|
||||
/// Mutable reference. `unpin` indicates the absence of any pinned data.
|
||||
MutableRef { unpin: bool },
|
||||
/// Box. `unpin` indicates the absence of any pinned data.
|
||||
Box { unpin: bool },
|
||||
/// Box. `unpin` indicates the absence of any pinned data. `global` indicates whether this box
|
||||
/// uses the global allocator or a custom one.
|
||||
Box { unpin: bool, global: bool },
|
||||
}
|
||||
|
||||
/// Note that this information is advisory only, and backends are free to ignore it.
|
||||
@ -1610,6 +1623,8 @@ pub enum PointerKind {
|
||||
pub struct PointeeInfo {
|
||||
pub size: Size,
|
||||
pub align: Align,
|
||||
/// If this is `None`, then this is a raw pointer, so size and alignment are not guaranteed to
|
||||
/// be reliable.
|
||||
pub safe: Option<PointerKind>,
|
||||
}
|
||||
|
||||
|
||||
@ -22,8 +22,6 @@
|
||||
#![cfg_attr(test, feature(test))]
|
||||
#![feature(strict_provenance)]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(internal_features)]
|
||||
#![allow(clippy::mut_from_ref)] // Arena allocators are one of the places where this pattern is fine.
|
||||
|
||||
@ -97,7 +95,7 @@ impl<T> ArenaChunk<T> {
|
||||
unsafe {
|
||||
if mem::size_of::<T>() == 0 {
|
||||
// A pointer as large as possible for zero-sized elements.
|
||||
ptr::invalid_mut(!0)
|
||||
ptr::without_provenance_mut(!0)
|
||||
} else {
|
||||
self.start().add(self.storage.len())
|
||||
}
|
||||
|
||||
@ -4,17 +4,17 @@ version = "0.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
# FIXME: bumping memchr to 2.7.1 causes linker errors in MSVC thin-lto
|
||||
# tidy-alphabetical-start
|
||||
bitflags = "2.4.1"
|
||||
memchr = "2.5.0"
|
||||
memchr = "=2.5.0"
|
||||
rustc_ast_ir = { path = "../rustc_ast_ir" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
rustc_lexer = { path = "../rustc_lexer" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_serialize = { path = "../rustc_serialize" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
# For Mutability and Movability, which could be uplifted into a common crate.
|
||||
rustc_type_ir = { path = "../rustc_type_ir" }
|
||||
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
||||
thin-vec = "0.2.12"
|
||||
tracing = "0.1"
|
||||
|
||||
@ -27,6 +27,7 @@ pub use UnsafeSource::*;
|
||||
use crate::ptr::P;
|
||||
use crate::token::{self, CommentKind, Delimiter};
|
||||
use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream};
|
||||
pub use rustc_ast_ir::{Movability, Mutability};
|
||||
use rustc_data_structures::packed::Pu128;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
@ -35,7 +36,6 @@ use rustc_macros::HashStable_Generic;
|
||||
use rustc_span::source_map::{respan, Spanned};
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
|
||||
pub use rustc_type_ir::{Movability, Mutability};
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
use thin_vec::{thin_vec, ThinVec};
|
||||
@ -291,12 +291,16 @@ pub use crate::node_id::{NodeId, CRATE_NODE_ID, DUMMY_NODE_ID};
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
|
||||
pub struct TraitBoundModifiers {
|
||||
pub constness: BoundConstness,
|
||||
pub asyncness: BoundAsyncness,
|
||||
pub polarity: BoundPolarity,
|
||||
}
|
||||
|
||||
impl TraitBoundModifiers {
|
||||
pub const NONE: Self =
|
||||
Self { constness: BoundConstness::Never, polarity: BoundPolarity::Positive };
|
||||
pub const NONE: Self = Self {
|
||||
constness: BoundConstness::Never,
|
||||
asyncness: BoundAsyncness::Normal,
|
||||
polarity: BoundPolarity::Positive,
|
||||
};
|
||||
}
|
||||
|
||||
/// The AST represents all type param bounds as types.
|
||||
@ -399,9 +403,10 @@ impl Default for Generics {
|
||||
/// A where-clause in a definition.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct WhereClause {
|
||||
/// `true` if we ate a `where` token: this can happen
|
||||
/// if we parsed no predicates (e.g. `struct Foo where {}`).
|
||||
/// This allows us to pretty-print accurately.
|
||||
/// `true` if we ate a `where` token.
|
||||
///
|
||||
/// This can happen if we parsed no predicates, e.g., `struct Foo where {}`.
|
||||
/// This allows us to pretty-print accurately and provide correct suggestion diagnostics.
|
||||
pub has_where_token: bool,
|
||||
pub predicates: ThinVec<WherePredicate>,
|
||||
pub span: Span,
|
||||
@ -666,6 +671,16 @@ impl Pat {
|
||||
});
|
||||
contains_never_pattern
|
||||
}
|
||||
|
||||
/// Return a name suitable for diagnostics.
|
||||
pub fn descr(&self) -> Option<String> {
|
||||
match &self.kind {
|
||||
PatKind::Wild => Some("_".to_string()),
|
||||
PatKind::Ident(BindingAnnotation::NONE, ident, None) => Some(format!("{ident}")),
|
||||
PatKind::Ref(pat, mutbl) => pat.descr().map(|d| format!("&{}{d}", mutbl.prefix_str())),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A single field in a struct pattern.
|
||||
@ -1006,7 +1021,7 @@ impl Stmt {
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum StmtKind {
|
||||
/// A local (let) binding.
|
||||
Local(P<Local>),
|
||||
Let(P<Local>),
|
||||
/// An item definition.
|
||||
Item(P<Item>),
|
||||
/// Expr without trailing semi-colon.
|
||||
@ -1048,6 +1063,7 @@ pub struct Local {
|
||||
pub ty: Option<P<Ty>>,
|
||||
pub kind: LocalKind,
|
||||
pub span: Span,
|
||||
pub colon_sp: Option<Span>,
|
||||
pub attrs: AttrVec,
|
||||
pub tokens: Option<LazyAttrTokenStream>,
|
||||
}
|
||||
@ -1292,23 +1308,10 @@ impl Expr {
|
||||
ExprKind::Yeet(..) => ExprPrecedence::Yeet,
|
||||
ExprKind::FormatArgs(..) => ExprPrecedence::FormatArgs,
|
||||
ExprKind::Become(..) => ExprPrecedence::Become,
|
||||
ExprKind::Err => ExprPrecedence::Err,
|
||||
ExprKind::Err(_) | ExprKind::Dummy => ExprPrecedence::Err,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn take(&mut self) -> Self {
|
||||
mem::replace(
|
||||
self,
|
||||
Expr {
|
||||
id: DUMMY_NODE_ID,
|
||||
kind: ExprKind::Err,
|
||||
span: DUMMY_SP,
|
||||
attrs: AttrVec::new(),
|
||||
tokens: None,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// To a first-order approximation, is this a pattern?
|
||||
pub fn is_approximately_pattern(&self) -> bool {
|
||||
matches!(
|
||||
@ -1527,7 +1530,10 @@ pub enum ExprKind {
|
||||
FormatArgs(P<FormatArgs>),
|
||||
|
||||
/// Placeholder for an expression that wasn't syntactically well formed in some way.
|
||||
Err,
|
||||
Err(ErrorGuaranteed),
|
||||
|
||||
/// Acts as a null expression. Lowering it will always emit a bug.
|
||||
Dummy,
|
||||
}
|
||||
|
||||
/// Used to differentiate between `for` loops and `for await` loops.
|
||||
@ -1842,7 +1848,7 @@ pub enum LitKind {
|
||||
/// A boolean literal (`true`, `false`).
|
||||
Bool(bool),
|
||||
/// Placeholder for a literal that wasn't well-formed in some way.
|
||||
Err,
|
||||
Err(ErrorGuaranteed),
|
||||
}
|
||||
|
||||
impl LitKind {
|
||||
@ -1889,7 +1895,7 @@ impl LitKind {
|
||||
| LitKind::Int(_, LitIntType::Unsuffixed)
|
||||
| LitKind::Float(_, LitFloatType::Unsuffixed)
|
||||
| LitKind::Bool(..)
|
||||
| LitKind::Err => false,
|
||||
| LitKind::Err(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1914,22 +1920,28 @@ pub struct FnSig {
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||
#[derive(Encodable, Decodable, HashStable_Generic)]
|
||||
pub enum FloatTy {
|
||||
F16,
|
||||
F32,
|
||||
F64,
|
||||
F128,
|
||||
}
|
||||
|
||||
impl FloatTy {
|
||||
pub fn name_str(self) -> &'static str {
|
||||
match self {
|
||||
FloatTy::F16 => "f16",
|
||||
FloatTy::F32 => "f32",
|
||||
FloatTy::F64 => "f64",
|
||||
FloatTy::F128 => "f128",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(self) -> Symbol {
|
||||
match self {
|
||||
FloatTy::F16 => sym::f16,
|
||||
FloatTy::F32 => sym::f32,
|
||||
FloatTy::F64 => sym::f64,
|
||||
FloatTy::F128 => sym::f128,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2103,9 +2115,9 @@ pub enum TyKind {
|
||||
/// A tuple (`(A, B, C, D,...)`).
|
||||
Tup(ThinVec<P<Ty>>),
|
||||
/// An anonymous struct type i.e. `struct { foo: Type }`
|
||||
AnonStruct(ThinVec<FieldDef>),
|
||||
AnonStruct(NodeId, ThinVec<FieldDef>),
|
||||
/// An anonymous union type i.e. `union { bar: Type }`
|
||||
AnonUnion(ThinVec<FieldDef>),
|
||||
AnonUnion(NodeId, ThinVec<FieldDef>),
|
||||
/// A path (`module::module::...::Type`), optionally
|
||||
/// "qualified", e.g., `<Vec<T> as SomeTrait>::SomeType`.
|
||||
///
|
||||
@ -2132,10 +2144,12 @@ pub enum TyKind {
|
||||
ImplicitSelf,
|
||||
/// A macro in the type position.
|
||||
MacCall(P<MacCall>),
|
||||
/// Placeholder for a kind that has failed to be defined.
|
||||
Err,
|
||||
/// Placeholder for a `va_list`.
|
||||
CVarArgs,
|
||||
/// Sometimes we need a dummy value when no error has occurred.
|
||||
Dummy,
|
||||
/// Placeholder for a kind that has failed to be defined.
|
||||
Err(ErrorGuaranteed),
|
||||
}
|
||||
|
||||
impl TyKind {
|
||||
@ -2157,6 +2171,10 @@ impl TyKind {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_anon_adt(&self) -> bool {
|
||||
matches!(self, TyKind::AnonStruct(..) | TyKind::AnonUnion(..))
|
||||
}
|
||||
}
|
||||
|
||||
/// Syntax used to declare a trait object.
|
||||
@ -2284,6 +2302,9 @@ pub enum InlineAsmOperand {
|
||||
Sym {
|
||||
sym: InlineAsmSym,
|
||||
},
|
||||
Label {
|
||||
block: P<Block>,
|
||||
},
|
||||
}
|
||||
|
||||
impl InlineAsmOperand {
|
||||
@ -2293,7 +2314,7 @@ impl InlineAsmOperand {
|
||||
| Self::Out { reg, .. }
|
||||
| Self::InOut { reg, .. }
|
||||
| Self::SplitInOut { reg, .. } => Some(reg),
|
||||
Self::Const { .. } | Self::Sym { .. } => None,
|
||||
Self::Const { .. } | Self::Sym { .. } | Self::Label { .. } => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2562,6 +2583,25 @@ impl BoundConstness {
|
||||
}
|
||||
}
|
||||
|
||||
/// The asyncness of a trait bound.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
|
||||
#[derive(HashStable_Generic)]
|
||||
pub enum BoundAsyncness {
|
||||
/// `Type: Trait`
|
||||
Normal,
|
||||
/// `Type: async Trait`
|
||||
Async(Span),
|
||||
}
|
||||
|
||||
impl BoundAsyncness {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Normal => "",
|
||||
Self::Async(_) => "async",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum FnRetTy {
|
||||
/// Returns type is not specified.
|
||||
@ -2988,18 +3028,29 @@ pub struct Trait {
|
||||
///
|
||||
/// If there is no where clause, then this is `false` with `DUMMY_SP`.
|
||||
#[derive(Copy, Clone, Encodable, Decodable, Debug, Default)]
|
||||
pub struct TyAliasWhereClause(pub bool, pub Span);
|
||||
pub struct TyAliasWhereClause {
|
||||
pub has_where_token: bool,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
/// The span information for the two where clauses on a `TyAlias`.
|
||||
#[derive(Copy, Clone, Encodable, Decodable, Debug, Default)]
|
||||
pub struct TyAliasWhereClauses {
|
||||
/// Before the equals sign.
|
||||
pub before: TyAliasWhereClause,
|
||||
/// After the equals sign.
|
||||
pub after: TyAliasWhereClause,
|
||||
/// The index in `TyAlias.generics.where_clause.predicates` that would split
|
||||
/// into predicates from the where clause before the equals sign and the ones
|
||||
/// from the where clause after the equals sign.
|
||||
pub split: usize,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct TyAlias {
|
||||
pub defaultness: Defaultness,
|
||||
pub generics: Generics,
|
||||
/// The span information for the two where clauses (before equals, after equals)
|
||||
pub where_clauses: (TyAliasWhereClause, TyAliasWhereClause),
|
||||
/// The index in `generics.where_clause.predicates` that would split into
|
||||
/// predicates from the where clause before the equals and the predicates
|
||||
/// from the where clause after the equals
|
||||
pub where_predicates_split: usize,
|
||||
pub where_clauses: TyAliasWhereClauses,
|
||||
pub bounds: GenericBounds,
|
||||
pub ty: Option<P<Ty>>,
|
||||
}
|
||||
@ -3300,13 +3351,13 @@ mod size_asserts {
|
||||
static_assert_size!(ForeignItem, 96);
|
||||
static_assert_size!(ForeignItemKind, 24);
|
||||
static_assert_size!(GenericArg, 24);
|
||||
static_assert_size!(GenericBound, 72);
|
||||
static_assert_size!(GenericBound, 88);
|
||||
static_assert_size!(Generics, 40);
|
||||
static_assert_size!(Impl, 136);
|
||||
static_assert_size!(Item, 136);
|
||||
static_assert_size!(ItemKind, 64);
|
||||
static_assert_size!(LitKind, 24);
|
||||
static_assert_size!(Local, 72);
|
||||
static_assert_size!(Local, 80);
|
||||
static_assert_size!(MetaItemLit, 40);
|
||||
static_assert_size!(Param, 40);
|
||||
static_assert_size!(Pat, 72);
|
||||
|
||||
@ -182,7 +182,7 @@ impl<T: HasTokens> HasTokens for Option<T> {
|
||||
impl HasTokens for StmtKind {
|
||||
fn tokens(&self) -> Option<&LazyAttrTokenStream> {
|
||||
match self {
|
||||
StmtKind::Local(local) => local.tokens.as_ref(),
|
||||
StmtKind::Let(local) => local.tokens.as_ref(),
|
||||
StmtKind::Item(item) => item.tokens(),
|
||||
StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.tokens(),
|
||||
StmtKind::Empty => return None,
|
||||
@ -191,7 +191,7 @@ impl HasTokens for StmtKind {
|
||||
}
|
||||
fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
|
||||
match self {
|
||||
StmtKind::Local(local) => Some(&mut local.tokens),
|
||||
StmtKind::Let(local) => Some(&mut local.tokens),
|
||||
StmtKind::Item(item) => item.tokens_mut(),
|
||||
StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.tokens_mut(),
|
||||
StmtKind::Empty => return None,
|
||||
@ -355,7 +355,7 @@ impl HasAttrs for StmtKind {
|
||||
|
||||
fn attrs(&self) -> &[Attribute] {
|
||||
match self {
|
||||
StmtKind::Local(local) => &local.attrs,
|
||||
StmtKind::Let(local) => &local.attrs,
|
||||
StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.attrs(),
|
||||
StmtKind::Item(item) => item.attrs(),
|
||||
StmtKind::Empty => &[],
|
||||
@ -365,7 +365,7 @@ impl HasAttrs for StmtKind {
|
||||
|
||||
fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) {
|
||||
match self {
|
||||
StmtKind::Local(local) => f(&mut local.attrs),
|
||||
StmtKind::Let(local) => f(&mut local.attrs),
|
||||
StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f),
|
||||
StmtKind::Item(item) => item.visit_attrs(f),
|
||||
StmtKind::Empty => {}
|
||||
|
||||
@ -12,14 +12,14 @@
|
||||
#![allow(internal_features)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(associated_type_bounds)]
|
||||
#![feature(associated_type_defaults)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(min_specialization)]
|
||||
#![cfg_attr(bootstrap, feature(min_specialization))]
|
||||
#![feature(never_type)]
|
||||
#![feature(negative_impls)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate rustc_macros;
|
||||
|
||||
@ -481,7 +481,12 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
|
||||
let Ty { id, kind, span, tokens } = ty.deref_mut();
|
||||
vis.visit_id(id);
|
||||
match kind {
|
||||
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err | TyKind::Never | TyKind::CVarArgs => {}
|
||||
TyKind::Infer
|
||||
| TyKind::ImplicitSelf
|
||||
| TyKind::Err(_)
|
||||
| TyKind::Dummy
|
||||
| TyKind::Never
|
||||
| TyKind::CVarArgs => {}
|
||||
TyKind::Slice(ty) => vis.visit_ty(ty),
|
||||
TyKind::Ptr(mt) => vis.visit_mt(mt),
|
||||
TyKind::Ref(lt, mt) => {
|
||||
@ -514,7 +519,8 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
|
||||
visit_vec(bounds, |bound| vis.visit_param_bound(bound));
|
||||
}
|
||||
TyKind::MacCall(mac) => vis.visit_mac_call(mac),
|
||||
TyKind::AnonStruct(fields) | TyKind::AnonUnion(fields) => {
|
||||
TyKind::AnonStruct(id, fields) | TyKind::AnonUnion(id, fields) => {
|
||||
vis.visit_id(id);
|
||||
fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
|
||||
}
|
||||
}
|
||||
@ -603,7 +609,7 @@ pub fn noop_visit_parenthesized_parameter_data<T: MutVisitor>(
|
||||
}
|
||||
|
||||
pub fn noop_visit_local<T: MutVisitor>(local: &mut P<Local>, vis: &mut T) {
|
||||
let Local { id, pat, ty, kind, span, attrs, tokens } = local.deref_mut();
|
||||
let Local { id, pat, ty, kind, span, colon_sp, attrs, tokens } = local.deref_mut();
|
||||
vis.visit_id(id);
|
||||
vis.visit_pat(pat);
|
||||
visit_opt(ty, |ty| vis.visit_ty(ty));
|
||||
@ -618,6 +624,7 @@ pub fn noop_visit_local<T: MutVisitor>(local: &mut P<Local>, vis: &mut T) {
|
||||
}
|
||||
}
|
||||
vis.visit_span(span);
|
||||
visit_opt(colon_sp, |sp| vis.visit_span(sp));
|
||||
visit_attrs(attrs, vis);
|
||||
visit_lazy_tts(tokens, vis);
|
||||
}
|
||||
@ -1073,8 +1080,8 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
|
||||
}) => {
|
||||
visit_defaultness(defaultness, vis);
|
||||
vis.visit_generics(generics);
|
||||
vis.visit_span(&mut where_clauses.0.1);
|
||||
vis.visit_span(&mut where_clauses.1.1);
|
||||
vis.visit_span(&mut where_clauses.before.span);
|
||||
vis.visit_span(&mut where_clauses.after.span);
|
||||
visit_bounds(bounds, vis);
|
||||
visit_opt(ty, |ty| vis.visit_ty(ty));
|
||||
}
|
||||
@ -1157,8 +1164,8 @@ pub fn noop_flat_map_assoc_item<T: MutVisitor>(
|
||||
}) => {
|
||||
visit_defaultness(defaultness, visitor);
|
||||
visitor.visit_generics(generics);
|
||||
visitor.visit_span(&mut where_clauses.0.1);
|
||||
visitor.visit_span(&mut where_clauses.1.1);
|
||||
visitor.visit_span(&mut where_clauses.before.span);
|
||||
visitor.visit_span(&mut where_clauses.after.span);
|
||||
visit_bounds(bounds, visitor);
|
||||
visit_opt(ty, |ty| visitor.visit_ty(ty));
|
||||
}
|
||||
@ -1251,8 +1258,8 @@ pub fn noop_flat_map_foreign_item<T: MutVisitor>(
|
||||
}) => {
|
||||
visit_defaultness(defaultness, visitor);
|
||||
visitor.visit_generics(generics);
|
||||
visitor.visit_span(&mut where_clauses.0.1);
|
||||
visitor.visit_span(&mut where_clauses.1.1);
|
||||
visitor.visit_span(&mut where_clauses.before.span);
|
||||
visitor.visit_span(&mut where_clauses.after.span);
|
||||
visit_bounds(bounds, visitor);
|
||||
visit_opt(ty, |ty| visitor.visit_ty(ty));
|
||||
}
|
||||
@ -1324,6 +1331,7 @@ pub fn noop_visit_inline_asm<T: MutVisitor>(asm: &mut InlineAsm, vis: &mut T) {
|
||||
}
|
||||
InlineAsmOperand::Const { anon_const } => vis.visit_anon_const(anon_const),
|
||||
InlineAsmOperand::Sym { sym } => vis.visit_inline_asm_sym(sym),
|
||||
InlineAsmOperand::Label { block } => vis.visit_block(block),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1520,7 +1528,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
|
||||
}
|
||||
ExprKind::Try(expr) => vis.visit_expr(expr),
|
||||
ExprKind::TryBlock(body) => vis.visit_block(body),
|
||||
ExprKind::Lit(_) | ExprKind::IncludedBytes(..) | ExprKind::Err => {}
|
||||
ExprKind::Lit(_) | ExprKind::IncludedBytes(..) | ExprKind::Err(_) | ExprKind::Dummy => {}
|
||||
}
|
||||
vis.visit_id(id);
|
||||
vis.visit_span(span);
|
||||
@ -1559,7 +1567,7 @@ pub fn noop_flat_map_stmt_kind<T: MutVisitor>(
|
||||
vis: &mut T,
|
||||
) -> SmallVec<[StmtKind; 1]> {
|
||||
match kind {
|
||||
StmtKind::Local(mut local) => smallvec![StmtKind::Local({
|
||||
StmtKind::Let(mut local) => smallvec![StmtKind::Let({
|
||||
vis.visit_local(&mut local);
|
||||
local
|
||||
})],
|
||||
@ -1597,7 +1605,10 @@ pub fn noop_visit_capture_by<T: MutVisitor>(capture_by: &mut CaptureBy, vis: &mu
|
||||
}
|
||||
}
|
||||
|
||||
/// Some value for the AST node that is valid but possibly meaningless.
|
||||
/// Some value for the AST node that is valid but possibly meaningless. Similar
|
||||
/// to `Default` but not intended for wide use. The value will never be used
|
||||
/// meaningfully, it exists just to support unwinding in `visit_clobber` in the
|
||||
/// case where its closure panics.
|
||||
pub trait DummyAstNode {
|
||||
fn dummy() -> Self;
|
||||
}
|
||||
@ -1636,7 +1647,7 @@ impl DummyAstNode for Expr {
|
||||
fn dummy() -> Self {
|
||||
Expr {
|
||||
id: DUMMY_NODE_ID,
|
||||
kind: ExprKind::Err,
|
||||
kind: ExprKind::Dummy,
|
||||
span: Default::default(),
|
||||
attrs: Default::default(),
|
||||
tokens: Default::default(),
|
||||
@ -1648,7 +1659,7 @@ impl DummyAstNode for Ty {
|
||||
fn dummy() -> Self {
|
||||
Ty {
|
||||
id: DUMMY_NODE_ID,
|
||||
kind: TyKind::Err,
|
||||
kind: TyKind::Dummy,
|
||||
span: Default::default(),
|
||||
tokens: Default::default(),
|
||||
}
|
||||
@ -1672,19 +1683,6 @@ impl DummyAstNode for Stmt {
|
||||
}
|
||||
}
|
||||
|
||||
impl DummyAstNode for Block {
|
||||
fn dummy() -> Self {
|
||||
Block {
|
||||
stmts: Default::default(),
|
||||
id: DUMMY_NODE_ID,
|
||||
rules: BlockCheckMode::Default,
|
||||
span: Default::default(),
|
||||
tokens: Default::default(),
|
||||
could_be_bare_literal: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DummyAstNode for Crate {
|
||||
fn dummy() -> Self {
|
||||
Crate {
|
||||
|
||||
@ -13,7 +13,7 @@ use rustc_macros::HashStable_Generic;
|
||||
use rustc_span::symbol::{kw, sym};
|
||||
#[allow(hidden_glob_reexports)]
|
||||
use rustc_span::symbol::{Ident, Symbol};
|
||||
use rustc_span::{edition::Edition, Span, DUMMY_SP};
|
||||
use rustc_span::{edition::Edition, ErrorGuaranteed, Span, DUMMY_SP};
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
|
||||
@ -75,7 +75,7 @@ pub enum LitKind {
|
||||
ByteStrRaw(u8), // raw byte string delimited by `n` hash symbols
|
||||
CStr,
|
||||
CStrRaw(u8),
|
||||
Err,
|
||||
Err(ErrorGuaranteed),
|
||||
}
|
||||
|
||||
/// A literal token.
|
||||
@ -107,7 +107,7 @@ impl Lit {
|
||||
/// Keep this in sync with `Token::can_begin_literal_or_bool` excluding unary negation.
|
||||
pub fn from_token(token: &Token) -> Option<Lit> {
|
||||
match token.uninterpolate().kind {
|
||||
Ident(name, false) if name.is_bool_lit() => Some(Lit::new(Bool, name, None)),
|
||||
Ident(name, IdentIsRaw::No) if name.is_bool_lit() => Some(Lit::new(Bool, name, None)),
|
||||
Literal(token_lit) => Some(token_lit),
|
||||
Interpolated(ref nt)
|
||||
if let NtExpr(expr) | NtLiteral(expr) = &nt.0
|
||||
@ -144,7 +144,7 @@ impl fmt::Display for Lit {
|
||||
CStrRaw(n) => {
|
||||
write!(f, "cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize))?
|
||||
}
|
||||
Integer | Float | Bool | Err => write!(f, "{symbol}")?,
|
||||
Integer | Float | Bool | Err(_) => write!(f, "{symbol}")?,
|
||||
}
|
||||
|
||||
if let Some(suffix) = suffix {
|
||||
@ -159,7 +159,7 @@ impl LitKind {
|
||||
/// An English article for the literal token kind.
|
||||
pub fn article(self) -> &'static str {
|
||||
match self {
|
||||
Integer | Err => "an",
|
||||
Integer | Err(_) => "an",
|
||||
_ => "a",
|
||||
}
|
||||
}
|
||||
@ -174,16 +174,16 @@ impl LitKind {
|
||||
Str | StrRaw(..) => "string",
|
||||
ByteStr | ByteStrRaw(..) => "byte string",
|
||||
CStr | CStrRaw(..) => "C string",
|
||||
Err => "error",
|
||||
Err(_) => "error",
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn may_have_suffix(self) -> bool {
|
||||
matches!(self, Integer | Float | Err)
|
||||
matches!(self, Integer | Float | Err(_))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: bool) -> bool {
|
||||
pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: IdentIsRaw) -> bool {
|
||||
let ident_token = Token::new(Ident(name, is_raw), span);
|
||||
|
||||
!ident_token.is_reserved_ident()
|
||||
@ -214,7 +214,7 @@ pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: bool) -> bool {
|
||||
.contains(&name)
|
||||
}
|
||||
|
||||
fn ident_can_begin_type(name: Symbol, span: Span, is_raw: bool) -> bool {
|
||||
fn ident_can_begin_type(name: Symbol, span: Span, is_raw: IdentIsRaw) -> bool {
|
||||
let ident_token = Token::new(Ident(name, is_raw), span);
|
||||
|
||||
!ident_token.is_reserved_ident()
|
||||
@ -223,6 +223,24 @@ fn ident_can_begin_type(name: Symbol, span: Span, is_raw: bool) -> bool {
|
||||
.contains(&name)
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Encodable, Decodable, Debug, Copy, Clone, HashStable_Generic)]
|
||||
pub enum IdentIsRaw {
|
||||
No,
|
||||
Yes,
|
||||
}
|
||||
|
||||
impl From<bool> for IdentIsRaw {
|
||||
fn from(b: bool) -> Self {
|
||||
if b { Self::Yes } else { Self::No }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IdentIsRaw> for bool {
|
||||
fn from(is_raw: IdentIsRaw) -> bool {
|
||||
matches!(is_raw, IdentIsRaw::Yes)
|
||||
}
|
||||
}
|
||||
|
||||
// SAFETY: due to the `Clone` impl below, all fields of all variants other than
|
||||
// `Interpolated` must impl `Copy`.
|
||||
#[derive(PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
@ -298,7 +316,7 @@ pub enum TokenKind {
|
||||
/// Do not forget about `NtIdent` when you want to match on identifiers.
|
||||
/// It's recommended to use `Token::(ident,uninterpolate,uninterpolated_span)` to
|
||||
/// treat regular and interpolated identifiers in the same way.
|
||||
Ident(Symbol, /* is_raw */ bool),
|
||||
Ident(Symbol, IdentIsRaw),
|
||||
/// Lifetime identifier token.
|
||||
/// Do not forget about `NtLifetime` when you want to match on lifetime identifiers.
|
||||
/// It's recommended to use `Token::(lifetime,uninterpolate,uninterpolated_span)` to
|
||||
@ -411,7 +429,7 @@ impl Token {
|
||||
|
||||
/// Recovers a `Token` from an `Ident`. This creates a raw identifier if necessary.
|
||||
pub fn from_ast_ident(ident: Ident) -> Self {
|
||||
Token::new(Ident(ident.name, ident.is_raw_guess()), ident.span)
|
||||
Token::new(Ident(ident.name, ident.is_raw_guess().into()), ident.span)
|
||||
}
|
||||
|
||||
/// For interpolated tokens, returns a span of the fragment to which the interpolated
|
||||
@ -567,7 +585,7 @@ impl Token {
|
||||
pub fn can_begin_literal_maybe_minus(&self) -> bool {
|
||||
match self.uninterpolate().kind {
|
||||
Literal(..) | BinOp(Minus) => true,
|
||||
Ident(name, false) if name.is_bool_lit() => true,
|
||||
Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true,
|
||||
Interpolated(ref nt) => match &nt.0 {
|
||||
NtLiteral(_) => true,
|
||||
NtExpr(e) => match &e.kind {
|
||||
@ -602,7 +620,7 @@ impl Token {
|
||||
|
||||
/// Returns an identifier if this token is an identifier.
|
||||
#[inline]
|
||||
pub fn ident(&self) -> Option<(Ident, /* is_raw */ bool)> {
|
||||
pub fn ident(&self) -> Option<(Ident, IdentIsRaw)> {
|
||||
// We avoid using `Token::uninterpolate` here because it's slow.
|
||||
match &self.kind {
|
||||
&Ident(name, is_raw) => Some((Ident::new(name, self.span), is_raw)),
|
||||
@ -755,7 +773,7 @@ impl Token {
|
||||
/// Returns `true` if the token is a non-raw identifier for which `pred` holds.
|
||||
pub fn is_non_raw_ident_where(&self, pred: impl FnOnce(Ident) -> bool) -> bool {
|
||||
match self.ident() {
|
||||
Some((id, false)) => pred(id),
|
||||
Some((id, IdentIsRaw::No)) => pred(id),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -806,7 +824,7 @@ impl Token {
|
||||
_ => return None,
|
||||
},
|
||||
SingleQuote => match joint.kind {
|
||||
Ident(name, false) => Lifetime(Symbol::intern(&format!("'{name}"))),
|
||||
Ident(name, IdentIsRaw::No) => Lifetime(Symbol::intern(&format!("'{name}"))),
|
||||
_ => return None,
|
||||
},
|
||||
|
||||
@ -836,7 +854,7 @@ pub enum Nonterminal {
|
||||
NtPat(P<ast::Pat>),
|
||||
NtExpr(P<ast::Expr>),
|
||||
NtTy(P<ast::Ty>),
|
||||
NtIdent(Ident, /* is_raw */ bool),
|
||||
NtIdent(Ident, IdentIsRaw),
|
||||
NtLifetime(Ident),
|
||||
NtLiteral(P<ast::Expr>),
|
||||
/// Stuff inside brackets for attributes
|
||||
|
||||
@ -656,7 +656,7 @@ impl TokenStream {
|
||||
DelimSpacing::new(Spacing::JointHidden, Spacing::Alone),
|
||||
Delimiter::Bracket,
|
||||
[
|
||||
TokenTree::token_alone(token::Ident(sym::doc, false), span),
|
||||
TokenTree::token_alone(token::Ident(sym::doc, token::IdentIsRaw::No), span),
|
||||
TokenTree::token_alone(token::Eq, span),
|
||||
TokenTree::token_alone(
|
||||
TokenKind::lit(token::StrRaw(num_of_hashes), data, None),
|
||||
|
||||
@ -89,7 +89,8 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
|
||||
| Paren(_)
|
||||
| Try(_)
|
||||
| Yeet(None)
|
||||
| Err => break None,
|
||||
| Err(_)
|
||||
| Dummy => break None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
use crate::token::CommentKind;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::{BytePos, CharPos, FileName, Pos, Symbol};
|
||||
use rustc_span::{BytePos, Symbol};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
@ -131,126 +130,3 @@ pub fn beautify_doc_string(data: Symbol, kind: CommentKind) -> Symbol {
|
||||
}
|
||||
data
|
||||
}
|
||||
|
||||
/// Returns `None` if the first `col` chars of `s` contain a non-whitespace char.
|
||||
/// Otherwise returns `Some(k)` where `k` is first char offset after that leading
|
||||
/// whitespace. Note that `k` may be outside bounds of `s`.
|
||||
fn all_whitespace(s: &str, col: CharPos) -> Option<usize> {
|
||||
let mut idx = 0;
|
||||
for (i, ch) in s.char_indices().take(col.to_usize()) {
|
||||
if !ch.is_whitespace() {
|
||||
return None;
|
||||
}
|
||||
idx = i + ch.len_utf8();
|
||||
}
|
||||
Some(idx)
|
||||
}
|
||||
|
||||
fn trim_whitespace_prefix(s: &str, col: CharPos) -> &str {
|
||||
let len = s.len();
|
||||
match all_whitespace(s, col) {
|
||||
Some(col) => {
|
||||
if col < len {
|
||||
&s[col..]
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
None => s,
|
||||
}
|
||||
}
|
||||
|
||||
fn split_block_comment_into_lines(text: &str, col: CharPos) -> Vec<String> {
|
||||
let mut res: Vec<String> = vec![];
|
||||
let mut lines = text.lines();
|
||||
// just push the first line
|
||||
res.extend(lines.next().map(|it| it.to_string()));
|
||||
// for other lines, strip common whitespace prefix
|
||||
for line in lines {
|
||||
res.push(trim_whitespace_prefix(line, col).to_string())
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
// it appears this function is called only from pprust... that's
|
||||
// probably not a good thing.
|
||||
pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comment> {
|
||||
let sm = SourceMap::new(sm.path_mapping().clone());
|
||||
let source_file = sm.new_source_file(path, src);
|
||||
let text = (*source_file.src.as_ref().unwrap()).clone();
|
||||
|
||||
let text: &str = text.as_str();
|
||||
let start_bpos = source_file.start_pos;
|
||||
let mut pos = 0;
|
||||
let mut comments: Vec<Comment> = Vec::new();
|
||||
let mut code_to_the_left = false;
|
||||
|
||||
if let Some(shebang_len) = rustc_lexer::strip_shebang(text) {
|
||||
comments.push(Comment {
|
||||
style: CommentStyle::Isolated,
|
||||
lines: vec![text[..shebang_len].to_string()],
|
||||
pos: start_bpos,
|
||||
});
|
||||
pos += shebang_len;
|
||||
}
|
||||
|
||||
for token in rustc_lexer::tokenize(&text[pos..]) {
|
||||
let token_text = &text[pos..pos + token.len as usize];
|
||||
match token.kind {
|
||||
rustc_lexer::TokenKind::Whitespace => {
|
||||
if let Some(mut idx) = token_text.find('\n') {
|
||||
code_to_the_left = false;
|
||||
while let Some(next_newline) = &token_text[idx + 1..].find('\n') {
|
||||
idx += 1 + next_newline;
|
||||
comments.push(Comment {
|
||||
style: CommentStyle::BlankLine,
|
||||
lines: vec![],
|
||||
pos: start_bpos + BytePos((pos + idx) as u32),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
rustc_lexer::TokenKind::BlockComment { doc_style, .. } => {
|
||||
if doc_style.is_none() {
|
||||
let code_to_the_right = !matches!(
|
||||
text[pos + token.len as usize..].chars().next(),
|
||||
Some('\r' | '\n')
|
||||
);
|
||||
let style = match (code_to_the_left, code_to_the_right) {
|
||||
(_, true) => CommentStyle::Mixed,
|
||||
(false, false) => CommentStyle::Isolated,
|
||||
(true, false) => CommentStyle::Trailing,
|
||||
};
|
||||
|
||||
// Count the number of chars since the start of the line by rescanning.
|
||||
let pos_in_file = start_bpos + BytePos(pos as u32);
|
||||
let line_begin_in_file = source_file.line_begin_pos(pos_in_file);
|
||||
let line_begin_pos = (line_begin_in_file - start_bpos).to_usize();
|
||||
let col = CharPos(text[line_begin_pos..pos].chars().count());
|
||||
|
||||
let lines = split_block_comment_into_lines(token_text, col);
|
||||
comments.push(Comment { style, lines, pos: pos_in_file })
|
||||
}
|
||||
}
|
||||
rustc_lexer::TokenKind::LineComment { doc_style } => {
|
||||
if doc_style.is_none() {
|
||||
comments.push(Comment {
|
||||
style: if code_to_the_left {
|
||||
CommentStyle::Trailing
|
||||
} else {
|
||||
CommentStyle::Isolated
|
||||
},
|
||||
lines: vec![token_text.to_string()],
|
||||
pos: start_bpos + BytePos(pos as u32),
|
||||
})
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
code_to_the_left = true;
|
||||
}
|
||||
}
|
||||
pos += token.len as usize;
|
||||
}
|
||||
|
||||
comments
|
||||
}
|
||||
|
||||
@ -31,20 +31,21 @@ pub fn escape_byte_str_symbol(bytes: &[u8]) -> Symbol {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum LitError {
|
||||
LexerError,
|
||||
InvalidSuffix,
|
||||
InvalidIntSuffix,
|
||||
InvalidFloatSuffix,
|
||||
NonDecimalFloat(u32),
|
||||
IntTooLarge(u32),
|
||||
InvalidSuffix(Symbol),
|
||||
InvalidIntSuffix(Symbol),
|
||||
InvalidFloatSuffix(Symbol),
|
||||
NonDecimalFloat(u32), // u32 is the base
|
||||
IntTooLarge(u32), // u32 is the base
|
||||
}
|
||||
|
||||
impl LitKind {
|
||||
/// Converts literal token into a semantic literal.
|
||||
pub fn from_token_lit(lit: token::Lit) -> Result<LitKind, LitError> {
|
||||
let token::Lit { kind, symbol, suffix } = lit;
|
||||
if suffix.is_some() && !kind.may_have_suffix() {
|
||||
return Err(LitError::InvalidSuffix);
|
||||
if let Some(suffix) = suffix
|
||||
&& !kind.may_have_suffix()
|
||||
{
|
||||
return Err(LitError::InvalidSuffix(suffix));
|
||||
}
|
||||
|
||||
// For byte/char/string literals, chars and escapes have already been
|
||||
@ -145,7 +146,7 @@ impl LitKind {
|
||||
buf.push(0);
|
||||
LitKind::CStr(buf.into(), StrStyle::Raw(n))
|
||||
}
|
||||
token::Err => LitKind::Err,
|
||||
token::Err(guar) => LitKind::Err(guar),
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -202,7 +203,7 @@ impl fmt::Display for LitKind {
|
||||
}
|
||||
}
|
||||
LitKind::Bool(b) => write!(f, "{}", if b { "true" } else { "false" })?,
|
||||
LitKind::Err => {
|
||||
LitKind::Err(_) => {
|
||||
// This only shows up in places like `-Zunpretty=hir` output, so we
|
||||
// don't bother to produce something useful.
|
||||
write!(f, "<bad-literal>")?;
|
||||
@ -238,7 +239,7 @@ impl MetaItemLit {
|
||||
LitKind::Char(_) => token::Char,
|
||||
LitKind::Int(..) => token::Integer,
|
||||
LitKind::Float(..) => token::Float,
|
||||
LitKind::Err => token::Err,
|
||||
LitKind::Err(guar) => token::Err(guar),
|
||||
};
|
||||
|
||||
token::Lit::new(kind, self.symbol, self.suffix)
|
||||
@ -272,12 +273,14 @@ fn filtered_float_lit(
|
||||
return Err(LitError::NonDecimalFloat(base));
|
||||
}
|
||||
Ok(match suffix {
|
||||
Some(suf) => LitKind::Float(
|
||||
Some(suffix) => LitKind::Float(
|
||||
symbol,
|
||||
ast::LitFloatType::Suffixed(match suf {
|
||||
ast::LitFloatType::Suffixed(match suffix {
|
||||
sym::f16 => ast::FloatTy::F16,
|
||||
sym::f32 => ast::FloatTy::F32,
|
||||
sym::f64 => ast::FloatTy::F64,
|
||||
_ => return Err(LitError::InvalidFloatSuffix),
|
||||
sym::f128 => ast::FloatTy::F128,
|
||||
_ => return Err(LitError::InvalidFloatSuffix(suffix)),
|
||||
}),
|
||||
),
|
||||
None => LitKind::Float(symbol, ast::LitFloatType::Unsuffixed),
|
||||
@ -318,17 +321,13 @@ fn integer_lit(symbol: Symbol, suffix: Option<Symbol>) -> Result<LitKind, LitErr
|
||||
// `1f64` and `2f32` etc. are valid float literals, and
|
||||
// `fxxx` looks more like an invalid float literal than invalid integer literal.
|
||||
_ if suf.as_str().starts_with('f') => return filtered_float_lit(symbol, suffix, base),
|
||||
_ => return Err(LitError::InvalidIntSuffix),
|
||||
_ => return Err(LitError::InvalidIntSuffix(suf)),
|
||||
},
|
||||
_ => ast::LitIntType::Unsuffixed,
|
||||
};
|
||||
|
||||
let s = &s[if base != 10 { 2 } else { 0 }..];
|
||||
u128::from_str_radix(s, base).map(|i| LitKind::Int(i.into(), ty)).map_err(|_| {
|
||||
// Small bases are lexed as if they were base 10, e.g, the string
|
||||
// might be `0b10201`. This will cause the conversion above to fail,
|
||||
// but these kinds of errors are already reported by the lexer.
|
||||
let from_lexer = base < 10 && s.chars().any(|c| c.to_digit(10).is_some_and(|d| d >= base));
|
||||
if from_lexer { LitError::LexerError } else { LitError::IntTooLarge(base) }
|
||||
})
|
||||
u128::from_str_radix(s, base)
|
||||
.map(|i| LitKind::Int(i.into(), ty))
|
||||
.map_err(|_| LitError::IntTooLarge(base))
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
22
compiler/rustc_ast_ir/Cargo.toml
Normal file
22
compiler/rustc_ast_ir/Cargo.toml
Normal file
@ -0,0 +1,22 @@
|
||||
[package]
|
||||
name = "rustc_ast_ir"
|
||||
version = "0.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
rustc_data_structures = { path = "../rustc_data_structures", optional = true }
|
||||
rustc_macros = { path = "../rustc_macros", optional = true }
|
||||
rustc_serialize = { path = "../rustc_serialize", optional = true }
|
||||
rustc_span = { path = "../rustc_span", optional = true }
|
||||
smallvec = { version = "1.8.1" }
|
||||
# tidy-alphabetical-end
|
||||
|
||||
[features]
|
||||
default = ["nightly"]
|
||||
nightly = [
|
||||
"rustc_serialize",
|
||||
"rustc_data_structures",
|
||||
"rustc_macros",
|
||||
"rustc_span",
|
||||
]
|
||||
71
compiler/rustc_ast_ir/src/lib.rs
Normal file
71
compiler/rustc_ast_ir/src/lib.rs
Normal file
@ -0,0 +1,71 @@
|
||||
#![cfg_attr(feature = "nightly", feature(never_type))]
|
||||
#![cfg_attr(feature = "nightly", feature(rustc_attrs))]
|
||||
#![cfg_attr(feature = "nightly", allow(internal_features))]
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
#[macro_use]
|
||||
extern crate rustc_macros;
|
||||
|
||||
pub mod visit;
|
||||
|
||||
/// The movability of a coroutine / closure literal:
|
||||
/// whether a coroutine contains self-references, causing it to be `!Unpin`.
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)]
|
||||
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))]
|
||||
pub enum Movability {
|
||||
/// May contain self-references, `!Unpin`.
|
||||
Static,
|
||||
/// Must not contain self-references, `Unpin`.
|
||||
Movable,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)]
|
||||
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))]
|
||||
pub enum Mutability {
|
||||
// N.B. Order is deliberate, so that Not < Mut
|
||||
Not,
|
||||
Mut,
|
||||
}
|
||||
|
||||
impl Mutability {
|
||||
pub fn invert(self) -> Self {
|
||||
match self {
|
||||
Mutability::Mut => Mutability::Not,
|
||||
Mutability::Not => Mutability::Mut,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `""` (empty string) or `"mut "` depending on the mutability.
|
||||
pub fn prefix_str(self) -> &'static str {
|
||||
match self {
|
||||
Mutability::Mut => "mut ",
|
||||
Mutability::Not => "",
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `"&"` or `"&mut "` depending on the mutability.
|
||||
pub fn ref_prefix_str(self) -> &'static str {
|
||||
match self {
|
||||
Mutability::Not => "&",
|
||||
Mutability::Mut => "&mut ",
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `""` (empty string) or `"mutably "` depending on the mutability.
|
||||
pub fn mutably_str(self) -> &'static str {
|
||||
match self {
|
||||
Mutability::Not => "",
|
||||
Mutability::Mut => "mutably ",
|
||||
}
|
||||
}
|
||||
|
||||
/// Return `true` if self is mutable
|
||||
pub fn is_mut(self) -> bool {
|
||||
matches!(self, Self::Mut)
|
||||
}
|
||||
|
||||
/// Return `true` if self is **not** mutable
|
||||
pub fn is_not(self) -> bool {
|
||||
matches!(self, Self::Not)
|
||||
}
|
||||
}
|
||||
82
compiler/rustc_ast_ir/src/visit.rs
Normal file
82
compiler/rustc_ast_ir/src/visit.rs
Normal file
@ -0,0 +1,82 @@
|
||||
use core::ops::ControlFlow;
|
||||
|
||||
/// Similar to the `Try` trait, but also implemented for `()`.
|
||||
pub trait VisitorResult {
|
||||
type Residual;
|
||||
fn output() -> Self;
|
||||
fn from_residual(residual: Self::Residual) -> Self;
|
||||
fn from_branch(b: ControlFlow<Self::Residual>) -> Self;
|
||||
fn branch(self) -> ControlFlow<Self::Residual>;
|
||||
}
|
||||
|
||||
impl VisitorResult for () {
|
||||
#[cfg(feature = "nightly")]
|
||||
type Residual = !;
|
||||
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
type Residual = core::convert::Infallible;
|
||||
|
||||
fn output() -> Self {}
|
||||
fn from_residual(_: Self::Residual) -> Self {}
|
||||
fn from_branch(_: ControlFlow<Self::Residual>) -> Self {}
|
||||
fn branch(self) -> ControlFlow<Self::Residual> {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> VisitorResult for ControlFlow<T> {
|
||||
type Residual = T;
|
||||
|
||||
fn output() -> Self {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
fn from_residual(residual: Self::Residual) -> Self {
|
||||
ControlFlow::Break(residual)
|
||||
}
|
||||
fn from_branch(b: Self) -> Self {
|
||||
b
|
||||
}
|
||||
fn branch(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! try_visit {
|
||||
($e:expr) => {
|
||||
match $crate::visit::VisitorResult::branch($e) {
|
||||
core::ops::ControlFlow::Continue(()) => (),
|
||||
#[allow(unreachable_code)]
|
||||
core::ops::ControlFlow::Break(r) => {
|
||||
return $crate::visit::VisitorResult::from_residual(r);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! visit_opt {
|
||||
($visitor: expr, $method: ident, $opt: expr $(, $($extra_args: expr),* )?) => {
|
||||
if let Some(x) = $opt {
|
||||
$crate::try_visit!($visitor.$method(x $(, $($extra_args,)* )?));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! walk_list {
|
||||
($visitor: expr, $method: ident, $list: expr $(, $($extra_args: expr),* )?) => {
|
||||
for elem in $list {
|
||||
$crate::try_visit!($visitor.$method(elem $(, $($extra_args,)* )?));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! walk_visitable_list {
|
||||
($visitor: expr, $list: expr $(, $($extra_args: expr),* )?) => {
|
||||
for elem in $list {
|
||||
$crate::try_visit!(elem.visit_with($visitor $(, $($extra_args,)* )?));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8,9 +8,19 @@ ast_lowering_arbitrary_expression_in_pattern =
|
||||
|
||||
ast_lowering_argument = argument
|
||||
|
||||
ast_lowering_assoc_ty_binding_in_dyn =
|
||||
associated type bounds are not allowed in `dyn` types
|
||||
.suggestion = use `impl Trait` to introduce a type instead
|
||||
|
||||
ast_lowering_assoc_ty_parentheses =
|
||||
parenthesized generic arguments cannot be used in associated type constraints
|
||||
|
||||
ast_lowering_async_bound_not_on_trait =
|
||||
`async` bound modifier only allowed on trait, not `{$descr}`
|
||||
|
||||
ast_lowering_async_bound_only_for_fn_traits =
|
||||
`async` bound modifier only allowed on `Fn`/`FnMut`/`FnOnce` traits
|
||||
|
||||
ast_lowering_async_coroutines_not_supported =
|
||||
`async` coroutines are not yet supported
|
||||
|
||||
@ -78,6 +88,9 @@ ast_lowering_invalid_abi_suggestion = did you mean
|
||||
ast_lowering_invalid_asm_template_modifier_const =
|
||||
asm template modifiers are not allowed for `const` arguments
|
||||
|
||||
ast_lowering_invalid_asm_template_modifier_label =
|
||||
asm template modifiers are not allowed for `label` arguments
|
||||
|
||||
ast_lowering_invalid_asm_template_modifier_reg_class =
|
||||
invalid asm template modifier for this register class
|
||||
|
||||
@ -94,9 +107,6 @@ ast_lowering_match_arm_with_no_body =
|
||||
`match` arm with no body
|
||||
.suggestion = add a body after the pattern
|
||||
|
||||
ast_lowering_misplaced_assoc_ty_binding =
|
||||
associated type bounds are only allowed in where clauses and function signatures, not in {$position}
|
||||
|
||||
ast_lowering_misplaced_double_dot =
|
||||
`..` patterns are not allowed here
|
||||
.note = only allowed in tuple, tuple struct, and slice patterns
|
||||
@ -117,9 +127,6 @@ ast_lowering_never_pattern_with_guard =
|
||||
a guard on a never pattern will never be run
|
||||
.suggestion = remove this guard
|
||||
|
||||
ast_lowering_not_supported_for_lifetime_binder_async_closure =
|
||||
`for<...>` binders on `async` closures are not currently supported
|
||||
|
||||
ast_lowering_previously_used_here = previously used here
|
||||
|
||||
ast_lowering_register1 = register `{$reg1_name}`
|
||||
|
||||
@ -3,9 +3,9 @@ use crate::{ImplTraitContext, ImplTraitPosition, ParamMode, ResolverAstLoweringE
|
||||
use super::errors::{
|
||||
AbiSpecifiedMultipleTimes, AttSyntaxOnlyX86, ClobberAbiNotSupported,
|
||||
InlineAsmUnsupportedTarget, InvalidAbiClobberAbi, InvalidAsmTemplateModifierConst,
|
||||
InvalidAsmTemplateModifierRegClass, InvalidAsmTemplateModifierRegClassSub,
|
||||
InvalidAsmTemplateModifierSym, InvalidRegister, InvalidRegisterClass, RegisterClassOnlyClobber,
|
||||
RegisterConflict,
|
||||
InvalidAsmTemplateModifierLabel, InvalidAsmTemplateModifierRegClass,
|
||||
InvalidAsmTemplateModifierRegClassSub, InvalidAsmTemplateModifierSym, InvalidRegister,
|
||||
InvalidRegisterClass, RegisterClassOnlyClobber, RegisterConflict,
|
||||
};
|
||||
use super::LoweringContext;
|
||||
|
||||
@ -22,6 +22,7 @@ use std::collections::hash_map::Entry;
|
||||
use std::fmt::Write;
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
pub(crate) fn lower_inline_asm(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
@ -195,7 +196,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
.get_partial_res(sym.id)
|
||||
.and_then(|res| res.full_res())
|
||||
.and_then(|res| match res {
|
||||
Res::Def(DefKind::Static(_), def_id) => Some(def_id),
|
||||
Res::Def(DefKind::Static { .. }, def_id) => Some(def_id),
|
||||
_ => None,
|
||||
});
|
||||
|
||||
@ -205,7 +206,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
&sym.qself,
|
||||
&sym.path,
|
||||
ParamMode::Optional,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
hir::InlineAsmOperand::SymStatic { path, def_id }
|
||||
@ -236,6 +237,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}
|
||||
}
|
||||
}
|
||||
InlineAsmOperand::Label { block } => {
|
||||
if !self.tcx.features().asm_goto {
|
||||
feature_err(
|
||||
sess,
|
||||
sym::asm_goto,
|
||||
*op_sp,
|
||||
"label operands for inline assembly are unstable",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
hir::InlineAsmOperand::Label { block: self.lower_block(block, false) }
|
||||
}
|
||||
};
|
||||
(op, self.lower_span(*op_sp))
|
||||
})
|
||||
@ -295,6 +308,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
op_span: op_sp,
|
||||
});
|
||||
}
|
||||
hir::InlineAsmOperand::Label { .. } => {
|
||||
self.dcx().emit_err(InvalidAsmTemplateModifierLabel {
|
||||
placeholder_span,
|
||||
op_span: op_sp,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -334,7 +353,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
|
||||
hir::InlineAsmOperand::Const { .. }
|
||||
| hir::InlineAsmOperand::SymFn { .. }
|
||||
| hir::InlineAsmOperand::SymStatic { .. } => {
|
||||
| hir::InlineAsmOperand::SymStatic { .. }
|
||||
| hir::InlineAsmOperand::Label { .. } => {
|
||||
unreachable!("{op:?} is not a register operand");
|
||||
}
|
||||
};
|
||||
|
||||
@ -32,11 +32,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
let mut expr = None;
|
||||
while let [s, tail @ ..] = ast_stmts {
|
||||
match &s.kind {
|
||||
StmtKind::Local(local) => {
|
||||
StmtKind::Let(local) => {
|
||||
let hir_id = self.lower_node_id(s.id);
|
||||
let local = self.lower_local(local);
|
||||
self.alias_attrs(hir_id, local.hir_id);
|
||||
let kind = hir::StmtKind::Local(local);
|
||||
let kind = hir::StmtKind::Let(local);
|
||||
let span = self.lower_span(s.span);
|
||||
stmts.push(hir::Stmt { hir_id, kind, span });
|
||||
}
|
||||
@ -85,7 +85,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
let ty = l
|
||||
.ty
|
||||
.as_ref()
|
||||
.map(|t| self.lower_ty(t, &ImplTraitContext::Disallowed(ImplTraitPosition::Variable)));
|
||||
.map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Variable)));
|
||||
let init = l.kind.init().map(|init| self.lower_expr(init));
|
||||
let hir_id = self.lower_node_id(l.id);
|
||||
let pat = self.lower_pat(&l.pat);
|
||||
|
||||
@ -103,12 +103,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
span: Span,
|
||||
) -> Result<DefId, ErrorGuaranteed> {
|
||||
let sig_id = if self.is_in_trait_impl { item_id } else { path_id };
|
||||
let sig_id = self
|
||||
.resolver
|
||||
.get_partial_res(sig_id)
|
||||
.map(|r| r.expect_full_res().opt_def_id())
|
||||
.unwrap_or(None);
|
||||
|
||||
let sig_id =
|
||||
self.resolver.get_partial_res(sig_id).and_then(|r| r.expect_full_res().opt_def_id());
|
||||
sig_id.ok_or_else(|| {
|
||||
self.tcx
|
||||
.dcx()
|
||||
@ -138,7 +134,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
} else {
|
||||
self.tcx.fn_arg_names(sig_id).len()
|
||||
};
|
||||
let inputs = self.arena.alloc_from_iter((0..args_count).into_iter().map(|arg| hir::Ty {
|
||||
let inputs = self.arena.alloc_from_iter((0..args_count).map(|arg| hir::Ty {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Input(arg)),
|
||||
span: self.lower_span(param_span),
|
||||
@ -218,7 +214,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
&delegation.qself,
|
||||
&delegation.path,
|
||||
ParamMode::Optional,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
let block = delegation.body.as_deref();
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
use rustc_errors::{codes::*, DiagnosticArgFromDisplay};
|
||||
use rustc_errors::{
|
||||
codes::*, Diag, DiagArgFromDisplay, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic,
|
||||
};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_span::{symbol::Ident, Span, Symbol};
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_generic_type_with_parentheses, code = E0214)]
|
||||
pub struct GenericTypeWithParentheses {
|
||||
#[primary_span]
|
||||
@ -12,7 +14,7 @@ pub struct GenericTypeWithParentheses {
|
||||
pub sub: Option<UseAngleBrackets>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Subdiagnostic)]
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(ast_lowering_use_angle_brackets, applicability = "maybe-incorrect")]
|
||||
pub struct UseAngleBrackets {
|
||||
#[suggestion_part(code = "<")]
|
||||
@ -38,14 +40,12 @@ pub struct InvalidAbi {
|
||||
|
||||
pub struct InvalidAbiReason(pub &'static str);
|
||||
|
||||
impl rustc_errors::AddToDiagnostic for InvalidAbiReason {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(
|
||||
&mut rustc_errors::Diagnostic,
|
||||
rustc_errors::SubdiagnosticMessage,
|
||||
) -> rustc_errors::SubdiagnosticMessage,
|
||||
{
|
||||
impl Subdiagnostic for InvalidAbiReason {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_: F,
|
||||
) {
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
diag.note(self.0);
|
||||
}
|
||||
@ -63,7 +63,7 @@ pub struct InvalidAbiSuggestion {
|
||||
pub suggestion: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_assoc_ty_parentheses)]
|
||||
pub struct AssocTyParentheses {
|
||||
#[primary_span]
|
||||
@ -72,7 +72,7 @@ pub struct AssocTyParentheses {
|
||||
pub sub: AssocTyParenthesesSub,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Subdiagnostic)]
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum AssocTyParenthesesSub {
|
||||
#[multipart_suggestion(ast_lowering_remove_parentheses)]
|
||||
Empty {
|
||||
@ -94,18 +94,19 @@ pub enum AssocTyParenthesesSub {
|
||||
pub struct MisplacedImplTrait<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub position: DiagnosticArgFromDisplay<'a>,
|
||||
pub position: DiagArgFromDisplay<'a>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_misplaced_assoc_ty_binding)]
|
||||
pub struct MisplacedAssocTyBinding<'a> {
|
||||
#[diag(ast_lowering_assoc_ty_binding_in_dyn)]
|
||||
pub struct MisplacedAssocTyBinding {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub position: DiagnosticArgFromDisplay<'a>,
|
||||
#[suggestion(code = " = impl", applicability = "maybe-incorrect", style = "verbose")]
|
||||
pub suggestion: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_underscore_expr_lhs_assign)]
|
||||
pub struct UnderscoreExprLhsAssign {
|
||||
#[primary_span]
|
||||
@ -113,7 +114,7 @@ pub struct UnderscoreExprLhsAssign {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_base_expression_double_dot, code = E0797)]
|
||||
pub struct BaseExpressionDoubleDot {
|
||||
#[primary_span]
|
||||
@ -121,7 +122,7 @@ pub struct BaseExpressionDoubleDot {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_await_only_in_async_fn_and_blocks, code = E0728)]
|
||||
pub struct AwaitOnlyInAsyncFnAndBlocks {
|
||||
#[primary_span]
|
||||
@ -131,21 +132,21 @@ pub struct AwaitOnlyInAsyncFnAndBlocks {
|
||||
pub item_span: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_coroutine_too_many_parameters, code = E0628)]
|
||||
pub struct CoroutineTooManyParameters {
|
||||
#[primary_span]
|
||||
pub fn_decl_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_closure_cannot_be_static, code = E0697)]
|
||||
pub struct ClosureCannotBeStatic {
|
||||
#[primary_span]
|
||||
pub fn_decl_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_functional_record_update_destructuring_assignment)]
|
||||
pub struct FunctionalRecordUpdateDestructuringAssignment {
|
||||
#[primary_span]
|
||||
@ -153,28 +154,28 @@ pub struct FunctionalRecordUpdateDestructuringAssignment {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_async_coroutines_not_supported, code = E0727)]
|
||||
pub struct AsyncCoroutinesNotSupported {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_inline_asm_unsupported_target, code = E0472)]
|
||||
pub struct InlineAsmUnsupportedTarget {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_att_syntax_only_x86)]
|
||||
pub struct AttSyntaxOnlyX86 {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_abi_specified_multiple_times)]
|
||||
pub struct AbiSpecifiedMultipleTimes {
|
||||
#[primary_span]
|
||||
@ -186,7 +187,7 @@ pub struct AbiSpecifiedMultipleTimes {
|
||||
pub equivalent: Option<()>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_clobber_abi_not_supported)]
|
||||
pub struct ClobberAbiNotSupported {
|
||||
#[primary_span]
|
||||
@ -202,7 +203,7 @@ pub struct InvalidAbiClobberAbi {
|
||||
pub supported_abis: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_invalid_register)]
|
||||
pub struct InvalidRegister<'a> {
|
||||
#[primary_span]
|
||||
@ -211,7 +212,7 @@ pub struct InvalidRegister<'a> {
|
||||
pub error: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_invalid_register_class)]
|
||||
pub struct InvalidRegisterClass<'a> {
|
||||
#[primary_span]
|
||||
@ -240,7 +241,7 @@ pub enum InvalidAsmTemplateModifierRegClassSub {
|
||||
DoesNotSupportModifier { class_name: Symbol },
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_invalid_asm_template_modifier_const)]
|
||||
pub struct InvalidAsmTemplateModifierConst {
|
||||
#[primary_span]
|
||||
@ -250,7 +251,7 @@ pub struct InvalidAsmTemplateModifierConst {
|
||||
pub op_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_invalid_asm_template_modifier_sym)]
|
||||
pub struct InvalidAsmTemplateModifierSym {
|
||||
#[primary_span]
|
||||
@ -260,7 +261,17 @@ pub struct InvalidAsmTemplateModifierSym {
|
||||
pub op_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_invalid_asm_template_modifier_label)]
|
||||
pub struct InvalidAsmTemplateModifierLabel {
|
||||
#[primary_span]
|
||||
#[label(ast_lowering_template_modifier)]
|
||||
pub placeholder_span: Span,
|
||||
#[label(ast_lowering_argument)]
|
||||
pub op_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_register_class_only_clobber)]
|
||||
pub struct RegisterClassOnlyClobber {
|
||||
#[primary_span]
|
||||
@ -268,7 +279,7 @@ pub struct RegisterClassOnlyClobber {
|
||||
pub reg_class_name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_register_conflict)]
|
||||
pub struct RegisterConflict<'a> {
|
||||
#[primary_span]
|
||||
@ -282,7 +293,7 @@ pub struct RegisterConflict<'a> {
|
||||
pub in_out: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[derive(Diagnostic)]
|
||||
#[help]
|
||||
#[diag(ast_lowering_sub_tuple_binding)]
|
||||
pub struct SubTupleBinding<'a> {
|
||||
@ -300,7 +311,7 @@ pub struct SubTupleBinding<'a> {
|
||||
pub ctx: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_extra_double_dot)]
|
||||
pub struct ExtraDoubleDot<'a> {
|
||||
#[primary_span]
|
||||
@ -311,7 +322,7 @@ pub struct ExtraDoubleDot<'a> {
|
||||
pub ctx: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[derive(Diagnostic)]
|
||||
#[note]
|
||||
#[diag(ast_lowering_misplaced_double_dot)]
|
||||
pub struct MisplacedDoubleDot {
|
||||
@ -319,20 +330,13 @@ pub struct MisplacedDoubleDot {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_misplaced_relax_trait_bound)]
|
||||
pub struct MisplacedRelaxTraitBound {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering_not_supported_for_lifetime_binder_async_closure)]
|
||||
pub struct NotSupportedForLifetimeBinderAsyncClosure {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_match_arm_with_no_body)]
|
||||
pub struct MatchArmWithNoBody {
|
||||
@ -359,14 +363,14 @@ pub struct NeverPatternWithGuard {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_arbitrary_expression_in_pattern)]
|
||||
pub struct ArbitraryExpressionInPattern {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_inclusive_range_with_no_end)]
|
||||
pub struct InclusiveRangeWithNoEnd {
|
||||
#[primary_span]
|
||||
@ -395,3 +399,18 @@ pub(crate) struct GenericParamDefaultInBinder {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_async_bound_not_on_trait)]
|
||||
pub(crate) struct AsyncBoundNotOnTrait {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub descr: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_async_bound_only_for_fn_traits)]
|
||||
pub(crate) struct AsyncBoundOnlyForFnTraits {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
use std::assert_matches::assert_matches;
|
||||
|
||||
use super::errors::{
|
||||
AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot,
|
||||
ClosureCannotBeStatic, CoroutineTooManyParameters,
|
||||
FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody,
|
||||
NeverPatternWithBody, NeverPatternWithGuard, NotSupportedForLifetimeBinderAsyncClosure,
|
||||
UnderscoreExprLhsAssign,
|
||||
NeverPatternWithBody, NeverPatternWithGuard, UnderscoreExprLhsAssign,
|
||||
};
|
||||
use super::ResolverAstLoweringExt;
|
||||
use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs};
|
||||
@ -13,6 +14,7 @@ use rustc_ast::*;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_session::errors::report_lit_error;
|
||||
use rustc_span::source_map::{respan, Spanned};
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
@ -98,7 +100,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
seg,
|
||||
ParamMode::Optional,
|
||||
ParenthesizedGenericArgs::Err,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
// Method calls can't have bound modifiers
|
||||
None,
|
||||
));
|
||||
let receiver = self.lower_expr(receiver);
|
||||
@ -121,8 +125,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let lit_kind = match LitKind::from_token_lit(*token_lit) {
|
||||
Ok(lit_kind) => lit_kind,
|
||||
Err(err) => {
|
||||
report_lit_error(&self.tcx.sess.parse_sess, err, *token_lit, e.span);
|
||||
LitKind::Err
|
||||
let guar =
|
||||
report_lit_error(&self.tcx.sess.psess, err, *token_lit, e.span);
|
||||
LitKind::Err(guar)
|
||||
}
|
||||
};
|
||||
let lit = self.arena.alloc(respan(self.lower_span(e.span), lit_kind));
|
||||
@ -138,13 +143,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
ExprKind::Cast(expr, ty) => {
|
||||
let expr = self.lower_expr(expr);
|
||||
let ty =
|
||||
self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Cast));
|
||||
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast));
|
||||
hir::ExprKind::Cast(expr, ty)
|
||||
}
|
||||
ExprKind::Type(expr, ty) => {
|
||||
let expr = self.lower_expr(expr);
|
||||
let ty =
|
||||
self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Cast));
|
||||
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast));
|
||||
hir::ExprKind::Type(expr, ty)
|
||||
}
|
||||
ExprKind::AddrOf(k, m, ohs) => {
|
||||
@ -264,7 +269,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
hir::ExprKind::Path(qpath)
|
||||
@ -292,7 +297,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
ExprKind::OffsetOf(container, fields) => hir::ExprKind::OffsetOf(
|
||||
self.lower_ty(
|
||||
container,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::OffsetOf),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::OffsetOf),
|
||||
),
|
||||
self.arena.alloc_from_iter(fields.iter().map(|&ident| self.lower_ident(ident))),
|
||||
),
|
||||
@ -311,7 +316,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
&se.qself,
|
||||
&se.path,
|
||||
ParamMode::Optional,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
)),
|
||||
self.arena
|
||||
@ -320,9 +325,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
)
|
||||
}
|
||||
ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
|
||||
ExprKind::Err => {
|
||||
hir::ExprKind::Err(self.dcx().span_delayed_bug(e.span, "lowered ExprKind::Err"))
|
||||
ExprKind::Err(guar) => hir::ExprKind::Err(*guar),
|
||||
|
||||
ExprKind::Dummy => {
|
||||
span_bug!(e.span, "lowered ExprKind::Dummy")
|
||||
}
|
||||
|
||||
ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr),
|
||||
|
||||
ExprKind::Paren(_) | ExprKind::ForLoop { .. } => {
|
||||
@ -709,7 +717,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
sym::track_caller,
|
||||
span,
|
||||
)))),
|
||||
id: self.tcx.sess.parse_sess.attr_id_generator.mk_attr_id(),
|
||||
id: self.tcx.sess.psess.attr_id_generator.mk_attr_id(),
|
||||
style: AttrStyle::Outer,
|
||||
span: unstable_span,
|
||||
}],
|
||||
@ -752,10 +760,28 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
Some(hir::CoroutineKind::Coroutine(_))
|
||||
| Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _))
|
||||
| None => {
|
||||
return hir::ExprKind::Err(self.dcx().emit_err(AwaitOnlyInAsyncFnAndBlocks {
|
||||
await_kw_span,
|
||||
item_span: self.current_item,
|
||||
}));
|
||||
// Lower to a block `{ EXPR; <error> }` so that the awaited expr
|
||||
// is not accidentally orphaned.
|
||||
let stmt_id = self.next_id();
|
||||
let expr_err = self.expr(
|
||||
expr.span,
|
||||
hir::ExprKind::Err(self.dcx().emit_err(AwaitOnlyInAsyncFnAndBlocks {
|
||||
await_kw_span,
|
||||
item_span: self.current_item,
|
||||
})),
|
||||
);
|
||||
return hir::ExprKind::Block(
|
||||
self.block_all(
|
||||
expr.span,
|
||||
arena_vec![self; hir::Stmt {
|
||||
hir_id: stmt_id,
|
||||
kind: hir::StmtKind::Semi(expr),
|
||||
span: expr.span,
|
||||
}],
|
||||
Some(self.arena.alloc(expr_err)),
|
||||
),
|
||||
None,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1026,30 +1052,27 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
fn_decl_span: Span,
|
||||
fn_arg_span: Span,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
if let &ClosureBinder::For { span, .. } = binder {
|
||||
self.dcx().emit_err(NotSupportedForLifetimeBinderAsyncClosure { span });
|
||||
}
|
||||
|
||||
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
|
||||
|
||||
assert_matches!(
|
||||
coroutine_kind,
|
||||
CoroutineKind::Async { .. },
|
||||
"only async closures are supported currently"
|
||||
);
|
||||
|
||||
let body = self.with_new_scopes(fn_decl_span, |this| {
|
||||
let inner_decl =
|
||||
FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
|
||||
|
||||
// Transform `async |x: u8| -> X { ... }` into
|
||||
// `|x: u8| || -> X { ... }`.
|
||||
let body_id = this.lower_body(|this| {
|
||||
let async_ret_ty = if let FnRetTy::Ty(ty) = &decl.output {
|
||||
let itctx = ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock);
|
||||
Some(hir::FnRetTy::Return(this.lower_ty(ty, &itctx)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(
|
||||
decl,
|
||||
&inner_decl,
|
||||
|this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)),
|
||||
body.span,
|
||||
coroutine_kind,
|
||||
hir::CoroutineSource::Closure,
|
||||
async_ret_ty,
|
||||
);
|
||||
|
||||
let hir_id = this.lower_node_id(coroutine_kind.closure_id());
|
||||
@ -1060,15 +1083,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
body_id
|
||||
});
|
||||
|
||||
let outer_decl =
|
||||
FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
|
||||
|
||||
let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
|
||||
// We need to lower the declaration outside the new scope, because we
|
||||
// have to conserve the state of being inside a loop condition for the
|
||||
// closure argument types.
|
||||
let fn_decl =
|
||||
self.lower_fn_decl(&outer_decl, closure_id, fn_decl_span, FnDeclKind::Closure, None);
|
||||
self.lower_fn_decl(&decl, closure_id, fn_decl_span, FnDeclKind::Closure, None);
|
||||
|
||||
let c = self.arena.alloc(hir::Closure {
|
||||
def_id: self.local_def_id(closure_id),
|
||||
@ -1079,7 +1099,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
body,
|
||||
fn_decl_span: self.lower_span(fn_decl_span),
|
||||
fn_arg_span: Some(self.lower_span(fn_arg_span)),
|
||||
kind: hir::ClosureKind::Closure,
|
||||
// Lower this as a `CoroutineClosure`. That will ensure that HIR typeck
|
||||
// knows that a `FnDecl` output type like `-> &str` actually means
|
||||
// "coroutine that returns &str", rather than directly returning a `&str`.
|
||||
kind: hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async),
|
||||
constness: hir::Constness::NotConst,
|
||||
});
|
||||
hir::ExprKind::Closure(c)
|
||||
@ -1241,7 +1264,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
// Destructure like a tuple struct.
|
||||
@ -1261,7 +1284,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
// Destructure like a unit struct.
|
||||
@ -1286,7 +1309,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
&se.qself,
|
||||
&se.path,
|
||||
ParamMode::Optional,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
let fields_omitted = match &se.rest {
|
||||
@ -1490,13 +1513,33 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
fn lower_expr_yield(&mut self, span: Span, opt_expr: Option<&Expr>) -> hir::ExprKind<'hir> {
|
||||
let yielded =
|
||||
opt_expr.as_ref().map(|x| self.lower_expr(x)).unwrap_or_else(|| self.expr_unit(span));
|
||||
|
||||
let is_async_gen = match self.coroutine_kind {
|
||||
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) => false,
|
||||
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => true,
|
||||
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => {
|
||||
return hir::ExprKind::Err(
|
||||
self.dcx().emit_err(AsyncCoroutinesNotSupported { span }),
|
||||
// Lower to a block `{ EXPR; <error> }` so that the awaited expr
|
||||
// is not accidentally orphaned.
|
||||
let stmt_id = self.next_id();
|
||||
let expr_err = self.expr(
|
||||
yielded.span,
|
||||
hir::ExprKind::Err(self.dcx().emit_err(AsyncCoroutinesNotSupported { span })),
|
||||
);
|
||||
return hir::ExprKind::Block(
|
||||
self.block_all(
|
||||
yielded.span,
|
||||
arena_vec![self; hir::Stmt {
|
||||
hir_id: stmt_id,
|
||||
kind: hir::StmtKind::Semi(yielded),
|
||||
span: yielded.span,
|
||||
}],
|
||||
Some(self.arena.alloc(expr_err)),
|
||||
),
|
||||
None,
|
||||
);
|
||||
}
|
||||
Some(hir::CoroutineKind::Coroutine(_)) => {
|
||||
@ -1526,9 +1569,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}
|
||||
};
|
||||
|
||||
let yielded =
|
||||
opt_expr.as_ref().map(|x| self.lower_expr(x)).unwrap_or_else(|| self.expr_unit(span));
|
||||
|
||||
if is_async_gen {
|
||||
// `yield $expr` is transformed into `task_context = yield async_gen_ready($expr)`.
|
||||
// This ensures that we store our resumed `ResumeContext` correctly, and also that
|
||||
@ -1747,7 +1787,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|
||||
// `#[allow(unreachable_code)]`
|
||||
let attr = attr::mk_attr_nested_word(
|
||||
&self.tcx.sess.parse_sess.attr_id_generator,
|
||||
&self.tcx.sess.psess.attr_id_generator,
|
||||
AttrStyle::Outer,
|
||||
sym::allow,
|
||||
sym::unreachable_code,
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
use super::LoweringContext;
|
||||
use core::ops::ControlFlow;
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::visit::Visitor;
|
||||
use rustc_ast::*;
|
||||
@ -594,30 +595,31 @@ fn expand_format_args<'hir>(
|
||||
}
|
||||
|
||||
fn may_contain_yield_point(e: &ast::Expr) -> bool {
|
||||
struct MayContainYieldPoint(bool);
|
||||
struct MayContainYieldPoint;
|
||||
|
||||
impl Visitor<'_> for MayContainYieldPoint {
|
||||
fn visit_expr(&mut self, e: &ast::Expr) {
|
||||
type Result = ControlFlow<()>;
|
||||
|
||||
fn visit_expr(&mut self, e: &ast::Expr) -> ControlFlow<()> {
|
||||
if let ast::ExprKind::Await(_, _) | ast::ExprKind::Yield(_) = e.kind {
|
||||
self.0 = true;
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
visit::walk_expr(self, e);
|
||||
visit::walk_expr(self, e)
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mac_call(&mut self, _: &ast::MacCall) {
|
||||
fn visit_mac_call(&mut self, _: &ast::MacCall) -> ControlFlow<()> {
|
||||
// Macros should be expanded at this point.
|
||||
unreachable!("unexpanded macro in ast lowering");
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, _: &ast::Item) {
|
||||
fn visit_item(&mut self, _: &ast::Item) -> ControlFlow<()> {
|
||||
// Do not recurse into nested items.
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
let mut visitor = MayContainYieldPoint(false);
|
||||
visitor.visit_expr(e);
|
||||
visitor.0
|
||||
MayContainYieldPoint.visit_expr(e).is_break()
|
||||
}
|
||||
|
||||
fn for_all_argument_indexes(template: &mut [FormatArgsPiece], mut f: impl FnMut(&mut usize)) {
|
||||
|
||||
@ -15,7 +15,7 @@ struct NodeCollector<'a, 'hir> {
|
||||
bodies: &'a SortedMap<ItemLocalId, &'hir Body<'hir>>,
|
||||
|
||||
/// Outputs
|
||||
nodes: IndexVec<ItemLocalId, Option<ParentedNode<'hir>>>,
|
||||
nodes: IndexVec<ItemLocalId, ParentedNode<'hir>>,
|
||||
parenting: LocalDefIdMap<ItemLocalId>,
|
||||
|
||||
/// The parent of this node
|
||||
@ -29,16 +29,19 @@ pub(super) fn index_hir<'hir>(
|
||||
tcx: TyCtxt<'hir>,
|
||||
item: hir::OwnerNode<'hir>,
|
||||
bodies: &SortedMap<ItemLocalId, &'hir Body<'hir>>,
|
||||
) -> (IndexVec<ItemLocalId, Option<ParentedNode<'hir>>>, LocalDefIdMap<ItemLocalId>) {
|
||||
let mut nodes = IndexVec::new();
|
||||
num_nodes: usize,
|
||||
) -> (IndexVec<ItemLocalId, ParentedNode<'hir>>, LocalDefIdMap<ItemLocalId>) {
|
||||
let zero_id = ItemLocalId::new(0);
|
||||
let err_node = ParentedNode { parent: zero_id, node: Node::Err(item.span()) };
|
||||
let mut nodes = IndexVec::from_elem_n(err_node, num_nodes);
|
||||
// This node's parent should never be accessed: the owner's parent is computed by the
|
||||
// hir_owner_parent query. Make it invalid (= ItemLocalId::MAX) to force an ICE whenever it is
|
||||
// used.
|
||||
nodes.push(Some(ParentedNode { parent: ItemLocalId::INVALID, node: item.into() }));
|
||||
nodes[zero_id] = ParentedNode { parent: ItemLocalId::INVALID, node: item.into() };
|
||||
let mut collector = NodeCollector {
|
||||
tcx,
|
||||
owner: item.def_id(),
|
||||
parent_node: ItemLocalId::new(0),
|
||||
parent_node: zero_id,
|
||||
nodes,
|
||||
bodies,
|
||||
parenting: Default::default(),
|
||||
@ -52,8 +55,17 @@ pub(super) fn index_hir<'hir>(
|
||||
OwnerNode::TraitItem(item) => collector.visit_trait_item(item),
|
||||
OwnerNode::ImplItem(item) => collector.visit_impl_item(item),
|
||||
OwnerNode::ForeignItem(item) => collector.visit_foreign_item(item),
|
||||
OwnerNode::AssocOpaqueTy(..) => unreachable!(),
|
||||
};
|
||||
|
||||
for (local_id, node) in collector.nodes.iter_enumerated() {
|
||||
if let Node::Err(span) = node.node {
|
||||
let hir_id = HirId { owner: item.def_id(), local_id };
|
||||
let msg = format!("ID {hir_id} not encountered when visiting item HIR");
|
||||
tcx.dcx().span_delayed_bug(*span, msg);
|
||||
}
|
||||
}
|
||||
|
||||
(collector.nodes, collector.parenting)
|
||||
}
|
||||
|
||||
@ -88,7 +100,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
self.nodes.insert(hir_id.local_id, ParentedNode { parent: self.parent_node, node });
|
||||
self.nodes[hir_id.local_id] = ParentedNode { parent: self.parent_node, node };
|
||||
}
|
||||
|
||||
fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_node_id: HirId, f: F) {
|
||||
@ -254,6 +266,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
||||
}
|
||||
|
||||
fn visit_path_segment(&mut self, path_segment: &'hir PathSegment<'hir>) {
|
||||
// FIXME: walk path segment with `path_segment.hir_id` parent.
|
||||
self.insert(path_segment.ident.span, path_segment.hir_id, Node::PathSegment(path_segment));
|
||||
intravisit::walk_path_segment(self, path_segment);
|
||||
}
|
||||
@ -348,4 +361,23 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
||||
|
||||
self.visit_nested_foreign_item(id);
|
||||
}
|
||||
|
||||
fn visit_where_predicate(&mut self, predicate: &'hir WherePredicate<'hir>) {
|
||||
match predicate {
|
||||
WherePredicate::BoundPredicate(pred) => {
|
||||
self.insert(pred.span, pred.hir_id, Node::WhereBoundPredicate(pred));
|
||||
self.with_parent(pred.hir_id, |this| {
|
||||
intravisit::walk_where_predicate(this, predicate)
|
||||
})
|
||||
}
|
||||
_ => intravisit::walk_where_predicate(self, predicate),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_array_length(&mut self, len: &'hir ArrayLen) {
|
||||
match len {
|
||||
ArrayLen::Infer(inf) => self.insert(inf.span, inf.hir_id, Node::ArrayLenInfer(inf)),
|
||||
ArrayLen::Body(..) => intravisit::walk_array_len(self, len),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@ pub(super) struct ItemLowerer<'a, 'hir> {
|
||||
pub(super) tcx: TyCtxt<'hir>,
|
||||
pub(super) resolver: &'a mut ResolverAstLowering,
|
||||
pub(super) ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>,
|
||||
pub(super) owners: &'a mut IndexVec<LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>>,
|
||||
pub(super) owners: &'a mut IndexVec<LocalDefId, hir::MaybeOwner<'hir>>,
|
||||
}
|
||||
|
||||
/// When we have a ty alias we *may* have two where clauses. To give the best diagnostics, we set the span
|
||||
@ -33,19 +33,20 @@ pub(super) struct ItemLowerer<'a, 'hir> {
|
||||
/// clause if it exists.
|
||||
fn add_ty_alias_where_clause(
|
||||
generics: &mut ast::Generics,
|
||||
mut where_clauses: (TyAliasWhereClause, TyAliasWhereClause),
|
||||
mut where_clauses: TyAliasWhereClauses,
|
||||
prefer_first: bool,
|
||||
) {
|
||||
if !prefer_first {
|
||||
where_clauses = (where_clauses.1, where_clauses.0);
|
||||
}
|
||||
if where_clauses.0.0 || !where_clauses.1.0 {
|
||||
generics.where_clause.has_where_token = where_clauses.0.0;
|
||||
generics.where_clause.span = where_clauses.0.1;
|
||||
} else {
|
||||
generics.where_clause.has_where_token = where_clauses.1.0;
|
||||
generics.where_clause.span = where_clauses.1.1;
|
||||
(where_clauses.before, where_clauses.after) = (where_clauses.after, where_clauses.before);
|
||||
}
|
||||
let where_clause =
|
||||
if where_clauses.before.has_where_token || !where_clauses.after.has_where_token {
|
||||
where_clauses.before
|
||||
} else {
|
||||
where_clauses.after
|
||||
};
|
||||
generics.where_clause.has_where_token = where_clause.has_where_token;
|
||||
generics.where_clause.span = where_clause.span;
|
||||
}
|
||||
|
||||
impl<'a, 'hir> ItemLowerer<'a, 'hir> {
|
||||
@ -64,10 +65,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn lower_node(
|
||||
&mut self,
|
||||
def_id: LocalDefId,
|
||||
) -> hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>> {
|
||||
pub(super) fn lower_node(&mut self, def_id: LocalDefId) -> hir::MaybeOwner<'hir> {
|
||||
let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
|
||||
if let hir::MaybeOwner::Phantom = owner {
|
||||
let node = self.ast_index[def_id];
|
||||
@ -192,7 +190,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
generics,
|
||||
Const::No,
|
||||
id,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
this.lower_const_item(ty, span, expr.as_deref(), ImplTraitPosition::ConstTy)
|
||||
},
|
||||
@ -221,7 +219,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|
||||
let itctx = ImplTraitContext::Universal;
|
||||
let (generics, decl) =
|
||||
this.lower_generics(generics, header.constness, id, &itctx, |this| {
|
||||
this.lower_generics(generics, header.constness, id, itctx, |this| {
|
||||
this.lower_fn_decl(
|
||||
decl,
|
||||
id,
|
||||
@ -266,7 +264,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
&generics,
|
||||
Const::No,
|
||||
id,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| match ty {
|
||||
None => {
|
||||
let guar = this.dcx().span_delayed_bug(
|
||||
@ -277,7 +275,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}
|
||||
Some(ty) => this.lower_ty(
|
||||
ty,
|
||||
&ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty: false },
|
||||
ImplTraitContext::OpaqueTy {
|
||||
origin: hir::OpaqueTyOrigin::TyAlias {
|
||||
parent: this.local_def_id(id),
|
||||
in_assoc_ty: false,
|
||||
},
|
||||
fn_kind: None,
|
||||
},
|
||||
),
|
||||
},
|
||||
);
|
||||
@ -288,7 +292,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
generics,
|
||||
Const::No,
|
||||
id,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
this.arena.alloc_from_iter(
|
||||
enum_definition.variants.iter().map(|x| this.lower_variant(x)),
|
||||
@ -302,7 +306,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
generics,
|
||||
Const::No,
|
||||
id,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| this.lower_variant_data(hir_id, struct_def),
|
||||
);
|
||||
hir::ItemKind::Struct(struct_def, generics)
|
||||
@ -312,7 +316,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
generics,
|
||||
Const::No,
|
||||
id,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| this.lower_variant_data(hir_id, vdata),
|
||||
);
|
||||
hir::ItemKind::Union(vdata, generics)
|
||||
@ -342,23 +346,28 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
// parent lifetime.
|
||||
let itctx = ImplTraitContext::Universal;
|
||||
let (generics, (trait_ref, lowered_ty)) =
|
||||
self.lower_generics(ast_generics, *constness, id, &itctx, |this| {
|
||||
let constness = match *constness {
|
||||
Const::Yes(span) => BoundConstness::Maybe(span),
|
||||
Const::No => BoundConstness::Never,
|
||||
self.lower_generics(ast_generics, *constness, id, itctx, |this| {
|
||||
let modifiers = TraitBoundModifiers {
|
||||
constness: match *constness {
|
||||
Const::Yes(span) => BoundConstness::Maybe(span),
|
||||
Const::No => BoundConstness::Never,
|
||||
},
|
||||
asyncness: BoundAsyncness::Normal,
|
||||
// we don't use this in bound lowering
|
||||
polarity: BoundPolarity::Positive,
|
||||
};
|
||||
|
||||
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
|
||||
this.lower_trait_ref(
|
||||
constness,
|
||||
modifiers,
|
||||
trait_ref,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
|
||||
)
|
||||
});
|
||||
|
||||
let lowered_ty = this.lower_ty(
|
||||
ty,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::ImplSelf),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::ImplSelf),
|
||||
);
|
||||
|
||||
(trait_ref, lowered_ty)
|
||||
@ -398,11 +407,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
generics,
|
||||
constness,
|
||||
id,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
let bounds = this.lower_param_bounds(
|
||||
bounds,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
);
|
||||
let items = this.arena.alloc_from_iter(
|
||||
items.iter().map(|item| this.lower_trait_item_ref(item)),
|
||||
@ -418,11 +427,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
generics,
|
||||
Const::No,
|
||||
id,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
this.lower_param_bounds(
|
||||
bounds,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
)
|
||||
},
|
||||
);
|
||||
@ -462,7 +471,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
body: Option<&Expr>,
|
||||
impl_trait_position: ImplTraitPosition,
|
||||
) -> (&'hir hir::Ty<'hir>, hir::BodyId) {
|
||||
let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(impl_trait_position));
|
||||
let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(impl_trait_position));
|
||||
(ty, self.lower_const_body(span, body))
|
||||
}
|
||||
|
||||
@ -496,8 +505,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
let res =
|
||||
self.expect_full_res_from_use(id).map(|res| self.lower_res(res)).collect();
|
||||
let res = self.lower_import_res(id, path.span);
|
||||
let path = self.lower_use_path(res, &path, ParamMode::Explicit);
|
||||
hir::ItemKind::Use(path, hir::UseKind::Single)
|
||||
}
|
||||
@ -533,7 +541,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
// for that we return the `{}` import (called the
|
||||
// `ListStem`).
|
||||
|
||||
let prefix = Path { segments, span: prefix.span.to(path.span), tokens: None };
|
||||
let span = prefix.span.to(path.span);
|
||||
let prefix = Path { segments, span, tokens: None };
|
||||
|
||||
// Add all the nested `PathListItem`s to the HIR.
|
||||
for &(ref use_tree, id) in trees {
|
||||
@ -567,9 +576,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
});
|
||||
}
|
||||
|
||||
let res =
|
||||
self.expect_full_res_from_use(id).map(|res| self.lower_res(res)).collect();
|
||||
let path = self.lower_use_path(res, &prefix, ParamMode::Explicit);
|
||||
// Condition should match `build_reduced_graph_for_use_tree`.
|
||||
let path = if trees.is_empty()
|
||||
&& !(prefix.segments.is_empty()
|
||||
|| prefix.segments.len() == 1
|
||||
&& prefix.segments[0].ident.name == kw::PathRoot)
|
||||
{
|
||||
// For empty lists we need to lower the prefix so it is checked for things
|
||||
// like stability later.
|
||||
let res = self.lower_import_res(id, span);
|
||||
self.lower_use_path(res, &prefix, ParamMode::Explicit)
|
||||
} else {
|
||||
// For non-empty lists we can just drop all the data, the prefix is already
|
||||
// present in HIR as a part of nested imports.
|
||||
self.arena.alloc(hir::UsePath { res: smallvec![], segments: &[], span })
|
||||
};
|
||||
hir::ItemKind::Use(path, hir::UseKind::ListStem)
|
||||
}
|
||||
}
|
||||
@ -624,7 +645,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let fdec = &sig.decl;
|
||||
let itctx = ImplTraitContext::Universal;
|
||||
let (generics, (fn_dec, fn_args)) =
|
||||
self.lower_generics(generics, Const::No, i.id, &itctx, |this| {
|
||||
self.lower_generics(generics, Const::No, i.id, itctx, |this| {
|
||||
(
|
||||
// Disallow `impl Trait` in foreign items.
|
||||
this.lower_fn_decl(
|
||||
@ -641,8 +662,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
hir::ForeignItemKind::Fn(fn_dec, fn_args, generics)
|
||||
}
|
||||
ForeignItemKind::Static(t, m, _) => {
|
||||
let ty = self
|
||||
.lower_ty(t, &ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
|
||||
let ty =
|
||||
self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
|
||||
hir::ForeignItemKind::Static(ty, *m)
|
||||
}
|
||||
ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type,
|
||||
@ -706,18 +727,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_field_def(&mut self, (index, f): (usize, &FieldDef)) -> hir::FieldDef<'hir> {
|
||||
pub(super) fn lower_field_def(
|
||||
&mut self,
|
||||
(index, f): (usize, &FieldDef),
|
||||
) -> hir::FieldDef<'hir> {
|
||||
let ty = if let TyKind::Path(qself, path) = &f.ty.kind {
|
||||
let t = self.lower_path_ty(
|
||||
&f.ty,
|
||||
qself,
|
||||
path,
|
||||
ParamMode::ExplicitNamed, // no `'_` in declarations (Issue #61124)
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy),
|
||||
);
|
||||
self.arena.alloc(t)
|
||||
} else {
|
||||
self.lower_ty(&f.ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy))
|
||||
self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy))
|
||||
};
|
||||
let hir_id = self.lower_node_id(f.id);
|
||||
self.lower_attrs(hir_id, &f.attrs);
|
||||
@ -746,12 +770,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
generics,
|
||||
Const::No,
|
||||
i.id,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
let ty = this.lower_ty(
|
||||
ty,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
|
||||
);
|
||||
let ty = this
|
||||
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
|
||||
let body = expr.as_ref().map(|x| this.lower_const_body(i.span, Some(x)));
|
||||
|
||||
hir::TraitItemKind::Const(ty, body)
|
||||
@ -794,18 +816,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
&generics,
|
||||
Const::No,
|
||||
i.id,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
let ty = ty.as_ref().map(|x| {
|
||||
this.lower_ty(
|
||||
x,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::AssocTy),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::AssocTy),
|
||||
)
|
||||
});
|
||||
hir::TraitItemKind::Type(
|
||||
this.lower_param_bounds(
|
||||
bounds,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
),
|
||||
ty,
|
||||
)
|
||||
@ -873,10 +895,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
generics,
|
||||
Const::No,
|
||||
i.id,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
let ty = this
|
||||
.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
|
||||
let ty =
|
||||
this.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
|
||||
let body = this.lower_const_body(i.span, expr.as_deref());
|
||||
|
||||
hir::ImplItemKind::Const(ty, body)
|
||||
@ -907,7 +929,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
&generics,
|
||||
Const::No,
|
||||
i.id,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| match ty {
|
||||
None => {
|
||||
let guar = this.dcx().span_delayed_bug(
|
||||
@ -920,7 +942,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
Some(ty) => {
|
||||
let ty = this.lower_ty(
|
||||
ty,
|
||||
&ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty: true },
|
||||
ImplTraitContext::OpaqueTy {
|
||||
origin: hir::OpaqueTyOrigin::TyAlias {
|
||||
parent: this.local_def_id(i.id),
|
||||
in_assoc_ty: true,
|
||||
},
|
||||
fn_kind: None,
|
||||
},
|
||||
);
|
||||
hir::ImplItemKind::Type(ty)
|
||||
}
|
||||
@ -1053,7 +1081,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
fn lower_block_expr_opt(&mut self, span: Span, block: Option<&Block>) -> hir::Expr<'hir> {
|
||||
match block {
|
||||
Some(block) => self.lower_block_expr(block),
|
||||
None => self.expr_err(span, self.dcx().span_delayed_bug(span, "no block")),
|
||||
None => self.expr_err(span, self.dcx().has_errors().unwrap()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1089,7 +1117,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
body.span,
|
||||
coroutine_kind,
|
||||
hir::CoroutineSource::Fn,
|
||||
None,
|
||||
);
|
||||
|
||||
// FIXME(async_fn_track_caller): Can this be moved above?
|
||||
@ -1111,7 +1138,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
body_span: Span,
|
||||
coroutine_kind: CoroutineKind,
|
||||
coroutine_source: hir::CoroutineSource,
|
||||
return_type_hint: Option<hir::FnRetTy<'hir>>,
|
||||
) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>) {
|
||||
let mut parameters: Vec<hir::Param<'_>> = Vec::new();
|
||||
let mut statements: Vec<hir::Stmt<'_>> = Vec::new();
|
||||
@ -1281,12 +1307,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
};
|
||||
let closure_id = coroutine_kind.closure_id();
|
||||
let coroutine_expr = self.make_desugared_coroutine_expr(
|
||||
// FIXME(async_closures): This should only move locals,
|
||||
// and not upvars. Capturing closure upvars by ref doesn't
|
||||
// work right now anyways, so whatever.
|
||||
CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
|
||||
// The default capture mode here is by-ref. Later on during upvar analysis,
|
||||
// we will force the captured arguments to by-move, but for async closures,
|
||||
// we want to make sure that we avoid unnecessarily moving captures, or else
|
||||
// all async closures would default to `FnOnce` as their calling mode.
|
||||
CaptureBy::Ref,
|
||||
closure_id,
|
||||
return_type_hint,
|
||||
None,
|
||||
body_span,
|
||||
desugaring_kind,
|
||||
coroutine_source,
|
||||
@ -1315,7 +1342,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
// synthesize a host effect param for them. We reject `const` on them during AST validation.
|
||||
let constness = if kind == FnDeclKind::Inherent { sig.header.constness } else { Const::No };
|
||||
let itctx = ImplTraitContext::Universal;
|
||||
let (generics, decl) = self.lower_generics(generics, constness, id, &itctx, |this| {
|
||||
let (generics, decl) = self.lower_generics(generics, constness, id, itctx, |this| {
|
||||
this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind)
|
||||
});
|
||||
(generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
|
||||
@ -1393,7 +1420,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
generics: &Generics,
|
||||
constness: Const,
|
||||
parent_node_id: NodeId,
|
||||
itctx: &ImplTraitContext,
|
||||
itctx: ImplTraitContext,
|
||||
f: impl FnOnce(&mut Self) -> T,
|
||||
) -> (&'hir hir::Generics<'hir>, T) {
|
||||
debug_assert!(self.impl_trait_defs.is_empty());
|
||||
@ -1599,7 +1626,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
bounds: &[GenericBound],
|
||||
colon_span: Option<Span>,
|
||||
parent_span: Span,
|
||||
itctx: &ImplTraitContext,
|
||||
itctx: ImplTraitContext,
|
||||
origin: PredicateOrigin,
|
||||
) -> Option<hir::WherePredicate<'hir>> {
|
||||
// Do not create a clause if we do not have anything inside it.
|
||||
@ -1673,10 +1700,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
bound_generic_params: self
|
||||
.lower_generic_params(bound_generic_params, hir::GenericParamSource::Binder),
|
||||
bounded_ty: self
|
||||
.lower_ty(bounded_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
|
||||
.lower_ty(bounded_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
|
||||
bounds: self.lower_param_bounds(
|
||||
bounds,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
),
|
||||
span: self.lower_span(*span),
|
||||
origin: PredicateOrigin::WhereClause,
|
||||
@ -1687,7 +1714,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
lifetime: self.lower_lifetime(lifetime),
|
||||
bounds: self.lower_param_bounds(
|
||||
bounds,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
),
|
||||
in_where_clause: true,
|
||||
})
|
||||
@ -1695,9 +1722,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
WherePredicate::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty, span }) => {
|
||||
hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
|
||||
lhs_ty: self
|
||||
.lower_ty(lhs_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
|
||||
.lower_ty(lhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
|
||||
rhs_ty: self
|
||||
.lower_ty(rhs_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
|
||||
.lower_ty(rhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
|
||||
span: self.lower_span(*span),
|
||||
})
|
||||
}
|
||||
|
||||
@ -33,10 +33,9 @@
|
||||
#![allow(internal_features)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(let_chains)]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate tracing;
|
||||
@ -52,18 +51,19 @@ use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::{DiagCtxt, DiagnosticArgFromDisplay, StashKey};
|
||||
use rustc_errors::{DiagArgFromDisplay, DiagCtxt, StashKey};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
|
||||
use rustc_hir::def_id::{LocalDefId, LocalDefIdMap, CRATE_DEF_ID, LOCAL_CRATE};
|
||||
use rustc_hir::{ConstArg, GenericArg, ItemLocalMap, ParamName, TraitCandidate};
|
||||
use rustc_index::{Idx, IndexSlice, IndexVec};
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
|
||||
use rustc_session::parse::{add_feature_diagnostics, feature_err};
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{DesugaringKind, Span, DUMMY_SP};
|
||||
use smallvec::SmallVec;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use std::collections::hash_map::Entry;
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
@ -99,7 +99,7 @@ struct LoweringContext<'a, 'hir> {
|
||||
/// Attributes inside the owner being lowered.
|
||||
attrs: SortedMap<hir::ItemLocalId, &'hir [Attribute]>,
|
||||
/// Collect items that were created by lowering the current owner.
|
||||
children: Vec<(LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>)>,
|
||||
children: Vec<(LocalDefId, hir::MaybeOwner<'hir>)>,
|
||||
|
||||
coroutine_kind: Option<hir::CoroutineKind>,
|
||||
|
||||
@ -131,6 +131,7 @@ struct LoweringContext<'a, 'hir> {
|
||||
allow_gen_future: Lrc<[Symbol]>,
|
||||
allow_async_iterator: Lrc<[Symbol]>,
|
||||
allow_for_await: Lrc<[Symbol]>,
|
||||
allow_async_fn_traits: Lrc<[Symbol]>,
|
||||
|
||||
/// Mapping from generics `def_id`s to TAIT generics `def_id`s.
|
||||
/// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic
|
||||
@ -176,6 +177,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
[sym::gen_future].into()
|
||||
},
|
||||
allow_for_await: [sym::async_iterator].into(),
|
||||
allow_async_fn_traits: [sym::async_fn_traits].into(),
|
||||
// FIXME(gen_blocks): how does `closure_track_caller`/`async_fn_track_caller`
|
||||
// interact with `gen`/`async gen` blocks
|
||||
allow_async_iterator: [sym::gen_future, sym::async_iterator].into(),
|
||||
@ -189,17 +191,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
trait ResolverAstLoweringExt {
|
||||
fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>>;
|
||||
fn get_partial_res(&self, id: NodeId) -> Option<PartialRes>;
|
||||
fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res<NodeId>>>;
|
||||
fn get_label_res(&self, id: NodeId) -> Option<NodeId>;
|
||||
fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes>;
|
||||
fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)>;
|
||||
fn remap_extra_lifetime_params(&mut self, from: NodeId, to: NodeId);
|
||||
}
|
||||
|
||||
impl ResolverAstLoweringExt for ResolverAstLowering {
|
||||
#[extension(trait ResolverAstLoweringExt)]
|
||||
impl ResolverAstLowering {
|
||||
fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>> {
|
||||
if let ExprKind::Path(None, path) = &expr.kind {
|
||||
// Don't perform legacy const generics rewriting if the path already
|
||||
@ -255,11 +248,6 @@ impl ResolverAstLoweringExt for ResolverAstLowering {
|
||||
fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> {
|
||||
self.extra_lifetime_params_map.remove(&id).unwrap_or_default()
|
||||
}
|
||||
|
||||
fn remap_extra_lifetime_params(&mut self, from: NodeId, to: NodeId) {
|
||||
let lifetimes = self.extra_lifetime_params_map.remove(&from).unwrap_or_default();
|
||||
self.extra_lifetime_params_map.insert(to, lifetimes);
|
||||
}
|
||||
}
|
||||
|
||||
/// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
|
||||
@ -277,13 +265,12 @@ enum ImplTraitContext {
|
||||
/// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually
|
||||
/// equivalent to a new opaque type like `type T = impl Debug; fn foo() -> T`.
|
||||
///
|
||||
ReturnPositionOpaqueTy {
|
||||
/// Origin: Either OpaqueTyOrigin::FnReturn or OpaqueTyOrigin::AsyncFn,
|
||||
OpaqueTy {
|
||||
origin: hir::OpaqueTyOrigin,
|
||||
fn_kind: FnDeclKind,
|
||||
/// Only used to change the lifetime capture rules, since
|
||||
/// RPITIT captures all in scope, RPIT does not.
|
||||
fn_kind: Option<FnDeclKind>,
|
||||
},
|
||||
/// Impl trait in type aliases.
|
||||
TypeAliasesOpaqueTy { in_assoc_ty: bool },
|
||||
/// `impl Trait` is unstably accepted in this position.
|
||||
FeatureGated(ImplTraitPosition, Symbol),
|
||||
/// `impl Trait` is not accepted in this position.
|
||||
@ -296,7 +283,6 @@ enum ImplTraitPosition {
|
||||
Path,
|
||||
Variable,
|
||||
Trait,
|
||||
AsyncBlock,
|
||||
Bound,
|
||||
Generic,
|
||||
ExternFnParam,
|
||||
@ -323,7 +309,6 @@ impl std::fmt::Display for ImplTraitPosition {
|
||||
ImplTraitPosition::Path => "paths",
|
||||
ImplTraitPosition::Variable => "the type of variable bindings",
|
||||
ImplTraitPosition::Trait => "traits",
|
||||
ImplTraitPosition::AsyncBlock => "async blocks",
|
||||
ImplTraitPosition::Bound => "bounds",
|
||||
ImplTraitPosition::Generic => "generics",
|
||||
ImplTraitPosition::ExternFnParam => "`extern fn` parameters",
|
||||
@ -415,7 +400,7 @@ fn index_crate<'a>(
|
||||
/// This hash will then be part of the crate_hash which is stored in the metadata.
|
||||
fn compute_hir_hash(
|
||||
tcx: TyCtxt<'_>,
|
||||
owners: &IndexSlice<LocalDefId, hir::MaybeOwner<&hir::OwnerInfo<'_>>>,
|
||||
owners: &IndexSlice<LocalDefId, hir::MaybeOwner<'_>>,
|
||||
) -> Fingerprint {
|
||||
let mut hir_body_nodes: Vec<_> = owners
|
||||
.iter_enumerated()
|
||||
@ -441,7 +426,7 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
|
||||
tcx.ensure_with_value().early_lint_checks(());
|
||||
tcx.ensure_with_value().debugger_visualizers(LOCAL_CRATE);
|
||||
tcx.ensure_with_value().get_lang_items(());
|
||||
let (mut resolver, krate) = tcx.resolver_for_lowering(()).steal();
|
||||
let (mut resolver, krate) = tcx.resolver_for_lowering().steal();
|
||||
|
||||
let ast_index = index_crate(&resolver.node_id_to_def_id, &krate);
|
||||
let mut owners = IndexVec::from_fn_n(
|
||||
@ -657,24 +642,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
let bodies = SortedMap::from_presorted_elements(bodies);
|
||||
|
||||
// Don't hash unless necessary, because it's expensive.
|
||||
let (opt_hash_including_bodies, attrs_hash) = if self.tcx.needs_crate_hash() {
|
||||
self.tcx.with_stable_hashing_context(|mut hcx| {
|
||||
let mut stable_hasher = StableHasher::new();
|
||||
node.hash_stable(&mut hcx, &mut stable_hasher);
|
||||
// Bodies are stored out of line, so we need to pull them explicitly in the hash.
|
||||
bodies.hash_stable(&mut hcx, &mut stable_hasher);
|
||||
let h1 = stable_hasher.finish();
|
||||
|
||||
let mut stable_hasher = StableHasher::new();
|
||||
attrs.hash_stable(&mut hcx, &mut stable_hasher);
|
||||
let h2 = stable_hasher.finish();
|
||||
|
||||
(Some(h1), Some(h2))
|
||||
})
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies);
|
||||
let (opt_hash_including_bodies, attrs_hash) =
|
||||
self.tcx.hash_owner_nodes(node, &bodies, &attrs);
|
||||
let num_nodes = self.item_local_id_counter.as_usize();
|
||||
let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies, num_nodes);
|
||||
let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies };
|
||||
let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash };
|
||||
|
||||
@ -749,8 +720,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
self.resolver.get_partial_res(id).map_or(Res::Err, |pr| pr.expect_full_res())
|
||||
}
|
||||
|
||||
fn expect_full_res_from_use(&mut self, id: NodeId) -> impl Iterator<Item = Res<NodeId>> {
|
||||
self.resolver.get_import_res(id).present_items()
|
||||
fn lower_import_res(&mut self, id: NodeId, span: Span) -> SmallVec<[Res; 3]> {
|
||||
let res = self.resolver.get_import_res(id).present_items();
|
||||
let res: SmallVec<_> = res.map(|res| self.lower_res(res)).collect();
|
||||
if res.is_empty() {
|
||||
self.dcx().span_delayed_bug(span, "no resolution for an import");
|
||||
return smallvec![Res::Err];
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
fn make_lang_item_qpath(&mut self, lang_item: hir::LangItem, span: Span) -> hir::QPath<'hir> {
|
||||
@ -966,10 +943,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
{
|
||||
lit
|
||||
} else {
|
||||
let guar = self.dcx().has_errors().unwrap();
|
||||
MetaItemLit {
|
||||
symbol: kw::Empty,
|
||||
suffix: None,
|
||||
kind: LitKind::Err,
|
||||
kind: LitKind::Err(guar),
|
||||
span: DUMMY_SP,
|
||||
}
|
||||
};
|
||||
@ -999,7 +977,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
fn lower_assoc_ty_constraint(
|
||||
&mut self,
|
||||
constraint: &AssocConstraint,
|
||||
itctx: &ImplTraitContext,
|
||||
itctx: ImplTraitContext,
|
||||
) -> hir::TypeBinding<'hir> {
|
||||
debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
|
||||
// lower generic arguments of identifier in constraint
|
||||
@ -1078,90 +1056,36 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
hir::TypeBindingKind::Equality { term }
|
||||
}
|
||||
AssocConstraintKind::Bound { bounds } => {
|
||||
enum DesugarKind<'a> {
|
||||
ImplTrait,
|
||||
Error(&'a ImplTraitPosition),
|
||||
Bound,
|
||||
}
|
||||
// Disallow ATB in dyn types
|
||||
if self.is_in_dyn_type {
|
||||
let suggestion = match itctx {
|
||||
ImplTraitContext::OpaqueTy { .. } | ImplTraitContext::Universal => {
|
||||
let bound_end_span = constraint
|
||||
.gen_args
|
||||
.as_ref()
|
||||
.map_or(constraint.ident.span, |args| args.span());
|
||||
if bound_end_span.eq_ctxt(constraint.span) {
|
||||
Some(self.tcx.sess.source_map().next_point(bound_end_span))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
// Piggy-back on the `impl Trait` context to figure out the correct behavior.
|
||||
let desugar_kind = match itctx {
|
||||
// We are in the return position:
|
||||
//
|
||||
// fn foo() -> impl Iterator<Item: Debug>
|
||||
//
|
||||
// so desugar to
|
||||
//
|
||||
// fn foo() -> impl Iterator<Item = impl Debug>
|
||||
ImplTraitContext::ReturnPositionOpaqueTy { .. }
|
||||
| ImplTraitContext::TypeAliasesOpaqueTy { .. } => DesugarKind::ImplTrait,
|
||||
let guar = self.dcx().emit_err(errors::MisplacedAssocTyBinding {
|
||||
span: constraint.span,
|
||||
suggestion,
|
||||
});
|
||||
let err_ty =
|
||||
&*self.arena.alloc(self.ty(constraint.span, hir::TyKind::Err(guar)));
|
||||
hir::TypeBindingKind::Equality { term: err_ty.into() }
|
||||
} else {
|
||||
// Desugar `AssocTy: Bounds` into a type binding where the
|
||||
// later desugars into a trait predicate.
|
||||
let bounds = self.lower_param_bounds(bounds, itctx);
|
||||
|
||||
// We are in the argument position, but within a dyn type:
|
||||
//
|
||||
// fn foo(x: dyn Iterator<Item: Debug>)
|
||||
//
|
||||
// so desugar to
|
||||
//
|
||||
// fn foo(x: dyn Iterator<Item = impl Debug>)
|
||||
ImplTraitContext::Universal if self.is_in_dyn_type => DesugarKind::ImplTrait,
|
||||
|
||||
ImplTraitContext::Disallowed(position) if self.is_in_dyn_type => {
|
||||
DesugarKind::Error(position)
|
||||
}
|
||||
|
||||
// We are in the parameter position, but not within a dyn type:
|
||||
//
|
||||
// fn foo(x: impl Iterator<Item: Debug>)
|
||||
//
|
||||
// so we leave it as is and this gets expanded in astconv to a bound like
|
||||
// `<T as Iterator>::Item: Debug` where `T` is the type parameter for the
|
||||
// `impl Iterator`.
|
||||
_ => DesugarKind::Bound,
|
||||
};
|
||||
|
||||
match desugar_kind {
|
||||
DesugarKind::ImplTrait => {
|
||||
// Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`. We do this by
|
||||
// constructing the HIR for `impl bounds...` and then lowering that.
|
||||
|
||||
let impl_trait_node_id = self.next_node_id();
|
||||
// Shift `impl Trait` lifetime captures from the associated type bound's
|
||||
// node id to the opaque node id, so that the opaque can actually use
|
||||
// these lifetime bounds.
|
||||
self.resolver
|
||||
.remap_extra_lifetime_params(constraint.id, impl_trait_node_id);
|
||||
|
||||
self.with_dyn_type_scope(false, |this| {
|
||||
let node_id = this.next_node_id();
|
||||
let ty = this.lower_ty(
|
||||
&Ty {
|
||||
id: node_id,
|
||||
kind: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()),
|
||||
span: this.lower_span(constraint.span),
|
||||
tokens: None,
|
||||
},
|
||||
itctx,
|
||||
);
|
||||
|
||||
hir::TypeBindingKind::Equality { term: ty.into() }
|
||||
})
|
||||
}
|
||||
DesugarKind::Bound => {
|
||||
// Desugar `AssocTy: Bounds` into a type binding where the
|
||||
// later desugars into a trait predicate.
|
||||
let bounds = self.lower_param_bounds(bounds, itctx);
|
||||
|
||||
hir::TypeBindingKind::Constraint { bounds }
|
||||
}
|
||||
DesugarKind::Error(position) => {
|
||||
let guar = self.dcx().emit_err(errors::MisplacedAssocTyBinding {
|
||||
span: constraint.span,
|
||||
position: DiagnosticArgFromDisplay(position),
|
||||
});
|
||||
let err_ty =
|
||||
&*self.arena.alloc(self.ty(constraint.span, hir::TyKind::Err(guar)));
|
||||
hir::TypeBindingKind::Equality { term: err_ty.into() }
|
||||
}
|
||||
hir::TypeBindingKind::Constraint { bounds }
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -1203,7 +1127,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
fn lower_generic_arg(
|
||||
&mut self,
|
||||
arg: &ast::GenericArg,
|
||||
itctx: &ImplTraitContext,
|
||||
itctx: ImplTraitContext,
|
||||
) -> hir::GenericArg<'hir> {
|
||||
match arg {
|
||||
ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(lt)),
|
||||
@ -1282,7 +1206,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn lower_ty(&mut self, t: &Ty, itctx: &ImplTraitContext) -> &'hir hir::Ty<'hir> {
|
||||
fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> &'hir hir::Ty<'hir> {
|
||||
self.arena.alloc(self.lower_ty_direct(t, itctx))
|
||||
}
|
||||
|
||||
@ -1292,7 +1216,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
qself: &Option<ptr::P<QSelf>>,
|
||||
path: &Path,
|
||||
param_mode: ParamMode,
|
||||
itctx: &ImplTraitContext,
|
||||
itctx: ImplTraitContext,
|
||||
) -> hir::Ty<'hir> {
|
||||
// Check whether we should interpret this as a bare trait object.
|
||||
// This check mirrors the one in late resolution. We only introduce this special case in
|
||||
@ -1311,7 +1235,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
span: t.span,
|
||||
},
|
||||
itctx,
|
||||
ast::BoundConstness::Never,
|
||||
TraitBoundModifiers::NONE,
|
||||
);
|
||||
let bounds = this.arena.alloc_from_iter([bound]);
|
||||
let lifetime_bound = this.elided_dyn_bound(t.span);
|
||||
@ -1334,23 +1258,48 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
self.ty(span, hir::TyKind::Tup(tys))
|
||||
}
|
||||
|
||||
fn lower_ty_direct(&mut self, t: &Ty, itctx: &ImplTraitContext) -> hir::Ty<'hir> {
|
||||
fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> {
|
||||
let kind = match &t.kind {
|
||||
TyKind::Infer => hir::TyKind::Infer,
|
||||
TyKind::Err => {
|
||||
hir::TyKind::Err(self.dcx().span_delayed_bug(t.span, "TyKind::Err lowered"))
|
||||
}
|
||||
// FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
TyKind::AnonStruct(ref _fields) => {
|
||||
hir::TyKind::Err(self.dcx().span_err(t.span, "anonymous structs are unimplemented"))
|
||||
}
|
||||
// FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
TyKind::AnonUnion(ref _fields) => {
|
||||
hir::TyKind::Err(self.dcx().span_err(t.span, "anonymous unions are unimplemented"))
|
||||
TyKind::Err(guar) => hir::TyKind::Err(*guar),
|
||||
// Lower the anonymous structs or unions in a nested lowering context.
|
||||
//
|
||||
// ```
|
||||
// struct Foo {
|
||||
// _: union {
|
||||
// // ^__________________ <-- within the nested lowering context,
|
||||
// /* fields */ // | we lower all fields defined into an
|
||||
// } // | owner node of struct or union item
|
||||
// // ^_____________________|
|
||||
// }
|
||||
// ```
|
||||
TyKind::AnonStruct(node_id, fields) | TyKind::AnonUnion(node_id, fields) => {
|
||||
// Here its `def_id` is created in `build_reduced_graph`.
|
||||
let def_id = self.local_def_id(*node_id);
|
||||
debug!(?def_id);
|
||||
let owner_id = hir::OwnerId { def_id };
|
||||
self.with_hir_id_owner(*node_id, |this| {
|
||||
let fields = this.arena.alloc_from_iter(
|
||||
fields.iter().enumerate().map(|f| this.lower_field_def(f)),
|
||||
);
|
||||
let span = t.span;
|
||||
let variant_data = hir::VariantData::Struct { fields, recovered: false };
|
||||
// FIXME: capture the generics from the outer adt.
|
||||
let generics = hir::Generics::empty();
|
||||
let kind = match t.kind {
|
||||
TyKind::AnonStruct(..) => hir::ItemKind::Struct(variant_data, generics),
|
||||
TyKind::AnonUnion(..) => hir::ItemKind::Union(variant_data, generics),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
hir::OwnerNode::Item(this.arena.alloc(hir::Item {
|
||||
ident: Ident::new(kw::Empty, span),
|
||||
owner_id,
|
||||
kind,
|
||||
span: this.lower_span(span),
|
||||
vis_span: this.lower_span(span.shrink_to_lo()),
|
||||
}))
|
||||
});
|
||||
hir::TyKind::AnonAdt(hir::ItemId { owner_id })
|
||||
}
|
||||
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
|
||||
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
|
||||
@ -1426,7 +1375,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
itctx,
|
||||
// Still, don't pass along the constness here; we don't want to
|
||||
// synthesize any host effect args, it'd only cause problems.
|
||||
ast::BoundConstness::Never,
|
||||
TraitBoundModifiers {
|
||||
constness: BoundConstness::Never,
|
||||
..*modifiers
|
||||
},
|
||||
))
|
||||
}
|
||||
BoundPolarity::Maybe(_) => None,
|
||||
@ -1447,24 +1399,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
TyKind::ImplTrait(def_node_id, bounds) => {
|
||||
let span = t.span;
|
||||
match itctx {
|
||||
ImplTraitContext::ReturnPositionOpaqueTy { origin, fn_kind } => self
|
||||
.lower_opaque_impl_trait(
|
||||
span,
|
||||
*origin,
|
||||
*def_node_id,
|
||||
bounds,
|
||||
Some(*fn_kind),
|
||||
itctx,
|
||||
),
|
||||
&ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty } => self
|
||||
.lower_opaque_impl_trait(
|
||||
span,
|
||||
hir::OpaqueTyOrigin::TyAlias { in_assoc_ty },
|
||||
*def_node_id,
|
||||
bounds,
|
||||
None,
|
||||
itctx,
|
||||
),
|
||||
ImplTraitContext::OpaqueTy { origin, fn_kind } => self.lower_opaque_impl_trait(
|
||||
span,
|
||||
origin,
|
||||
*def_node_id,
|
||||
bounds,
|
||||
fn_kind,
|
||||
itctx,
|
||||
),
|
||||
ImplTraitContext::Universal => {
|
||||
let span = t.span;
|
||||
|
||||
@ -1503,9 +1445,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
.create_feature_err(
|
||||
MisplacedImplTrait {
|
||||
span: t.span,
|
||||
position: DiagnosticArgFromDisplay(position),
|
||||
position: DiagArgFromDisplay(&position),
|
||||
},
|
||||
*feature,
|
||||
feature,
|
||||
)
|
||||
.emit();
|
||||
hir::TyKind::Err(guar)
|
||||
@ -1513,7 +1455,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
ImplTraitContext::Disallowed(position) => {
|
||||
let guar = self.dcx().emit_err(MisplacedImplTrait {
|
||||
span: t.span,
|
||||
position: DiagnosticArgFromDisplay(position),
|
||||
position: DiagArgFromDisplay(&position),
|
||||
});
|
||||
hir::TyKind::Err(guar)
|
||||
}
|
||||
@ -1527,6 +1469,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
);
|
||||
hir::TyKind::Err(guar)
|
||||
}
|
||||
TyKind::Dummy => panic!("`TyKind::Dummy` should never be lowered"),
|
||||
};
|
||||
|
||||
hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.lower_node_id(t.id) }
|
||||
@ -1571,7 +1514,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
opaque_ty_node_id: NodeId,
|
||||
bounds: &GenericBounds,
|
||||
fn_kind: Option<FnDeclKind>,
|
||||
itctx: &ImplTraitContext,
|
||||
itctx: ImplTraitContext,
|
||||
) -> hir::TyKind<'hir> {
|
||||
// Make sure we know that some funky desugaring has been going on here.
|
||||
// This is a first: there is code in other places like for loop
|
||||
@ -1582,9 +1525,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
|
||||
let captured_lifetimes_to_duplicate = match origin {
|
||||
hir::OpaqueTyOrigin::TyAlias { .. } => {
|
||||
// in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't duplicate any
|
||||
// lifetimes, since we don't have the issue that any are late-bound.
|
||||
Vec::new()
|
||||
// type alias impl trait and associated type position impl trait were
|
||||
// decided to capture all in-scope lifetimes, which we collect for
|
||||
// all opaques during resolution.
|
||||
self.resolver
|
||||
.take_extra_lifetime_params(opaque_ty_node_id)
|
||||
.into_iter()
|
||||
.map(|(ident, id, _)| Lifetime { id, ident })
|
||||
.collect()
|
||||
}
|
||||
hir::OpaqueTyOrigin::FnReturn(..) => {
|
||||
if matches!(
|
||||
@ -1838,7 +1786,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::PointerParam)
|
||||
}
|
||||
};
|
||||
self.lower_ty_direct(¶m.ty, &itctx)
|
||||
self.lower_ty_direct(¶m.ty, itctx)
|
||||
}));
|
||||
|
||||
let output = match coro {
|
||||
@ -1852,9 +1800,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
FnDeclKind::Fn
|
||||
| FnDeclKind::Inherent
|
||||
| FnDeclKind::Trait
|
||||
| FnDeclKind::Impl => ImplTraitContext::ReturnPositionOpaqueTy {
|
||||
| FnDeclKind::Impl => ImplTraitContext::OpaqueTy {
|
||||
origin: hir::OpaqueTyOrigin::FnReturn(self.local_def_id(fn_node_id)),
|
||||
fn_kind: kind,
|
||||
fn_kind: Some(kind),
|
||||
},
|
||||
FnDeclKind::ExternFn => {
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::ExternFnReturn)
|
||||
@ -1866,7 +1814,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::PointerReturn)
|
||||
}
|
||||
};
|
||||
hir::FnRetTy::Return(self.lower_ty(ty, &itctx))
|
||||
hir::FnRetTy::Return(self.lower_ty(ty, itctx))
|
||||
}
|
||||
FnRetTy::Default(span) => hir::FnRetTy::DefaultReturn(self.lower_span(*span)),
|
||||
},
|
||||
@ -1948,9 +1896,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
output,
|
||||
coro,
|
||||
opaque_ty_span,
|
||||
ImplTraitContext::ReturnPositionOpaqueTy {
|
||||
ImplTraitContext::OpaqueTy {
|
||||
origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
|
||||
fn_kind,
|
||||
fn_kind: Some(fn_kind),
|
||||
},
|
||||
);
|
||||
arena_vec![this; bound]
|
||||
@ -1967,7 +1915,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
output: &FnRetTy,
|
||||
coro: CoroutineKind,
|
||||
opaque_ty_span: Span,
|
||||
nested_impl_trait_context: ImplTraitContext,
|
||||
itctx: ImplTraitContext,
|
||||
) -> hir::GenericBound<'hir> {
|
||||
// Compute the `T` in `Future<Output = T>` from the return type.
|
||||
let output_ty = match output {
|
||||
@ -1975,7 +1923,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
// Not `OpaqueTyOrigin::AsyncFn`: that's only used for the
|
||||
// `impl Future` opaque type that `async fn` implicitly
|
||||
// generates.
|
||||
self.lower_ty(ty, &nested_impl_trait_context)
|
||||
self.lower_ty(ty, itctx)
|
||||
}
|
||||
FnRetTy::Default(ret_ty_span) => self.arena.alloc(self.ty_tup(*ret_ty_span, &[])),
|
||||
};
|
||||
@ -2015,11 +1963,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
fn lower_param_bound(
|
||||
&mut self,
|
||||
tpb: &GenericBound,
|
||||
itctx: &ImplTraitContext,
|
||||
itctx: ImplTraitContext,
|
||||
) -> hir::GenericBound<'hir> {
|
||||
match tpb {
|
||||
GenericBound::Trait(p, modifiers) => hir::GenericBound::Trait(
|
||||
self.lower_poly_trait_ref(p, itctx, modifiers.constness.into()),
|
||||
self.lower_poly_trait_ref(p, itctx, *modifiers),
|
||||
self.lower_trait_bound_modifiers(*modifiers),
|
||||
),
|
||||
GenericBound::Outlives(lifetime) => {
|
||||
@ -2154,7 +2102,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
.map(|def| {
|
||||
self.lower_ty(
|
||||
def,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault),
|
||||
)
|
||||
});
|
||||
|
||||
@ -2164,7 +2112,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}
|
||||
GenericParamKind::Const { ty, kw_span: _, default } => {
|
||||
let ty = self
|
||||
.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault));
|
||||
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault));
|
||||
|
||||
// Not only do we deny const param defaults in binders but we also map them to `None`
|
||||
// since later compiler stages cannot handle them (and shouldn't need to be able to).
|
||||
@ -2192,9 +2140,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
|
||||
fn lower_trait_ref(
|
||||
&mut self,
|
||||
constness: ast::BoundConstness,
|
||||
modifiers: ast::TraitBoundModifiers,
|
||||
p: &TraitRef,
|
||||
itctx: &ImplTraitContext,
|
||||
itctx: ImplTraitContext,
|
||||
) -> hir::TraitRef<'hir> {
|
||||
let path = match self.lower_qpath(
|
||||
p.ref_id,
|
||||
@ -2202,7 +2150,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
&p.path,
|
||||
ParamMode::Explicit,
|
||||
itctx,
|
||||
Some(constness),
|
||||
Some(modifiers),
|
||||
) {
|
||||
hir::QPath::Resolved(None, path) => path,
|
||||
qpath => panic!("lower_trait_ref: unexpected QPath `{qpath:?}`"),
|
||||
@ -2214,16 +2162,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
fn lower_poly_trait_ref(
|
||||
&mut self,
|
||||
p: &PolyTraitRef,
|
||||
itctx: &ImplTraitContext,
|
||||
constness: ast::BoundConstness,
|
||||
itctx: ImplTraitContext,
|
||||
modifiers: ast::TraitBoundModifiers,
|
||||
) -> hir::PolyTraitRef<'hir> {
|
||||
let bound_generic_params =
|
||||
self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params);
|
||||
let trait_ref = self.lower_trait_ref(constness, &p.trait_ref, itctx);
|
||||
let trait_ref = self.lower_trait_ref(modifiers, &p.trait_ref, itctx);
|
||||
hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) }
|
||||
}
|
||||
|
||||
fn lower_mt(&mut self, mt: &MutTy, itctx: &ImplTraitContext) -> hir::MutTy<'hir> {
|
||||
fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> {
|
||||
hir::MutTy { ty: self.lower_ty(&mt.ty, itctx), mutbl: mt.mutbl }
|
||||
}
|
||||
|
||||
@ -2231,7 +2179,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
fn lower_param_bounds(
|
||||
&mut self,
|
||||
bounds: &[GenericBound],
|
||||
itctx: &ImplTraitContext,
|
||||
itctx: ImplTraitContext,
|
||||
) -> hir::GenericBounds<'hir> {
|
||||
self.arena.alloc_from_iter(self.lower_param_bounds_mut(bounds, itctx))
|
||||
}
|
||||
@ -2239,7 +2187,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
fn lower_param_bounds_mut<'s>(
|
||||
&'s mut self,
|
||||
bounds: &'s [GenericBound],
|
||||
itctx: &'s ImplTraitContext,
|
||||
itctx: ImplTraitContext,
|
||||
) -> impl Iterator<Item = hir::GenericBound<'hir>> + Captures<'s> + Captures<'a> {
|
||||
bounds.iter().map(move |bound| self.lower_param_bound(bound, itctx))
|
||||
}
|
||||
@ -2275,7 +2223,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
bounds,
|
||||
/* colon_span */ None,
|
||||
span,
|
||||
&ImplTraitContext::Universal,
|
||||
ImplTraitContext::Universal,
|
||||
hir::PredicateOrigin::ImplTrait,
|
||||
);
|
||||
|
||||
@ -2301,6 +2249,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
self.expr_block(block)
|
||||
}
|
||||
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen {
|
||||
match c.value.kind {
|
||||
ExprKind::Underscore => {
|
||||
@ -2392,7 +2341,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
span: self.lower_span(span),
|
||||
ty: None,
|
||||
};
|
||||
self.stmt(span, hir::StmtKind::Local(self.arena.alloc(local)))
|
||||
self.stmt(span, hir::StmtKind::Let(self.arena.alloc(local)))
|
||||
}
|
||||
|
||||
fn block_expr(&mut self, expr: &'hir hir::Expr<'hir>) -> &'hir hir::Block<'hir> {
|
||||
|
||||
@ -38,7 +38,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct");
|
||||
@ -55,7 +55,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
break hir::PatKind::Path(qpath);
|
||||
@ -66,7 +66,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
|
||||
@ -331,7 +331,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
ExprKind::Lit(..)
|
||||
| ExprKind::ConstBlock(..)
|
||||
| ExprKind::IncludedBytes(..)
|
||||
| ExprKind::Err => {}
|
||||
| ExprKind::Err(_)
|
||||
| ExprKind::Dummy => {}
|
||||
ExprKind::Path(..) if allow_paths => {}
|
||||
ExprKind::Unary(UnOp::Neg, inner) if matches!(inner.kind, ExprKind::Lit(_)) => {}
|
||||
_ => {
|
||||
|
||||
@ -1,17 +1,21 @@
|
||||
use crate::ImplTraitPosition;
|
||||
|
||||
use super::errors::{GenericTypeWithParentheses, UseAngleBrackets};
|
||||
use super::errors::{
|
||||
AsyncBoundNotOnTrait, AsyncBoundOnlyForFnTraits, GenericTypeWithParentheses, UseAngleBrackets,
|
||||
};
|
||||
use super::ResolverAstLoweringExt;
|
||||
use super::{GenericArgsCtor, LifetimeRes, ParenthesizedGenericArgs};
|
||||
use super::{ImplTraitContext, LoweringContext, ParamMode};
|
||||
|
||||
use rustc_ast::{self as ast, *};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, PartialRes, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::GenericArg;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::{BytePos, Span, DUMMY_SP};
|
||||
use rustc_span::{BytePos, DesugaringKind, Span, Symbol, DUMMY_SP};
|
||||
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
@ -23,9 +27,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
qself: &Option<ptr::P<QSelf>>,
|
||||
p: &Path,
|
||||
param_mode: ParamMode,
|
||||
itctx: &ImplTraitContext,
|
||||
// constness of the impl/bound if this is a trait path
|
||||
constness: Option<ast::BoundConstness>,
|
||||
itctx: ImplTraitContext,
|
||||
// modifiers of the impl/bound if this is a trait path
|
||||
modifiers: Option<ast::TraitBoundModifiers>,
|
||||
) -> hir::QPath<'hir> {
|
||||
let qself_position = qself.as_ref().map(|q| q.position);
|
||||
let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
|
||||
@ -35,10 +39,36 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
let base_res = partial_res.base_res();
|
||||
let unresolved_segments = partial_res.unresolved_segments();
|
||||
|
||||
let mut res = self.lower_res(base_res);
|
||||
|
||||
// When we have an `async` kw on a bound, map the trait it resolves to.
|
||||
let mut bound_modifier_allowed_features = None;
|
||||
if let Some(TraitBoundModifiers { asyncness: BoundAsyncness::Async(_), .. }) = modifiers {
|
||||
match res {
|
||||
Res::Def(DefKind::Trait, def_id) => {
|
||||
if let Some((async_def_id, features)) = self.map_trait_to_async_trait(def_id) {
|
||||
res = Res::Def(DefKind::Trait, async_def_id);
|
||||
bound_modifier_allowed_features = Some(features);
|
||||
} else {
|
||||
self.dcx().emit_err(AsyncBoundOnlyForFnTraits { span: p.span });
|
||||
}
|
||||
}
|
||||
Res::Err => {
|
||||
// No additional error.
|
||||
}
|
||||
_ => {
|
||||
// This error isn't actually emitted AFAICT, but it's best to keep
|
||||
// it around in case the resolver doesn't always check the defkind
|
||||
// of an item or something.
|
||||
self.dcx().emit_err(AsyncBoundNotOnTrait { span: p.span, descr: res.descr() });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let path_span_lo = p.span.shrink_to_lo();
|
||||
let proj_start = p.segments.len() - unresolved_segments;
|
||||
let path = self.arena.alloc(hir::Path {
|
||||
res: self.lower_res(base_res),
|
||||
res,
|
||||
segments: self.arena.alloc_from_iter(p.segments[..proj_start].iter().enumerate().map(
|
||||
|(i, segment)| {
|
||||
let param_mode = match (qself_position, param_mode) {
|
||||
@ -77,7 +107,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
parenthesized_generic_args,
|
||||
itctx,
|
||||
// if this is the last segment, add constness to the trait path
|
||||
if i == proj_start - 1 { constness } else { None },
|
||||
if i == proj_start - 1 { modifiers.map(|m| m.constness) } else { None },
|
||||
bound_modifier_allowed_features.clone(),
|
||||
)
|
||||
},
|
||||
)),
|
||||
@ -88,6 +119,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
),
|
||||
});
|
||||
|
||||
if let Some(bound_modifier_allowed_features) = bound_modifier_allowed_features {
|
||||
path.span = self.mark_span_with_reason(
|
||||
DesugaringKind::BoundModifier,
|
||||
path.span,
|
||||
Some(bound_modifier_allowed_features),
|
||||
);
|
||||
}
|
||||
|
||||
// Simple case, either no projections, or only fully-qualified.
|
||||
// E.g., `std::mem::size_of` or `<I as Iterator>::Item`.
|
||||
if unresolved_segments == 0 {
|
||||
@ -125,6 +164,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
ParenthesizedGenericArgs::Err,
|
||||
itctx,
|
||||
None,
|
||||
None,
|
||||
));
|
||||
let qpath = hir::QPath::TypeRelative(ty, hir_segment);
|
||||
|
||||
@ -156,6 +196,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
p: &Path,
|
||||
param_mode: ParamMode,
|
||||
) -> &'hir hir::UsePath<'hir> {
|
||||
assert!((1..=3).contains(&res.len()));
|
||||
self.arena.alloc(hir::UsePath {
|
||||
res,
|
||||
segments: self.arena.alloc_from_iter(p.segments.iter().map(|segment| {
|
||||
@ -164,7 +205,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
segment,
|
||||
param_mode,
|
||||
ParenthesizedGenericArgs::Err,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
})),
|
||||
@ -178,8 +220,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
segment: &PathSegment,
|
||||
param_mode: ParamMode,
|
||||
parenthesized_generic_args: ParenthesizedGenericArgs,
|
||||
itctx: &ImplTraitContext,
|
||||
itctx: ImplTraitContext,
|
||||
constness: Option<ast::BoundConstness>,
|
||||
// Additional features ungated with a bound modifier like `async`.
|
||||
// This is passed down to the implicit associated type binding in
|
||||
// parenthesized bounds.
|
||||
bound_modifier_allowed_features: Option<Lrc<[Symbol]>>,
|
||||
) -> hir::PathSegment<'hir> {
|
||||
debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment);
|
||||
let (mut generic_args, infer_args) = if let Some(generic_args) = segment.args.as_deref() {
|
||||
@ -188,9 +234,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
|
||||
}
|
||||
GenericArgs::Parenthesized(data) => match parenthesized_generic_args {
|
||||
ParenthesizedGenericArgs::ParenSugar => {
|
||||
self.lower_parenthesized_parameter_data(data, itctx)
|
||||
}
|
||||
ParenthesizedGenericArgs::ParenSugar => self
|
||||
.lower_parenthesized_parameter_data(
|
||||
data,
|
||||
itctx,
|
||||
bound_modifier_allowed_features,
|
||||
),
|
||||
ParenthesizedGenericArgs::Err => {
|
||||
// Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait<params...>`
|
||||
let sub = if !data.inputs.is_empty() {
|
||||
@ -325,7 +374,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
&mut self,
|
||||
data: &AngleBracketedArgs,
|
||||
param_mode: ParamMode,
|
||||
itctx: &ImplTraitContext,
|
||||
itctx: ImplTraitContext,
|
||||
) -> (GenericArgsCtor<'hir>, bool) {
|
||||
let has_non_lt_args = data.args.iter().any(|arg| match arg {
|
||||
AngleBracketedArg::Arg(ast::GenericArg::Lifetime(_))
|
||||
@ -356,7 +405,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
fn lower_parenthesized_parameter_data(
|
||||
&mut self,
|
||||
data: &ParenthesizedArgs,
|
||||
itctx: &ImplTraitContext,
|
||||
itctx: ImplTraitContext,
|
||||
bound_modifier_allowed_features: Option<Lrc<[Symbol]>>,
|
||||
) -> (GenericArgsCtor<'hir>, bool) {
|
||||
// Switch to `PassThrough` mode for anonymous lifetimes; this
|
||||
// means that we permit things like `&Ref<T>`, where `Ref` has
|
||||
@ -365,7 +415,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
// we generally don't permit such things (see #51008).
|
||||
let ParenthesizedArgs { span, inputs, inputs_span, output } = data;
|
||||
let inputs = self.arena.alloc_from_iter(inputs.iter().map(|ty| {
|
||||
self.lower_ty_direct(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam))
|
||||
self.lower_ty_direct(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam))
|
||||
}));
|
||||
let output_ty = match output {
|
||||
// Only allow `impl Trait` in return position. i.e.:
|
||||
@ -373,13 +423,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
// fn f(_: impl Fn() -> impl Debug) -> impl Fn() -> impl Debug
|
||||
// // disallowed --^^^^^^^^^^ allowed --^^^^^^^^^^
|
||||
// ```
|
||||
FnRetTy::Ty(ty) if matches!(itctx, ImplTraitContext::ReturnPositionOpaqueTy { .. }) => {
|
||||
FnRetTy::Ty(ty) if matches!(itctx, ImplTraitContext::OpaqueTy { .. }) => {
|
||||
if self.tcx.features().impl_trait_in_fn_trait_return {
|
||||
self.lower_ty(ty, itctx)
|
||||
} else {
|
||||
self.lower_ty(
|
||||
ty,
|
||||
&ImplTraitContext::FeatureGated(
|
||||
ImplTraitContext::FeatureGated(
|
||||
ImplTraitPosition::FnTraitReturn,
|
||||
sym::impl_trait_in_fn_trait_return,
|
||||
),
|
||||
@ -387,12 +437,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}
|
||||
}
|
||||
FnRetTy::Ty(ty) => {
|
||||
self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn))
|
||||
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn))
|
||||
}
|
||||
FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])),
|
||||
};
|
||||
let args = smallvec![GenericArg::Type(self.arena.alloc(self.ty_tup(*inputs_span, inputs)))];
|
||||
let binding = self.assoc_ty_binding(sym::Output, output_ty.span, output_ty);
|
||||
|
||||
// If we have a bound like `async Fn() -> T`, make sure that we mark the
|
||||
// `Output = T` associated type bound with the right feature gates.
|
||||
let mut output_span = output_ty.span;
|
||||
if let Some(bound_modifier_allowed_features) = bound_modifier_allowed_features {
|
||||
output_span = self.mark_span_with_reason(
|
||||
DesugaringKind::BoundModifier,
|
||||
output_span,
|
||||
Some(bound_modifier_allowed_features),
|
||||
);
|
||||
}
|
||||
let binding = self.assoc_ty_binding(sym::Output, output_span, output_ty);
|
||||
|
||||
(
|
||||
GenericArgsCtor {
|
||||
args,
|
||||
@ -429,4 +491,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
kind,
|
||||
}
|
||||
}
|
||||
|
||||
/// When a bound is annotated with `async`, it signals to lowering that the trait
|
||||
/// that the bound refers to should be mapped to the "async" flavor of the trait.
|
||||
///
|
||||
/// This only needs to be done until we unify `AsyncFn` and `Fn` traits into one
|
||||
/// that is generic over `async`ness, if that's ever possible, or modify the
|
||||
/// lowering of `async Fn()` bounds to desugar to another trait like `LendingFn`.
|
||||
fn map_trait_to_async_trait(&self, def_id: DefId) -> Option<(DefId, Lrc<[Symbol]>)> {
|
||||
let lang_items = self.tcx.lang_items();
|
||||
if Some(def_id) == lang_items.fn_trait() {
|
||||
Some((lang_items.async_fn_trait()?, self.allow_async_fn_traits.clone()))
|
||||
} else if Some(def_id) == lang_items.fn_mut_trait() {
|
||||
Some((lang_items.async_fn_mut_trait()?, self.allow_async_fn_traits.clone()))
|
||||
} else if Some(def_id) == lang_items.fn_once_trait() {
|
||||
Some((lang_items.async_fn_once_trait()?, self.allow_async_fn_traits.clone()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
itertools = "0.11"
|
||||
itertools = "0.12"
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
|
||||
rustc_attr = { path = "../rustc_attr" }
|
||||
|
||||
@ -280,4 +280,5 @@ ast_passes_where_clause_after_type_alias = where clauses are not allowed after t
|
||||
|
||||
ast_passes_where_clause_before_type_alias = where clauses are not allowed before the type for type aliases
|
||||
.note = see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
|
||||
.suggestion = move it to the end of the type declaration
|
||||
.remove_suggestion = remove this `where`
|
||||
.move_suggestion = move it to the end of the type declaration
|
||||
|
||||
@ -8,8 +8,7 @@
|
||||
|
||||
use itertools::{Either, Itertools};
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::visit::{AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
|
||||
use rustc_ast::walk_list;
|
||||
use rustc_ast::visit::{walk_list, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
|
||||
use rustc_ast::*;
|
||||
use rustc_ast_pretty::pprust::{self, State};
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
@ -18,7 +17,7 @@ use rustc_parse::validate_attr;
|
||||
use rustc_session::lint::builtin::{
|
||||
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY,
|
||||
};
|
||||
use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
|
||||
use rustc_session::lint::{BuiltinLintDiag, LintBuffer};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::Span;
|
||||
@ -138,38 +137,42 @@ impl<'a> AstValidator<'a> {
|
||||
&mut self,
|
||||
ty_alias: &TyAlias,
|
||||
) -> Result<(), errors::WhereClauseBeforeTypeAlias> {
|
||||
let before_predicates =
|
||||
ty_alias.generics.where_clause.predicates.split_at(ty_alias.where_predicates_split).0;
|
||||
|
||||
if ty_alias.ty.is_none() || before_predicates.is_empty() {
|
||||
if ty_alias.ty.is_none() || !ty_alias.where_clauses.before.has_where_token {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut state = State::new();
|
||||
if !ty_alias.where_clauses.1.0 {
|
||||
state.space();
|
||||
state.word_space("where");
|
||||
} else {
|
||||
state.word_space(",");
|
||||
}
|
||||
let mut first = true;
|
||||
for p in before_predicates {
|
||||
if !first {
|
||||
state.word_space(",");
|
||||
}
|
||||
first = false;
|
||||
state.print_where_predicate(p);
|
||||
}
|
||||
let (before_predicates, after_predicates) =
|
||||
ty_alias.generics.where_clause.predicates.split_at(ty_alias.where_clauses.split);
|
||||
let span = ty_alias.where_clauses.before.span;
|
||||
|
||||
let span = ty_alias.where_clauses.0.1;
|
||||
Err(errors::WhereClauseBeforeTypeAlias {
|
||||
span,
|
||||
sugg: errors::WhereClauseBeforeTypeAliasSugg {
|
||||
let sugg = if !before_predicates.is_empty() || !ty_alias.where_clauses.after.has_where_token
|
||||
{
|
||||
let mut state = State::new();
|
||||
|
||||
if !ty_alias.where_clauses.after.has_where_token {
|
||||
state.space();
|
||||
state.word_space("where");
|
||||
}
|
||||
|
||||
let mut first = after_predicates.is_empty();
|
||||
for p in before_predicates {
|
||||
if !first {
|
||||
state.word_space(",");
|
||||
}
|
||||
first = false;
|
||||
state.print_where_predicate(p);
|
||||
}
|
||||
|
||||
errors::WhereClauseBeforeTypeAliasSugg::Move {
|
||||
left: span,
|
||||
snippet: state.s.eof(),
|
||||
right: ty_alias.where_clauses.1.1.shrink_to_hi(),
|
||||
},
|
||||
})
|
||||
right: ty_alias.where_clauses.after.span.shrink_to_hi(),
|
||||
}
|
||||
} else {
|
||||
errors::WhereClauseBeforeTypeAliasSugg::Remove { span }
|
||||
};
|
||||
|
||||
Err(errors::WhereClauseBeforeTypeAlias { span, sugg })
|
||||
}
|
||||
|
||||
fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
|
||||
@ -219,8 +222,8 @@ impl<'a> AstValidator<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
TyKind::AnonStruct(ref fields, ..) | TyKind::AnonUnion(ref fields, ..) => {
|
||||
walk_list!(self, visit_field_def, fields)
|
||||
TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => {
|
||||
walk_list!(self, visit_struct_field_def, fields)
|
||||
}
|
||||
_ => visit::walk_ty(self, t),
|
||||
}
|
||||
@ -457,8 +460,7 @@ impl<'a> AstValidator<'a> {
|
||||
fn check_foreign_ty_genericless(
|
||||
&self,
|
||||
generics: &Generics,
|
||||
before_where_clause: &TyAliasWhereClause,
|
||||
after_where_clause: &TyAliasWhereClause,
|
||||
where_clauses: &TyAliasWhereClauses,
|
||||
) {
|
||||
let cannot_have = |span, descr, remove_descr| {
|
||||
self.dcx().emit_err(errors::ExternTypesCannotHave {
|
||||
@ -473,14 +475,14 @@ impl<'a> AstValidator<'a> {
|
||||
cannot_have(generics.span, "generic parameters", "generic parameters");
|
||||
}
|
||||
|
||||
let check_where_clause = |where_clause: &TyAliasWhereClause| {
|
||||
if let TyAliasWhereClause(true, where_clause_span) = where_clause {
|
||||
cannot_have(*where_clause_span, "`where` clauses", "`where` clause");
|
||||
let check_where_clause = |where_clause: TyAliasWhereClause| {
|
||||
if where_clause.has_where_token {
|
||||
cannot_have(where_clause.span, "`where` clauses", "`where` clause");
|
||||
}
|
||||
};
|
||||
|
||||
check_where_clause(before_where_clause);
|
||||
check_where_clause(after_where_clause);
|
||||
check_where_clause(where_clauses.before);
|
||||
check_where_clause(where_clauses.after);
|
||||
}
|
||||
|
||||
fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
|
||||
@ -747,7 +749,7 @@ impl<'a> AstValidator<'a> {
|
||||
id,
|
||||
span,
|
||||
fluent::ast_passes_extern_without_abi,
|
||||
BuiltinLintDiagnostics::MissingAbi(span, abi::Abi::FALLBACK),
|
||||
BuiltinLintDiag::MissingAbi(span, abi::Abi::FALLBACK),
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -832,7 +834,7 @@ fn validate_generic_param_order(
|
||||
|
||||
impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
fn visit_attribute(&mut self, attr: &Attribute) {
|
||||
validate_attr::check_attr(&self.session.parse_sess, attr);
|
||||
validate_attr::check_attr(&self.session.psess, attr);
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, ty: &'a Ty) {
|
||||
@ -881,8 +883,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
&item.vis,
|
||||
errors::VisibilityNotPermittedNote::TraitImpl,
|
||||
);
|
||||
if let TyKind::Err = self_ty.kind {
|
||||
this.dcx().emit_err(errors::ObsoleteAuto { span: item.span });
|
||||
if let TyKind::Dummy = self_ty.kind {
|
||||
// Abort immediately otherwise the `TyKind::Dummy` will reach HIR lowering,
|
||||
// which isn't allowed. Not a problem for this obscure, obsolete syntax.
|
||||
this.dcx().emit_fatal(errors::ObsoleteAuto { span: item.span });
|
||||
}
|
||||
if let (&Unsafe::Yes(span), &ImplPolarity::Negative(sp)) = (unsafety, polarity)
|
||||
{
|
||||
@ -1123,9 +1127,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
if let Err(err) = self.check_type_alias_where_clause_location(ty_alias) {
|
||||
self.dcx().emit_err(err);
|
||||
}
|
||||
} else if where_clauses.1.0 {
|
||||
} else if where_clauses.after.has_where_token {
|
||||
self.dcx().emit_err(errors::WhereClauseAfterTypeAlias {
|
||||
span: where_clauses.1.1,
|
||||
span: where_clauses.after.span,
|
||||
help: self.session.is_nightly_build().then_some(()),
|
||||
});
|
||||
}
|
||||
@ -1155,7 +1159,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
self.check_defaultness(fi.span, *defaultness);
|
||||
self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span));
|
||||
self.check_type_no_bounds(bounds, "`extern` blocks");
|
||||
self.check_foreign_ty_genericless(generics, &where_clauses.0, &where_clauses.1);
|
||||
self.check_foreign_ty_genericless(generics, where_clauses);
|
||||
self.check_foreign_item_ascii_only(fi.ident);
|
||||
}
|
||||
ForeignItemKind::Static(_, _, body) => {
|
||||
@ -1406,7 +1410,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
FnCtxt::Foreign => fluent::ast_passes_pattern_in_foreign,
|
||||
_ => fluent::ast_passes_pattern_in_bodiless,
|
||||
};
|
||||
let diag = BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident);
|
||||
let diag = BuiltinLintDiag::PatternsInFnsWithoutBody(span, ident);
|
||||
self.lint_buffer.buffer_lint_with_diagnostic(
|
||||
PATTERNS_IN_FNS_WITHOUT_BODY,
|
||||
id,
|
||||
@ -1478,15 +1482,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
if let AssocItemKind::Type(ty_alias) = &item.kind
|
||||
&& let Err(err) = self.check_type_alias_where_clause_location(ty_alias)
|
||||
{
|
||||
let sugg = match err.sugg {
|
||||
errors::WhereClauseBeforeTypeAliasSugg::Remove { .. } => None,
|
||||
errors::WhereClauseBeforeTypeAliasSugg::Move { snippet, right, .. } => {
|
||||
Some((right, snippet))
|
||||
}
|
||||
};
|
||||
self.lint_buffer.buffer_lint_with_diagnostic(
|
||||
DEPRECATED_WHERE_CLAUSE_LOCATION,
|
||||
item.id,
|
||||
err.span,
|
||||
fluent::ast_passes_deprecated_where_clause_location,
|
||||
BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
|
||||
err.sugg.right,
|
||||
err.sugg.snippet,
|
||||
),
|
||||
BuiltinLintDiag::DeprecatedWhereclauseLocation(sugg),
|
||||
);
|
||||
}
|
||||
|
||||
@ -1520,6 +1527,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
generics,
|
||||
body.as_deref(),
|
||||
);
|
||||
walk_list!(self, visit_attribute, &item.attrs);
|
||||
self.visit_fn(kind, item.span, item.id);
|
||||
}
|
||||
AssocItemKind::Type(_) => {
|
||||
@ -1596,44 +1604,98 @@ fn deny_equality_constraints(
|
||||
}
|
||||
}
|
||||
}
|
||||
// Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
|
||||
if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
|
||||
if let [potential_param, potential_assoc] = &full_path.segments[..] {
|
||||
for param in &generics.params {
|
||||
if param.ident == potential_param.ident {
|
||||
for bound in ¶m.bounds {
|
||||
if let ast::GenericBound::Trait(trait_ref, TraitBoundModifiers::NONE) =
|
||||
bound
|
||||
|
||||
let mut suggest =
|
||||
|poly: &PolyTraitRef, potential_assoc: &PathSegment, predicate: &WhereEqPredicate| {
|
||||
if let [trait_segment] = &poly.trait_ref.path.segments[..] {
|
||||
let assoc = pprust::path_to_string(&ast::Path::from_ident(potential_assoc.ident));
|
||||
let ty = pprust::ty_to_string(&predicate.rhs_ty);
|
||||
let (args, span) = match &trait_segment.args {
|
||||
Some(args) => match args.deref() {
|
||||
ast::GenericArgs::AngleBracketed(args) => {
|
||||
let Some(arg) = args.args.last() else {
|
||||
return;
|
||||
};
|
||||
(format!(", {assoc} = {ty}"), arg.span().shrink_to_hi())
|
||||
}
|
||||
_ => return,
|
||||
},
|
||||
None => (format!("<{assoc} = {ty}>"), trait_segment.span().shrink_to_hi()),
|
||||
};
|
||||
let removal_span = if generics.where_clause.predicates.len() == 1 {
|
||||
// We're removing th eonly where bound left, remove the whole thing.
|
||||
generics.where_clause.span
|
||||
} else {
|
||||
let mut span = predicate.span;
|
||||
let mut prev: Option<Span> = None;
|
||||
let mut preds = generics.where_clause.predicates.iter().peekable();
|
||||
// Find the predicate that shouldn't have been in the where bound list.
|
||||
while let Some(pred) = preds.next() {
|
||||
if let WherePredicate::EqPredicate(pred) = pred
|
||||
&& pred.span == predicate.span
|
||||
{
|
||||
if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] {
|
||||
let assoc = pprust::path_to_string(&ast::Path::from_ident(
|
||||
potential_assoc.ident,
|
||||
));
|
||||
let ty = pprust::ty_to_string(&predicate.rhs_ty);
|
||||
let (args, span) = match &trait_segment.args {
|
||||
Some(args) => match args.deref() {
|
||||
ast::GenericArgs::AngleBracketed(args) => {
|
||||
let Some(arg) = args.args.last() else {
|
||||
continue;
|
||||
};
|
||||
(format!(", {assoc} = {ty}"), arg.span().shrink_to_hi())
|
||||
}
|
||||
_ => continue,
|
||||
},
|
||||
None => (
|
||||
format!("<{assoc} = {ty}>"),
|
||||
trait_segment.span().shrink_to_hi(),
|
||||
),
|
||||
};
|
||||
err.assoc2 = Some(errors::AssociatedSuggestion2 {
|
||||
span,
|
||||
args,
|
||||
predicate: predicate.span,
|
||||
trait_segment: trait_segment.ident,
|
||||
potential_assoc: potential_assoc.ident,
|
||||
});
|
||||
if let Some(next) = preds.peek() {
|
||||
// This is the first predicate, remove the trailing comma as well.
|
||||
span = span.with_hi(next.span().lo());
|
||||
} else if let Some(prev) = prev {
|
||||
// Remove the previous comma as well.
|
||||
span = span.with_lo(prev.hi());
|
||||
}
|
||||
}
|
||||
prev = Some(pred.span());
|
||||
}
|
||||
span
|
||||
};
|
||||
err.assoc2 = Some(errors::AssociatedSuggestion2 {
|
||||
span,
|
||||
args,
|
||||
predicate: removal_span,
|
||||
trait_segment: trait_segment.ident,
|
||||
potential_assoc: potential_assoc.ident,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
|
||||
// Given `A: Foo, Foo::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
|
||||
for bounds in generics.params.iter().map(|p| &p.bounds).chain(
|
||||
generics.where_clause.predicates.iter().filter_map(|pred| match pred {
|
||||
WherePredicate::BoundPredicate(p) => Some(&p.bounds),
|
||||
_ => None,
|
||||
}),
|
||||
) {
|
||||
for bound in bounds {
|
||||
if let GenericBound::Trait(poly, TraitBoundModifiers::NONE) = bound {
|
||||
if full_path.segments[..full_path.segments.len() - 1]
|
||||
.iter()
|
||||
.map(|segment| segment.ident.name)
|
||||
.zip(poly.trait_ref.path.segments.iter().map(|segment| segment.ident.name))
|
||||
.all(|(a, b)| a == b)
|
||||
&& let Some(potential_assoc) = full_path.segments.iter().last()
|
||||
{
|
||||
suggest(poly, potential_assoc, predicate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
|
||||
if let [potential_param, potential_assoc] = &full_path.segments[..] {
|
||||
for (ident, bounds) in generics.params.iter().map(|p| (p.ident, &p.bounds)).chain(
|
||||
generics.where_clause.predicates.iter().filter_map(|pred| match pred {
|
||||
WherePredicate::BoundPredicate(p)
|
||||
if let ast::TyKind::Path(None, path) = &p.bounded_ty.kind
|
||||
&& let [segment] = &path.segments[..] =>
|
||||
{
|
||||
Some((segment.ident, &p.bounds))
|
||||
}
|
||||
_ => None,
|
||||
}),
|
||||
) {
|
||||
if ident == potential_param.ident {
|
||||
for bound in bounds {
|
||||
if let ast::GenericBound::Trait(poly, TraitBoundModifiers::NONE) = bound {
|
||||
suggest(poly, potential_assoc, predicate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
//! Errors emitted by ast_passes.
|
||||
|
||||
use rustc_ast::ParamKindOrd;
|
||||
use rustc_errors::{codes::*, AddToDiagnostic, Applicability};
|
||||
use rustc_errors::{
|
||||
codes::*, Applicability, Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic,
|
||||
};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_span::{symbol::Ident, Span, Symbol};
|
||||
|
||||
@ -371,14 +373,12 @@ pub struct ArgsBeforeConstraint {
|
||||
pub struct EmptyLabelManySpans(pub Vec<Span>);
|
||||
|
||||
// The derive for `Vec<Span>` does multiple calls to `span_label`, adding commas between each
|
||||
impl AddToDiagnostic for EmptyLabelManySpans {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(
|
||||
&mut rustc_errors::Diagnostic,
|
||||
rustc_errors::SubdiagnosticMessage,
|
||||
) -> rustc_errors::SubdiagnosticMessage,
|
||||
{
|
||||
impl Subdiagnostic for EmptyLabelManySpans {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_: F,
|
||||
) {
|
||||
diag.span_labels(self.0, "");
|
||||
}
|
||||
}
|
||||
@ -515,17 +515,25 @@ pub struct WhereClauseBeforeTypeAlias {
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
ast_passes_suggestion,
|
||||
applicability = "machine-applicable",
|
||||
style = "verbose"
|
||||
)]
|
||||
pub struct WhereClauseBeforeTypeAliasSugg {
|
||||
#[suggestion_part(code = "")]
|
||||
pub left: Span,
|
||||
pub snippet: String,
|
||||
#[suggestion_part(code = "{snippet}")]
|
||||
pub right: Span,
|
||||
|
||||
pub enum WhereClauseBeforeTypeAliasSugg {
|
||||
#[suggestion(ast_passes_remove_suggestion, applicability = "machine-applicable", code = "")]
|
||||
Remove {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[multipart_suggestion(
|
||||
ast_passes_move_suggestion,
|
||||
applicability = "machine-applicable",
|
||||
style = "verbose"
|
||||
)]
|
||||
Move {
|
||||
#[suggestion_part(code = "")]
|
||||
left: Span,
|
||||
snippet: String,
|
||||
#[suggestion_part(code = "{snippet}")]
|
||||
right: Span,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
@ -734,14 +742,12 @@ pub struct StableFeature {
|
||||
pub since: Symbol,
|
||||
}
|
||||
|
||||
impl AddToDiagnostic for StableFeature {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
|
||||
where
|
||||
F: Fn(
|
||||
&mut rustc_errors::Diagnostic,
|
||||
rustc_errors::SubdiagnosticMessage,
|
||||
) -> rustc_errors::SubdiagnosticMessage,
|
||||
{
|
||||
impl Subdiagnostic for StableFeature {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_: F,
|
||||
) {
|
||||
diag.arg("name", self.name);
|
||||
diag.arg("since", self.since);
|
||||
diag.help(fluent::ast_passes_stable_since);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
|
||||
use rustc_ast::{attr, AssocConstraint, AssocConstraintKind, NodeId};
|
||||
use rustc_ast::{PatKind, RangeEnd};
|
||||
use rustc_ast::{token, PatKind, RangeEnd};
|
||||
use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP};
|
||||
use rustc_session::parse::{feature_err, feature_err_issue, feature_warn};
|
||||
use rustc_session::Session;
|
||||
@ -17,11 +17,15 @@ use crate::errors;
|
||||
macro_rules! gate {
|
||||
($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{
|
||||
if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) {
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
feature_err(&$visitor.sess, sym::$feature, $span, $explain).emit();
|
||||
}
|
||||
}};
|
||||
($visitor:expr, $feature:ident, $span:expr, $explain:expr, $help:expr) => {{
|
||||
if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) {
|
||||
// FIXME: make this translatable
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
feature_err(&$visitor.sess, sym::$feature, $span, $explain).with_help($help).emit();
|
||||
}
|
||||
}};
|
||||
@ -31,6 +35,7 @@ macro_rules! gate {
|
||||
macro_rules! gate_alt {
|
||||
($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr) => {{
|
||||
if !$has_feature && !$span.allows_unstable($name) {
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
feature_err(&$visitor.sess, $name, $span, $explain).emit();
|
||||
}
|
||||
}};
|
||||
@ -70,6 +75,7 @@ struct PostExpansionVisitor<'a> {
|
||||
}
|
||||
|
||||
impl<'a> PostExpansionVisitor<'a> {
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
fn check_abi(&self, abi: ast::StrLit, constness: ast::Const) {
|
||||
let ast::StrLit { symbol_unescaped, span, .. } = abi;
|
||||
|
||||
@ -200,14 +206,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
);
|
||||
}
|
||||
}
|
||||
if !attr.is_doc_comment()
|
||||
&& let [seg, _] = attr.get_normal_item().path.segments.as_slice()
|
||||
&& seg.ident.name == sym::diagnostic
|
||||
&& !self.features.diagnostic_namespace
|
||||
{
|
||||
let msg = "`#[diagnostic]` attribute name space is experimental";
|
||||
gate!(self, diagnostic_namespace, seg.ident.span, msg);
|
||||
}
|
||||
|
||||
// Emit errors for non-staged-api crates.
|
||||
if !self.features.staged_api {
|
||||
@ -380,6 +378,17 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
ast::ExprKind::TryBlock(_) => {
|
||||
gate!(&self, try_blocks, e.span, "`try` expression is experimental");
|
||||
}
|
||||
ast::ExprKind::Lit(token::Lit { kind: token::LitKind::Float, suffix, .. }) => {
|
||||
match suffix {
|
||||
Some(sym::f16) => {
|
||||
gate!(&self, f16, e.span, "the type `f16` is unstable")
|
||||
}
|
||||
Some(sym::f128) => {
|
||||
gate!(&self, f128, e.span, "the type `f128` is unstable")
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
visit::walk_expr(self, e)
|
||||
@ -504,7 +513,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||
check_incompatible_features(sess, features);
|
||||
let mut visitor = PostExpansionVisitor { sess, features };
|
||||
|
||||
let spans = sess.parse_sess.gated_spans.spans.borrow();
|
||||
let spans = sess.psess.gated_spans.spans.borrow();
|
||||
macro_rules! gate_all {
|
||||
($gate:ident, $msg:literal) => {
|
||||
if let Some(spans) = spans.get(&sym::$gate) {
|
||||
@ -576,6 +585,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||
if let Ok(snippet) = sm.span_to_snippet(span)
|
||||
&& snippet == "!"
|
||||
{
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
feature_err(sess, sym::never_patterns, span, "`!` patterns are experimental")
|
||||
.emit();
|
||||
} else {
|
||||
|
||||
@ -11,8 +11,6 @@
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(iter_is_partitioned)]
|
||||
#![feature(let_chains)]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
||||
pub mod ast_validation;
|
||||
mod errors;
|
||||
|
||||
@ -5,8 +5,9 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
itertools = "0.11"
|
||||
itertools = "0.12"
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_lexer = { path = "../rustc_lexer" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
thin-vec = "0.2.12"
|
||||
# tidy-alphabetical-end
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
#![allow(internal_features)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![doc(rust_logo)]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
#![feature(box_patterns)]
|
||||
|
||||
mod helpers;
|
||||
|
||||
@ -8,12 +8,13 @@ mod item;
|
||||
use crate::pp::Breaks::{Consistent, Inconsistent};
|
||||
use crate::pp::{self, Breaks};
|
||||
use crate::pprust::state::expr::FixupContext;
|
||||
use ast::TraitBoundModifiers;
|
||||
use rustc_ast::attr::AttrIdGenerator;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, BinOpToken, CommentKind, Delimiter, Nonterminal, Token, TokenKind};
|
||||
use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree};
|
||||
use rustc_ast::util::classify;
|
||||
use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle};
|
||||
use rustc_ast::util::comments::{Comment, CommentStyle};
|
||||
use rustc_ast::util::parser;
|
||||
use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, BlockCheckMode, PatKind};
|
||||
use rustc_ast::{attr, BindingAnnotation, ByRef, DelimArgs, RangeEnd, RangeSyntax, Term};
|
||||
@ -23,7 +24,7 @@ use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::source_map::{SourceMap, Spanned};
|
||||
use rustc_span::symbol::{kw, sym, Ident, IdentPrinter, Symbol};
|
||||
use rustc_span::{BytePos, FileName, Span, DUMMY_SP};
|
||||
use rustc_span::{BytePos, CharPos, FileName, Pos, Span, DUMMY_SP};
|
||||
use std::borrow::Cow;
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
@ -58,6 +59,127 @@ pub struct Comments<'a> {
|
||||
current: usize,
|
||||
}
|
||||
|
||||
/// Returns `None` if the first `col` chars of `s` contain a non-whitespace char.
|
||||
/// Otherwise returns `Some(k)` where `k` is first char offset after that leading
|
||||
/// whitespace. Note that `k` may be outside bounds of `s`.
|
||||
fn all_whitespace(s: &str, col: CharPos) -> Option<usize> {
|
||||
let mut idx = 0;
|
||||
for (i, ch) in s.char_indices().take(col.to_usize()) {
|
||||
if !ch.is_whitespace() {
|
||||
return None;
|
||||
}
|
||||
idx = i + ch.len_utf8();
|
||||
}
|
||||
Some(idx)
|
||||
}
|
||||
|
||||
fn trim_whitespace_prefix(s: &str, col: CharPos) -> &str {
|
||||
let len = s.len();
|
||||
match all_whitespace(s, col) {
|
||||
Some(col) => {
|
||||
if col < len {
|
||||
&s[col..]
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
None => s,
|
||||
}
|
||||
}
|
||||
|
||||
fn split_block_comment_into_lines(text: &str, col: CharPos) -> Vec<String> {
|
||||
let mut res: Vec<String> = vec![];
|
||||
let mut lines = text.lines();
|
||||
// just push the first line
|
||||
res.extend(lines.next().map(|it| it.to_string()));
|
||||
// for other lines, strip common whitespace prefix
|
||||
for line in lines {
|
||||
res.push(trim_whitespace_prefix(line, col).to_string())
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comment> {
|
||||
let sm = SourceMap::new(sm.path_mapping().clone());
|
||||
let source_file = sm.new_source_file(path, src);
|
||||
let text = (*source_file.src.as_ref().unwrap()).clone();
|
||||
|
||||
let text: &str = text.as_str();
|
||||
let start_bpos = source_file.start_pos;
|
||||
let mut pos = 0;
|
||||
let mut comments: Vec<Comment> = Vec::new();
|
||||
let mut code_to_the_left = false;
|
||||
|
||||
if let Some(shebang_len) = rustc_lexer::strip_shebang(text) {
|
||||
comments.push(Comment {
|
||||
style: CommentStyle::Isolated,
|
||||
lines: vec![text[..shebang_len].to_string()],
|
||||
pos: start_bpos,
|
||||
});
|
||||
pos += shebang_len;
|
||||
}
|
||||
|
||||
for token in rustc_lexer::tokenize(&text[pos..]) {
|
||||
let token_text = &text[pos..pos + token.len as usize];
|
||||
match token.kind {
|
||||
rustc_lexer::TokenKind::Whitespace => {
|
||||
if let Some(mut idx) = token_text.find('\n') {
|
||||
code_to_the_left = false;
|
||||
while let Some(next_newline) = &token_text[idx + 1..].find('\n') {
|
||||
idx += 1 + next_newline;
|
||||
comments.push(Comment {
|
||||
style: CommentStyle::BlankLine,
|
||||
lines: vec![],
|
||||
pos: start_bpos + BytePos((pos + idx) as u32),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
rustc_lexer::TokenKind::BlockComment { doc_style, .. } => {
|
||||
if doc_style.is_none() {
|
||||
let code_to_the_right = !matches!(
|
||||
text[pos + token.len as usize..].chars().next(),
|
||||
Some('\r' | '\n')
|
||||
);
|
||||
let style = match (code_to_the_left, code_to_the_right) {
|
||||
(_, true) => CommentStyle::Mixed,
|
||||
(false, false) => CommentStyle::Isolated,
|
||||
(true, false) => CommentStyle::Trailing,
|
||||
};
|
||||
|
||||
// Count the number of chars since the start of the line by rescanning.
|
||||
let pos_in_file = start_bpos + BytePos(pos as u32);
|
||||
let line_begin_in_file = source_file.line_begin_pos(pos_in_file);
|
||||
let line_begin_pos = (line_begin_in_file - start_bpos).to_usize();
|
||||
let col = CharPos(text[line_begin_pos..pos].chars().count());
|
||||
|
||||
let lines = split_block_comment_into_lines(token_text, col);
|
||||
comments.push(Comment { style, lines, pos: pos_in_file })
|
||||
}
|
||||
}
|
||||
rustc_lexer::TokenKind::LineComment { doc_style } => {
|
||||
if doc_style.is_none() {
|
||||
comments.push(Comment {
|
||||
style: if code_to_the_left {
|
||||
CommentStyle::Trailing
|
||||
} else {
|
||||
CommentStyle::Isolated
|
||||
},
|
||||
lines: vec![token_text.to_string()],
|
||||
pos: start_bpos + BytePos(pos as u32),
|
||||
})
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
code_to_the_left = true;
|
||||
}
|
||||
}
|
||||
pos += token.len as usize;
|
||||
}
|
||||
|
||||
comments
|
||||
}
|
||||
|
||||
impl<'a> Comments<'a> {
|
||||
pub fn new(sm: &'a SourceMap, filename: FileName, input: String) -> Comments<'a> {
|
||||
let comments = gather_comments(sm, filename, input);
|
||||
@ -184,7 +306,7 @@ fn space_between(tt1: &TokenTree, tt2: &TokenTree) -> bool {
|
||||
|
||||
// IDENT + `!`: `println!()`, but `if !x { ... }` needs a space after the `if`
|
||||
(Tok(Token { kind: Ident(sym, is_raw), span }, _), Tok(Token { kind: Not, .. }, _))
|
||||
if !Ident::new(*sym, *span).is_reserved() || *is_raw =>
|
||||
if !Ident::new(*sym, *span).is_reserved() || matches!(is_raw, IdentIsRaw::Yes) =>
|
||||
{
|
||||
false
|
||||
}
|
||||
@ -196,7 +318,7 @@ fn space_between(tt1: &TokenTree, tt2: &TokenTree) -> bool {
|
||||
|| *sym == kw::Fn
|
||||
|| *sym == kw::SelfUpper
|
||||
|| *sym == kw::Pub
|
||||
|| *is_raw =>
|
||||
|| matches!(is_raw, IdentIsRaw::Yes) =>
|
||||
{
|
||||
false
|
||||
}
|
||||
@ -253,7 +375,7 @@ fn literal_to_string(lit: token::Lit) -> String {
|
||||
token::CStrRaw(n) => {
|
||||
format!("cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize))
|
||||
}
|
||||
token::Integer | token::Float | token::Bool | token::Err => symbol.to_string(),
|
||||
token::Integer | token::Float | token::Bool | token::Err(_) => symbol.to_string(),
|
||||
};
|
||||
|
||||
if let Some(suffix) = suffix {
|
||||
@ -730,7 +852,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
||||
token::NtBlock(e) => self.block_to_string(e),
|
||||
token::NtStmt(e) => self.stmt_to_string(e),
|
||||
token::NtPat(e) => self.pat_to_string(e),
|
||||
token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(*e, *is_raw).to_string(),
|
||||
&token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(e, is_raw.into()).to_string(),
|
||||
token::NtLifetime(e) => e.to_string(),
|
||||
token::NtLiteral(e) => self.expr_to_string(e),
|
||||
token::NtVis(e) => self.vis_to_string(e),
|
||||
@ -794,7 +916,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
||||
|
||||
/* Name components */
|
||||
token::Ident(s, is_raw) => {
|
||||
IdentPrinter::new(s, is_raw, convert_dollar_crate).to_string().into()
|
||||
IdentPrinter::new(s, is_raw.into(), convert_dollar_crate).to_string().into()
|
||||
}
|
||||
token::Lifetime(s) => s.to_string().into(),
|
||||
|
||||
@ -1002,11 +1124,11 @@ impl<'a> State<'a> {
|
||||
}
|
||||
self.pclose();
|
||||
}
|
||||
ast::TyKind::AnonStruct(fields) => {
|
||||
ast::TyKind::AnonStruct(_, fields) => {
|
||||
self.head("struct");
|
||||
self.print_record_struct_body(fields, ty.span);
|
||||
}
|
||||
ast::TyKind::AnonUnion(fields) => {
|
||||
ast::TyKind::AnonUnion(_, fields) => {
|
||||
self.head("union");
|
||||
self.print_record_struct_body(fields, ty.span);
|
||||
}
|
||||
@ -1047,11 +1169,16 @@ impl<'a> State<'a> {
|
||||
ast::TyKind::Infer => {
|
||||
self.word("_");
|
||||
}
|
||||
ast::TyKind::Err => {
|
||||
ast::TyKind::Err(_) => {
|
||||
self.popen();
|
||||
self.word("/*ERROR*/");
|
||||
self.pclose();
|
||||
}
|
||||
ast::TyKind::Dummy => {
|
||||
self.popen();
|
||||
self.word("/*DUMMY*/");
|
||||
self.pclose();
|
||||
}
|
||||
ast::TyKind::ImplicitSelf => {
|
||||
self.word("Self");
|
||||
}
|
||||
@ -1085,7 +1212,7 @@ impl<'a> State<'a> {
|
||||
fn print_stmt(&mut self, st: &ast::Stmt) {
|
||||
self.maybe_print_comment(st.span.lo());
|
||||
match &st.kind {
|
||||
ast::StmtKind::Local(loc) => {
|
||||
ast::StmtKind::Let(loc) => {
|
||||
self.print_outer_attributes(&loc.attrs);
|
||||
self.space_if_not_bol();
|
||||
self.ibox(INDENT_UNIT);
|
||||
@ -1325,6 +1452,10 @@ impl<'a> State<'a> {
|
||||
s.print_path(&sym.path, true, 0);
|
||||
}
|
||||
}
|
||||
InlineAsmOperand::Label { block } => {
|
||||
s.head("label");
|
||||
s.print_block(block);
|
||||
}
|
||||
}
|
||||
}
|
||||
AsmArg::ClobberAbi(abi) => {
|
||||
@ -1590,18 +1721,28 @@ impl<'a> State<'a> {
|
||||
}
|
||||
|
||||
match bound {
|
||||
GenericBound::Trait(tref, modifier) => {
|
||||
match modifier.constness {
|
||||
GenericBound::Trait(
|
||||
tref,
|
||||
TraitBoundModifiers { constness, asyncness, polarity },
|
||||
) => {
|
||||
match constness {
|
||||
ast::BoundConstness::Never => {}
|
||||
ast::BoundConstness::Always(_) | ast::BoundConstness::Maybe(_) => {
|
||||
self.word_space(modifier.constness.as_str());
|
||||
self.word_space(constness.as_str());
|
||||
}
|
||||
}
|
||||
|
||||
match modifier.polarity {
|
||||
match asyncness {
|
||||
ast::BoundAsyncness::Normal => {}
|
||||
ast::BoundAsyncness::Async(_) => {
|
||||
self.word_space(asyncness.as_str());
|
||||
}
|
||||
}
|
||||
|
||||
match polarity {
|
||||
ast::BoundPolarity::Positive => {}
|
||||
ast::BoundPolarity::Negative(_) | ast::BoundPolarity::Maybe(_) => {
|
||||
self.word(modifier.polarity.as_str());
|
||||
self.word(polarity.as_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -893,11 +893,16 @@ impl<'a> State<'a> {
|
||||
self.word_nbsp("try");
|
||||
self.print_block_with_attrs(blk, attrs)
|
||||
}
|
||||
ast::ExprKind::Err => {
|
||||
ast::ExprKind::Err(_) => {
|
||||
self.popen();
|
||||
self.word("/*ERROR*/");
|
||||
self.pclose()
|
||||
}
|
||||
ast::ExprKind::Dummy => {
|
||||
self.popen();
|
||||
self.word("/*DUMMY*/");
|
||||
self.pclose();
|
||||
}
|
||||
}
|
||||
|
||||
self.ann.post(self, AnnNode::Expr(expr));
|
||||
|
||||
@ -43,7 +43,6 @@ impl<'a> State<'a> {
|
||||
defaultness,
|
||||
generics,
|
||||
where_clauses,
|
||||
where_predicates_split,
|
||||
bounds,
|
||||
ty,
|
||||
}) => {
|
||||
@ -51,7 +50,6 @@ impl<'a> State<'a> {
|
||||
ident,
|
||||
generics,
|
||||
*where_clauses,
|
||||
*where_predicates_split,
|
||||
bounds,
|
||||
ty.as_deref(),
|
||||
vis,
|
||||
@ -108,15 +106,14 @@ impl<'a> State<'a> {
|
||||
&mut self,
|
||||
ident: Ident,
|
||||
generics: &ast::Generics,
|
||||
where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
|
||||
where_predicates_split: usize,
|
||||
where_clauses: ast::TyAliasWhereClauses,
|
||||
bounds: &ast::GenericBounds,
|
||||
ty: Option<&ast::Ty>,
|
||||
vis: &ast::Visibility,
|
||||
defaultness: ast::Defaultness,
|
||||
) {
|
||||
let (before_predicates, after_predicates) =
|
||||
generics.where_clause.predicates.split_at(where_predicates_split);
|
||||
generics.where_clause.predicates.split_at(where_clauses.split);
|
||||
self.head("");
|
||||
self.print_visibility(vis);
|
||||
self.print_defaultness(defaultness);
|
||||
@ -127,13 +124,13 @@ impl<'a> State<'a> {
|
||||
self.word_nbsp(":");
|
||||
self.print_type_bounds(bounds);
|
||||
}
|
||||
self.print_where_clause_parts(where_clauses.0.0, before_predicates);
|
||||
self.print_where_clause_parts(where_clauses.before.has_where_token, before_predicates);
|
||||
if let Some(ty) = ty {
|
||||
self.space();
|
||||
self.word_space("=");
|
||||
self.print_type(ty);
|
||||
}
|
||||
self.print_where_clause_parts(where_clauses.1.0, after_predicates);
|
||||
self.print_where_clause_parts(where_clauses.after.has_where_token, after_predicates);
|
||||
self.word(";");
|
||||
self.end(); // end inner head-block
|
||||
self.end(); // end outer head-block
|
||||
@ -249,7 +246,6 @@ impl<'a> State<'a> {
|
||||
defaultness,
|
||||
generics,
|
||||
where_clauses,
|
||||
where_predicates_split,
|
||||
bounds,
|
||||
ty,
|
||||
}) => {
|
||||
@ -257,7 +253,6 @@ impl<'a> State<'a> {
|
||||
item.ident,
|
||||
generics,
|
||||
*where_clauses,
|
||||
*where_predicates_split,
|
||||
bounds,
|
||||
ty.as_deref(),
|
||||
&item.vis,
|
||||
@ -536,7 +531,6 @@ impl<'a> State<'a> {
|
||||
defaultness,
|
||||
generics,
|
||||
where_clauses,
|
||||
where_predicates_split,
|
||||
bounds,
|
||||
ty,
|
||||
}) => {
|
||||
@ -544,7 +538,6 @@ impl<'a> State<'a> {
|
||||
ident,
|
||||
generics,
|
||||
*where_clauses,
|
||||
*where_predicates_split,
|
||||
bounds,
|
||||
ty.as_deref(),
|
||||
vis,
|
||||
|
||||
@ -27,10 +27,16 @@ attr_incorrect_meta_item =
|
||||
attr_incorrect_repr_format_align_one_arg =
|
||||
incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
|
||||
|
||||
attr_incorrect_repr_format_expect_literal_integer =
|
||||
incorrect `repr(align)` attribute format: `align` expects a literal integer as argument
|
||||
|
||||
attr_incorrect_repr_format_generic =
|
||||
incorrect `repr({$repr_arg})` attribute format
|
||||
.suggestion = use parentheses instead
|
||||
|
||||
attr_incorrect_repr_format_packed_expect_integer =
|
||||
incorrect `repr(packed)` attribute format: `packed` expects a literal integer as argument
|
||||
|
||||
attr_incorrect_repr_format_packed_one_or_zero_arg =
|
||||
incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all
|
||||
|
||||
|
||||
@ -8,12 +8,12 @@ use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg};
|
||||
use rustc_macros::HashStable_Generic;
|
||||
use rustc_session::config::ExpectedValues;
|
||||
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
|
||||
use rustc_session::lint::BuiltinLintDiagnostics;
|
||||
use rustc_session::lint::BuiltinLintDiag;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_session::{RustcVersion, Session};
|
||||
use rustc_span::hygiene::Transparency;
|
||||
use rustc_span::{symbol::sym, symbol::Symbol, Span};
|
||||
use std::num::NonZeroU32;
|
||||
use std::num::NonZero;
|
||||
|
||||
use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
|
||||
|
||||
@ -113,7 +113,7 @@ pub enum StabilityLevel {
|
||||
/// Reason for the current stability level.
|
||||
reason: UnstableReason,
|
||||
/// Relevant `rust-lang/rust` issue.
|
||||
issue: Option<NonZeroU32>,
|
||||
issue: Option<NonZero<u32>>,
|
||||
is_soft: bool,
|
||||
/// If part of a feature is stabilized and a new feature is added for the remaining parts,
|
||||
/// then the `implied_by` attribute is used to indicate which now-stable feature previously
|
||||
@ -442,7 +442,7 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
|
||||
// is a name/value pair string literal.
|
||||
issue_num = match issue.unwrap().as_str() {
|
||||
"none" => None,
|
||||
issue => match issue.parse::<NonZeroU32>() {
|
||||
issue => match issue.parse::<NonZero<u32>>() {
|
||||
Ok(num) => Some(num),
|
||||
Err(err) => {
|
||||
sess.dcx().emit_err(
|
||||
@ -516,6 +516,7 @@ pub struct Condition {
|
||||
}
|
||||
|
||||
/// Tests if a cfg-pattern matches the cfg set
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
pub fn cfg_matches(
|
||||
cfg: &ast::MetaItem,
|
||||
sess: &Session,
|
||||
@ -524,9 +525,9 @@ pub fn cfg_matches(
|
||||
) -> bool {
|
||||
eval_condition(cfg, sess, features, &mut |cfg| {
|
||||
try_gate_cfg(cfg.name, cfg.span, sess, features);
|
||||
match sess.parse_sess.check_config.expecteds.get(&cfg.name) {
|
||||
match sess.psess.check_config.expecteds.get(&cfg.name) {
|
||||
Some(ExpectedValues::Some(values)) if !values.contains(&cfg.value) => {
|
||||
sess.parse_sess.buffer_lint_with_diagnostic(
|
||||
sess.psess.buffer_lint_with_diagnostic(
|
||||
UNEXPECTED_CFGS,
|
||||
cfg.span,
|
||||
lint_node_id,
|
||||
@ -535,19 +536,19 @@ pub fn cfg_matches(
|
||||
} else {
|
||||
format!("unexpected `cfg` condition value: (none)")
|
||||
},
|
||||
BuiltinLintDiagnostics::UnexpectedCfgValue(
|
||||
BuiltinLintDiag::UnexpectedCfgValue(
|
||||
(cfg.name, cfg.name_span),
|
||||
cfg.value.map(|v| (v, cfg.value_span.unwrap())),
|
||||
),
|
||||
);
|
||||
}
|
||||
None if sess.parse_sess.check_config.exhaustive_names => {
|
||||
sess.parse_sess.buffer_lint_with_diagnostic(
|
||||
None if sess.psess.check_config.exhaustive_names => {
|
||||
sess.psess.buffer_lint_with_diagnostic(
|
||||
UNEXPECTED_CFGS,
|
||||
cfg.span,
|
||||
lint_node_id,
|
||||
format!("unexpected `cfg` condition name: `{}`", cfg.name),
|
||||
BuiltinLintDiagnostics::UnexpectedCfgName(
|
||||
BuiltinLintDiag::UnexpectedCfgName(
|
||||
(cfg.name, cfg.name_span),
|
||||
cfg.value.map(|v| (v, cfg.value_span.unwrap())),
|
||||
),
|
||||
@ -555,7 +556,7 @@ pub fn cfg_matches(
|
||||
}
|
||||
_ => { /* not unexpected */ }
|
||||
}
|
||||
sess.parse_sess.config.contains(&(cfg.name, cfg.value))
|
||||
sess.psess.config.contains(&(cfg.name, cfg.value))
|
||||
})
|
||||
}
|
||||
|
||||
@ -566,6 +567,7 @@ fn try_gate_cfg(name: Symbol, span: Span, sess: &Session, features: Option<&Feat
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &Session, features: &Features) {
|
||||
let (cfg, feature, has_feature) = gated_cfg;
|
||||
if !has_feature(features) && !cfg_span.allows_unstable(*feature) {
|
||||
@ -592,13 +594,14 @@ fn parse_version(s: Symbol) -> Option<RustcVersion> {
|
||||
|
||||
/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
|
||||
/// evaluate individual items.
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
pub fn eval_condition(
|
||||
cfg: &ast::MetaItem,
|
||||
sess: &Session,
|
||||
features: Option<&Features>,
|
||||
eval: &mut impl FnMut(Condition) -> bool,
|
||||
) -> bool {
|
||||
let dcx = &sess.parse_sess.dcx;
|
||||
let dcx = &sess.psess.dcx;
|
||||
match &cfg.kind {
|
||||
ast::MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => {
|
||||
try_gate_cfg(sym::version, cfg.span, sess, features);
|
||||
@ -626,7 +629,7 @@ pub fn eval_condition(
|
||||
};
|
||||
|
||||
// See https://github.com/rust-lang/rust/issues/64796#issuecomment-640851454 for details
|
||||
if sess.parse_sess.assume_incomplete_release {
|
||||
if sess.psess.assume_incomplete_release {
|
||||
RustcVersion::CURRENT > min_version
|
||||
} else {
|
||||
RustcVersion::CURRENT >= min_version
|
||||
@ -984,17 +987,24 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
||||
}
|
||||
} else if let Some((name, value)) = item.name_value_literal() {
|
||||
let mut literal_error = None;
|
||||
let mut err_span = item.span();
|
||||
if name == sym::align {
|
||||
recognised = true;
|
||||
match parse_alignment(&value.kind) {
|
||||
Ok(literal) => acc.push(ReprAlign(literal)),
|
||||
Err(message) => literal_error = Some(message),
|
||||
Err(message) => {
|
||||
err_span = value.span;
|
||||
literal_error = Some(message)
|
||||
}
|
||||
};
|
||||
} else if name == sym::packed {
|
||||
recognised = true;
|
||||
match parse_alignment(&value.kind) {
|
||||
Ok(literal) => acc.push(ReprPacked(literal)),
|
||||
Err(message) => literal_error = Some(message),
|
||||
Err(message) => {
|
||||
err_span = value.span;
|
||||
literal_error = Some(message)
|
||||
}
|
||||
};
|
||||
} else if matches!(name, sym::Rust | sym::C | sym::simd | sym::transparent)
|
||||
|| int_type_of_word(name).is_some()
|
||||
@ -1007,7 +1017,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
||||
}
|
||||
if let Some(literal_error) = literal_error {
|
||||
sess.dcx().emit_err(session_diagnostics::InvalidReprGeneric {
|
||||
span: item.span(),
|
||||
span: err_span,
|
||||
repr_arg: name.to_ident_string(),
|
||||
error_part: literal_error,
|
||||
});
|
||||
@ -1039,21 +1049,37 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
||||
});
|
||||
}
|
||||
}
|
||||
MetaItemKind::List(_) => {
|
||||
MetaItemKind::List(nested_items) => {
|
||||
if meta_item.has_name(sym::align) {
|
||||
recognised = true;
|
||||
sess.dcx().emit_err(
|
||||
session_diagnostics::IncorrectReprFormatAlignOneArg {
|
||||
span: meta_item.span,
|
||||
},
|
||||
);
|
||||
if nested_items.len() == 1 {
|
||||
sess.dcx().emit_err(
|
||||
session_diagnostics::IncorrectReprFormatExpectInteger {
|
||||
span: nested_items[0].span(),
|
||||
},
|
||||
);
|
||||
} else {
|
||||
sess.dcx().emit_err(
|
||||
session_diagnostics::IncorrectReprFormatAlignOneArg {
|
||||
span: meta_item.span,
|
||||
},
|
||||
);
|
||||
}
|
||||
} else if meta_item.has_name(sym::packed) {
|
||||
recognised = true;
|
||||
sess.dcx().emit_err(
|
||||
session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg {
|
||||
span: meta_item.span,
|
||||
},
|
||||
);
|
||||
if nested_items.len() == 1 {
|
||||
sess.dcx().emit_err(
|
||||
session_diagnostics::IncorrectReprFormatPackedExpectInteger {
|
||||
span: nested_items[0].span(),
|
||||
},
|
||||
);
|
||||
} else {
|
||||
sess.dcx().emit_err(
|
||||
session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg {
|
||||
span: meta_item.span,
|
||||
},
|
||||
);
|
||||
}
|
||||
} else if matches!(
|
||||
meta_item.name_or_empty(),
|
||||
sym::Rust | sym::C | sym::simd | sym::transparent
|
||||
|
||||
@ -7,9 +7,8 @@
|
||||
#![allow(internal_features)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(generic_nonzero)]
|
||||
#![feature(let_chains)]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate rustc_macros;
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
use std::num::IntErrorKind;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_errors::{
|
||||
codes::*, Applicability, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, Level,
|
||||
};
|
||||
use rustc_errors::{codes::*, Applicability, Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level};
|
||||
use rustc_macros::Diagnostic;
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
@ -50,10 +48,10 @@ pub(crate) struct UnknownMetaItem<'a> {
|
||||
}
|
||||
|
||||
// Manual implementation to be able to format `expected` items correctly.
|
||||
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for UnknownMetaItem<'_> {
|
||||
fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> {
|
||||
impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnknownMetaItem<'_> {
|
||||
fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> {
|
||||
let expected = self.expected.iter().map(|name| format!("`{name}`")).collect::<Vec<_>>();
|
||||
DiagnosticBuilder::new(dcx, level, fluent::attr_unknown_meta_item)
|
||||
Diag::new(dcx, level, fluent::attr_unknown_meta_item)
|
||||
.with_span(self.span)
|
||||
.with_code(E0541)
|
||||
.with_arg("item", self.item)
|
||||
@ -170,6 +168,12 @@ pub(crate) struct IncorrectReprFormatPackedOneOrZeroArg {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_incorrect_repr_format_packed_expect_integer, code = E0552)]
|
||||
pub(crate) struct IncorrectReprFormatPackedExpectInteger {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_invalid_repr_hint_no_paren, code = E0552)]
|
||||
@ -197,9 +201,9 @@ pub(crate) struct UnsupportedLiteral {
|
||||
pub start_point_span: Span,
|
||||
}
|
||||
|
||||
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for UnsupportedLiteral {
|
||||
fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> {
|
||||
let mut diag = DiagnosticBuilder::new(
|
||||
impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnsupportedLiteral {
|
||||
fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> {
|
||||
let mut diag = Diag::new(
|
||||
dcx,
|
||||
level,
|
||||
match self.reason {
|
||||
@ -252,6 +256,13 @@ pub(crate) struct IncorrectReprFormatAlignOneArg {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_incorrect_repr_format_expect_literal_integer, code = E0693)]
|
||||
pub(crate) struct IncorrectReprFormatExpectInteger {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_incorrect_repr_format_generic, code = E0693)]
|
||||
pub(crate) struct IncorrectReprFormatGeneric<'a> {
|
||||
|
||||
@ -6,7 +6,7 @@ edition = "2021"
|
||||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
either = "1.5.0"
|
||||
itertools = "0.11"
|
||||
itertools = "0.12"
|
||||
polonius-engine = "0.13.0"
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
|
||||
@ -16,6 +16,9 @@ borrowck_borrow_due_to_use_closure =
|
||||
borrowck_borrow_due_to_use_coroutine =
|
||||
borrow occurs due to use in coroutine
|
||||
|
||||
borrowck_calling_operator_moves =
|
||||
calling this operator moves the value
|
||||
|
||||
borrowck_calling_operator_moves_lhs =
|
||||
calling this operator moves the left-hand side
|
||||
|
||||
@ -163,7 +166,13 @@ borrowck_returned_lifetime_wrong =
|
||||
borrowck_returned_ref_escaped =
|
||||
returns a reference to a captured variable which escapes the closure body
|
||||
|
||||
borrowck_simd_shuffle_last_const = last argument of `simd_shuffle` is required to be a `const` item
|
||||
borrowck_simd_intrinsic_arg_const =
|
||||
{$arg ->
|
||||
[1] 1st
|
||||
[2] 2nd
|
||||
[3] 3rd
|
||||
*[other] {$arg}th
|
||||
} argument of `{$intrinsic}` is required to be a `const` item
|
||||
|
||||
borrowck_suggest_create_freash_reborrow =
|
||||
consider reborrowing the `Pin` instead of moving it
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
use crate::path_utils::allow_two_phase_borrow;
|
||||
use crate::place_ext::PlaceExt;
|
||||
use crate::BorrowIndex;
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
use rustc_errors::{codes::*, struct_span_code_err, DiagCtxt, DiagnosticBuilder};
|
||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
|
||||
use rustc_errors::{codes::*, struct_span_code_err, Diag, DiagCtxt};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_span::Span;
|
||||
|
||||
@ -14,7 +17,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
place: &str,
|
||||
borrow_place: &str,
|
||||
value_place: &str,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
) -> Diag<'tcx> {
|
||||
self.dcx().create_err(crate::session_diagnostics::MoveBorrow {
|
||||
place,
|
||||
span,
|
||||
@ -30,7 +33,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
desc: &str,
|
||||
borrow_span: Span,
|
||||
borrow_desc: &str,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
) -> Diag<'tcx> {
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
span,
|
||||
@ -50,7 +53,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
old_loan_span: Span,
|
||||
old_opt_via: &str,
|
||||
old_load_end_span: Option<Span>,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
) -> Diag<'tcx> {
|
||||
let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") };
|
||||
let mut err = struct_span_code_err!(
|
||||
self.dcx(),
|
||||
@ -97,7 +100,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
desc: &str,
|
||||
old_loan_span: Span,
|
||||
old_load_end_span: Option<Span>,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
) -> Diag<'tcx> {
|
||||
let mut err = struct_span_code_err!(
|
||||
self.dcx(),
|
||||
new_loan_span,
|
||||
@ -130,7 +133,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
noun_old: &str,
|
||||
old_opt_via: &str,
|
||||
previous_end_span: Option<Span>,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> Diag<'tcx> {
|
||||
let mut err = struct_span_code_err!(
|
||||
self.dcx(),
|
||||
new_loan_span,
|
||||
@ -162,7 +165,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
old_opt_via: &str,
|
||||
previous_end_span: Option<Span>,
|
||||
second_borrow_desc: &str,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> Diag<'tcx> {
|
||||
let mut err = struct_span_code_err!(
|
||||
self.dcx(),
|
||||
new_loan_span,
|
||||
@ -194,7 +197,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
kind_old: &str,
|
||||
msg_old: &str,
|
||||
old_load_end_span: Option<Span>,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> Diag<'tcx> {
|
||||
let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") };
|
||||
let mut err = struct_span_code_err!(
|
||||
self.dcx(),
|
||||
@ -235,7 +238,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
span: Span,
|
||||
borrow_span: Span,
|
||||
desc: &str,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> Diag<'tcx> {
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
span,
|
||||
@ -252,12 +255,12 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
span: Span,
|
||||
desc: &str,
|
||||
is_arg: bool,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> Diag<'tcx> {
|
||||
let msg = if is_arg { "to immutable argument" } else { "twice to immutable variable" };
|
||||
struct_span_code_err!(self.dcx(), span, E0384, "cannot assign {} {}", msg, desc)
|
||||
}
|
||||
|
||||
pub(crate) fn cannot_assign(&self, span: Span, desc: &str) -> DiagnosticBuilder<'tcx> {
|
||||
pub(crate) fn cannot_assign(&self, span: Span, desc: &str) -> Diag<'tcx> {
|
||||
struct_span_code_err!(self.dcx(), span, E0594, "cannot assign to {}", desc)
|
||||
}
|
||||
|
||||
@ -265,7 +268,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
&self,
|
||||
move_from_span: Span,
|
||||
move_from_desc: &str,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> Diag<'tcx> {
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
move_from_span,
|
||||
@ -283,7 +286,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
move_from_span: Span,
|
||||
ty: Ty<'_>,
|
||||
is_index: Option<bool>,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> Diag<'tcx> {
|
||||
let type_name = match (&ty.kind(), is_index) {
|
||||
(&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array",
|
||||
(&ty::Slice(_), _) => "slice",
|
||||
@ -304,7 +307,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
&self,
|
||||
move_from_span: Span,
|
||||
container_ty: Ty<'_>,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> Diag<'tcx> {
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
move_from_span,
|
||||
@ -321,7 +324,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
verb: &str,
|
||||
optional_adverb_for_moved: &str,
|
||||
moved_path: Option<String>,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
) -> Diag<'tcx> {
|
||||
let moved_path = moved_path.map(|mp| format!(": `{mp}`")).unwrap_or_default();
|
||||
|
||||
struct_span_code_err!(
|
||||
@ -340,7 +343,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
span: Span,
|
||||
path: &str,
|
||||
reason: &str,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
) -> Diag<'tcx> {
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
span,
|
||||
@ -358,7 +361,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
immutable_place: &str,
|
||||
immutable_section: &str,
|
||||
action: &str,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
) -> Diag<'tcx> {
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
mutate_span,
|
||||
@ -376,7 +379,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
&self,
|
||||
span: Span,
|
||||
yield_span: Span,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
) -> Diag<'tcx> {
|
||||
let coroutine_kind = self.body.coroutine.as_ref().unwrap().coroutine_kind;
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
@ -387,10 +390,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
.with_span_label(yield_span, "possible yield occurs here")
|
||||
}
|
||||
|
||||
pub(crate) fn cannot_borrow_across_destructor(
|
||||
&self,
|
||||
borrow_span: Span,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
pub(crate) fn cannot_borrow_across_destructor(&self, borrow_span: Span) -> Diag<'tcx> {
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
borrow_span,
|
||||
@ -399,11 +399,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn path_does_not_live_long_enough(
|
||||
&self,
|
||||
span: Span,
|
||||
path: &str,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
pub(crate) fn path_does_not_live_long_enough(&self, span: Span, path: &str) -> Diag<'tcx> {
|
||||
struct_span_code_err!(self.dcx(), span, E0597, "{} does not live long enough", path,)
|
||||
}
|
||||
|
||||
@ -413,7 +409,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
return_kind: &str,
|
||||
reference_desc: &str,
|
||||
path_desc: &str,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
) -> Diag<'tcx> {
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
span,
|
||||
@ -436,7 +432,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
borrowed_path: &str,
|
||||
capture_span: Span,
|
||||
scope: &str,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
) -> Diag<'tcx> {
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
closure_span,
|
||||
@ -448,10 +444,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
.with_span_label(closure_span, format!("may outlive borrowed value {borrowed_path}"))
|
||||
}
|
||||
|
||||
pub(crate) fn thread_local_value_does_not_live_long_enough(
|
||||
&self,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
pub(crate) fn thread_local_value_does_not_live_long_enough(&self, span: Span) -> Diag<'tcx> {
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
span,
|
||||
@ -460,10 +453,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn temporary_value_borrowed_for_too_long(
|
||||
&self,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
pub(crate) fn temporary_value_borrowed_for_too_long(&self, span: Span) -> Diag<'tcx> {
|
||||
struct_span_code_err!(self.dcx(), span, E0716, "temporary value dropped while borrowed",)
|
||||
}
|
||||
}
|
||||
@ -472,7 +462,7 @@ pub(crate) fn borrowed_data_escapes_closure<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
escape_span: Span,
|
||||
escapes_from: &str,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
) -> Diag<'tcx> {
|
||||
struct_span_code_err!(
|
||||
tcx.dcx(),
|
||||
escape_span,
|
||||
|
||||
@ -1,6 +1,3 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
||||
use rustc_data_structures::graph::scc::Sccs;
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
//! This file provides API for compiler consumers.
|
||||
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
@ -108,7 +106,7 @@ pub fn get_body_with_borrowck_facts(
|
||||
options: ConsumerOptions,
|
||||
) -> BodyWithBorrowckFacts<'_> {
|
||||
let (input_body, promoted) = tcx.mir_promoted(def);
|
||||
let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(def)).build();
|
||||
let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::bind(tcx, def)).build();
|
||||
let input_body: &Body<'_> = &input_body.borrow();
|
||||
let promoted: &IndexSlice<_, _> = &promoted.borrow();
|
||||
*super::do_mir_borrowck(&infcx, input_body, promoted, Some(options)).1.unwrap()
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::graph::WithSuccessors;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
use rustc_middle::mir::visit::{
|
||||
MutatingUseContext, NonMutatingUseContext, NonUseContext, PlaceContext,
|
||||
};
|
||||
|
||||
@ -1,7 +1,4 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
||||
use rustc_errors::DiagnosticBuilder;
|
||||
use rustc_errors::Diag;
|
||||
use rustc_infer::infer::canonical::Canonical;
|
||||
use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError;
|
||||
use rustc_infer::infer::region_constraints::Constraint;
|
||||
@ -147,7 +144,7 @@ impl<'tcx> ToUniverseInfo<'tcx> for ! {
|
||||
trait TypeOpInfo<'tcx> {
|
||||
/// Returns an error to be reported if rerunning the type op fails to
|
||||
/// recover the error's cause.
|
||||
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx>;
|
||||
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> Diag<'tcx>;
|
||||
|
||||
fn base_universe(&self) -> ty::UniverseIndex;
|
||||
|
||||
@ -157,7 +154,7 @@ trait TypeOpInfo<'tcx> {
|
||||
cause: ObligationCause<'tcx>,
|
||||
placeholder_region: ty::Region<'tcx>,
|
||||
error_region: Option<ty::Region<'tcx>>,
|
||||
) -> Option<DiagnosticBuilder<'tcx>>;
|
||||
) -> Option<Diag<'tcx>>;
|
||||
|
||||
#[instrument(level = "debug", skip(self, mbcx))]
|
||||
fn report_error(
|
||||
@ -220,7 +217,7 @@ struct PredicateQuery<'tcx> {
|
||||
}
|
||||
|
||||
impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
|
||||
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> Diag<'tcx> {
|
||||
tcx.dcx().create_err(HigherRankedLifetimeError {
|
||||
cause: Some(HigherRankedErrorCause::CouldNotProve {
|
||||
predicate: self.canonical_query.value.value.predicate.to_string(),
|
||||
@ -239,7 +236,7 @@ impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
|
||||
cause: ObligationCause<'tcx>,
|
||||
placeholder_region: ty::Region<'tcx>,
|
||||
error_region: Option<ty::Region<'tcx>>,
|
||||
) -> Option<DiagnosticBuilder<'tcx>> {
|
||||
) -> Option<Diag<'tcx>> {
|
||||
let (infcx, key, _) =
|
||||
mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
@ -257,7 +254,7 @@ impl<'tcx, T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T>
|
||||
where
|
||||
T: Copy + fmt::Display + TypeFoldable<TyCtxt<'tcx>> + 'tcx,
|
||||
{
|
||||
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> Diag<'tcx> {
|
||||
tcx.dcx().create_err(HigherRankedLifetimeError {
|
||||
cause: Some(HigherRankedErrorCause::CouldNotNormalize {
|
||||
value: self.canonical_query.value.value.value.to_string(),
|
||||
@ -276,7 +273,7 @@ where
|
||||
cause: ObligationCause<'tcx>,
|
||||
placeholder_region: ty::Region<'tcx>,
|
||||
error_region: Option<ty::Region<'tcx>>,
|
||||
) -> Option<DiagnosticBuilder<'tcx>> {
|
||||
) -> Option<Diag<'tcx>> {
|
||||
let (infcx, key, _) =
|
||||
mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
@ -300,7 +297,7 @@ struct AscribeUserTypeQuery<'tcx> {
|
||||
}
|
||||
|
||||
impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
|
||||
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> Diag<'tcx> {
|
||||
// FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
|
||||
// and is only the fallback when the nice error fails. Consider improving this some more.
|
||||
tcx.dcx().create_err(HigherRankedLifetimeError { cause: None, span })
|
||||
@ -316,7 +313,7 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
|
||||
cause: ObligationCause<'tcx>,
|
||||
placeholder_region: ty::Region<'tcx>,
|
||||
error_region: Option<ty::Region<'tcx>>,
|
||||
) -> Option<DiagnosticBuilder<'tcx>> {
|
||||
) -> Option<Diag<'tcx>> {
|
||||
let (infcx, key, _) =
|
||||
mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
@ -326,7 +323,7 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
|
||||
}
|
||||
|
||||
impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
|
||||
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> Diag<'tcx> {
|
||||
// FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
|
||||
// and is only the fallback when the nice error fails. Consider improving this some more.
|
||||
tcx.dcx().create_err(HigherRankedLifetimeError { cause: None, span })
|
||||
@ -342,7 +339,7 @@ impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
|
||||
_cause: ObligationCause<'tcx>,
|
||||
placeholder_region: ty::Region<'tcx>,
|
||||
error_region: Option<ty::Region<'tcx>>,
|
||||
) -> Option<DiagnosticBuilder<'tcx>> {
|
||||
) -> Option<Diag<'tcx>> {
|
||||
try_extract_error_from_region_constraints(
|
||||
mbcx.infcx,
|
||||
placeholder_region,
|
||||
@ -363,7 +360,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
placeholder_region: ty::Region<'tcx>,
|
||||
error_region: Option<ty::Region<'tcx>>,
|
||||
) -> Option<DiagnosticBuilder<'tcx>> {
|
||||
) -> Option<Diag<'tcx>> {
|
||||
// We generally shouldn't have errors here because the query was
|
||||
// already run, but there's no point using `span_delayed_bug`
|
||||
// when we're going to emit an error here anyway.
|
||||
@ -387,7 +384,7 @@ fn try_extract_error_from_region_constraints<'tcx>(
|
||||
region_constraints: &RegionConstraintData<'tcx>,
|
||||
mut region_var_origin: impl FnMut(RegionVid) -> RegionVariableOrigin,
|
||||
mut universe_of_region: impl FnMut(RegionVid) -> UniverseIndex,
|
||||
) -> Option<DiagnosticBuilder<'tcx>> {
|
||||
) -> Option<Diag<'tcx>> {
|
||||
let placeholder_universe = match placeholder_region.kind() {
|
||||
ty::RePlaceholder(p) => p.universe,
|
||||
ty::ReVar(vid) => universe_of_region(vid),
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
// ignore-tidy-filelength
|
||||
|
||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
|
||||
use either::Either;
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_errors::{
|
||||
codes::*, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan,
|
||||
};
|
||||
use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag, MultiSpan};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
|
||||
use rustc_hir::{CoroutineDesugaring, PatField};
|
||||
use rustc_hir::{CoroutineKind, CoroutineSource, LangItem};
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_middle::hir::nested_filter::OnlyBodies;
|
||||
use rustc_middle::mir::tcx::PlaceTy;
|
||||
use rustc_middle::mir::{
|
||||
@ -20,16 +20,21 @@ use rustc_middle::mir::{
|
||||
PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
|
||||
VarBindingForm,
|
||||
};
|
||||
use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{
|
||||
self, suggest_constraining_type_params, PredicateKind, ToPredicate, Ty, TyCtxt,
|
||||
TypeSuperVisitable, TypeVisitor,
|
||||
};
|
||||
use rustc_middle::util::CallKind;
|
||||
use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::hygiene::DesugaringKind;
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::{BytePos, Span, Symbol};
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
|
||||
use rustc_trait_selection::traits::error_reporting::FindExprBySpan;
|
||||
use rustc_trait_selection::traits::ObligationCtxt;
|
||||
use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
|
||||
use std::iter;
|
||||
|
||||
use crate::borrow_set::TwoPhaseActivation;
|
||||
@ -38,7 +43,7 @@ use crate::diagnostics::conflict_errors::StorageDeadOrDrop::LocalStorageDead;
|
||||
use crate::diagnostics::{find_all_local_uses, CapturedMessageOpt};
|
||||
use crate::{
|
||||
borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
|
||||
InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind,
|
||||
InitializationRequiringAction, MirBorrowckCtxt, WriteKind,
|
||||
};
|
||||
|
||||
use super::{
|
||||
@ -113,7 +118,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
self.buffer_error(err);
|
||||
} else {
|
||||
if let Some((reported_place, _)) = self.has_move_error(&move_out_indices) {
|
||||
if self.prefixes(*reported_place, PrefixSet::All).any(|p| p == used_place) {
|
||||
if used_place.is_prefix_of(*reported_place) {
|
||||
debug!(
|
||||
"report_use_of_moved_or_uninitialized place: error suppressed mois={:?}",
|
||||
move_out_indices
|
||||
@ -226,7 +231,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
seen_spans.insert(move_span);
|
||||
}
|
||||
|
||||
use_spans.var_path_only_subdiag(&mut err, desired_action);
|
||||
use_spans.var_path_only_subdiag(self.dcx(), &mut err, desired_action);
|
||||
|
||||
if !is_loop_move {
|
||||
err.span_label(
|
||||
@ -282,24 +287,31 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
// something that already has `Fn`-like bounds (or is a closure), so we can't
|
||||
// restrict anyways.
|
||||
} else {
|
||||
self.suggest_adding_copy_bounds(&mut err, ty, span);
|
||||
let copy_did = self.infcx.tcx.require_lang_item(LangItem::Copy, Some(span));
|
||||
self.suggest_adding_bounds(&mut err, ty, copy_did, span);
|
||||
}
|
||||
|
||||
if needs_note {
|
||||
if let Some(local) = place.as_local() {
|
||||
let span = self.body.local_decls[local].source_info.span;
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move,
|
||||
ty,
|
||||
place: ¬e_msg,
|
||||
span,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move,
|
||||
ty,
|
||||
place: ¬e_msg,
|
||||
span,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Note {
|
||||
is_partial_move,
|
||||
ty,
|
||||
place: ¬e_msg,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
crate::session_diagnostics::TypeNoCopy::Note {
|
||||
is_partial_move,
|
||||
ty,
|
||||
place: ¬e_msg,
|
||||
},
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@ -327,7 +339,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
&mut self,
|
||||
mpi: MovePathIndex,
|
||||
move_span: Span,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
err: &mut Diag<'tcx>,
|
||||
in_pattern: &mut bool,
|
||||
move_spans: UseSpans<'_>,
|
||||
) {
|
||||
@ -400,67 +412,59 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
let typeck = self.infcx.tcx.typeck(self.mir_def_id());
|
||||
let hir_id = hir.parent_id(expr.hir_id);
|
||||
if let Some(parent) = self.infcx.tcx.opt_hir_node(hir_id) {
|
||||
let (def_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent
|
||||
&& let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind
|
||||
&& let Some(def_id) = typeck.type_dependent_def_id(parent_expr.hir_id)
|
||||
{
|
||||
(def_id.as_local(), args, 1)
|
||||
} else if let hir::Node::Expr(parent_expr) = parent
|
||||
&& let hir::ExprKind::Call(call, args) = parent_expr.kind
|
||||
&& let ty::FnDef(def_id, _) = typeck.node_type(call.hir_id).kind()
|
||||
{
|
||||
(def_id.as_local(), args, 0)
|
||||
} else {
|
||||
(None, &[][..], 0)
|
||||
let parent = self.infcx.tcx.parent_hir_node(expr.hir_id);
|
||||
let (def_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent
|
||||
&& let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind
|
||||
&& let Some(def_id) = typeck.type_dependent_def_id(parent_expr.hir_id)
|
||||
{
|
||||
(def_id.as_local(), args, 1)
|
||||
} else if let hir::Node::Expr(parent_expr) = parent
|
||||
&& let hir::ExprKind::Call(call, args) = parent_expr.kind
|
||||
&& let ty::FnDef(def_id, _) = typeck.node_type(call.hir_id).kind()
|
||||
{
|
||||
(def_id.as_local(), args, 0)
|
||||
} else {
|
||||
(None, &[][..], 0)
|
||||
};
|
||||
if let Some(def_id) = def_id
|
||||
&& let node = self.infcx.tcx.hir_node_by_def_id(def_id)
|
||||
&& let Some(fn_sig) = node.fn_sig()
|
||||
&& let Some(ident) = node.ident()
|
||||
&& let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id)
|
||||
&& let Some(arg) = fn_sig.decl.inputs.get(pos + offset)
|
||||
{
|
||||
let mut span: MultiSpan = arg.span.into();
|
||||
span.push_span_label(
|
||||
arg.span,
|
||||
"this parameter takes ownership of the value".to_string(),
|
||||
);
|
||||
let descr = match node.fn_kind() {
|
||||
Some(hir::intravisit::FnKind::ItemFn(..)) | None => "function",
|
||||
Some(hir::intravisit::FnKind::Method(..)) => "method",
|
||||
Some(hir::intravisit::FnKind::Closure) => "closure",
|
||||
};
|
||||
if let Some(def_id) = def_id
|
||||
&& let Some(node) = self
|
||||
.infcx
|
||||
.tcx
|
||||
.opt_hir_node(self.infcx.tcx.local_def_id_to_hir_id(def_id))
|
||||
&& let Some(fn_sig) = node.fn_sig()
|
||||
&& let Some(ident) = node.ident()
|
||||
&& let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id)
|
||||
&& let Some(arg) = fn_sig.decl.inputs.get(pos + offset)
|
||||
{
|
||||
let mut span: MultiSpan = arg.span.into();
|
||||
span.push_span_label(
|
||||
arg.span,
|
||||
"this parameter takes ownership of the value".to_string(),
|
||||
);
|
||||
let descr = match node.fn_kind() {
|
||||
Some(hir::intravisit::FnKind::ItemFn(..)) | None => "function",
|
||||
Some(hir::intravisit::FnKind::Method(..)) => "method",
|
||||
Some(hir::intravisit::FnKind::Closure) => "closure",
|
||||
};
|
||||
span.push_span_label(ident.span, format!("in this {descr}"));
|
||||
err.span_note(
|
||||
span,
|
||||
format!(
|
||||
"consider changing this parameter type in {descr} `{ident}` to \
|
||||
span.push_span_label(ident.span, format!("in this {descr}"));
|
||||
err.span_note(
|
||||
span,
|
||||
format!(
|
||||
"consider changing this parameter type in {descr} `{ident}` to \
|
||||
borrow instead if owning the value isn't necessary",
|
||||
),
|
||||
);
|
||||
}
|
||||
let place = &self.move_data.move_paths[mpi].place;
|
||||
let ty = place.ty(self.body, self.infcx.tcx).ty;
|
||||
if let hir::Node::Expr(parent_expr) = parent
|
||||
&& let hir::ExprKind::Call(call_expr, _) = parent_expr.kind
|
||||
&& let hir::ExprKind::Path(hir::QPath::LangItem(
|
||||
LangItem::IntoIterIntoIter,
|
||||
_,
|
||||
)) = call_expr.kind
|
||||
{
|
||||
// Do not suggest `.clone()` in a `for` loop, we already suggest borrowing.
|
||||
} else if let UseSpans::FnSelfUse { kind: CallKind::Normal { .. }, .. } =
|
||||
move_spans
|
||||
{
|
||||
// We already suggest cloning for these cases in `explain_captures`.
|
||||
} else {
|
||||
self.suggest_cloning(err, ty, expr, move_span);
|
||||
}
|
||||
),
|
||||
);
|
||||
}
|
||||
let place = &self.move_data.move_paths[mpi].place;
|
||||
let ty = place.ty(self.body, self.infcx.tcx).ty;
|
||||
if let hir::Node::Expr(parent_expr) = parent
|
||||
&& let hir::ExprKind::Call(call_expr, _) = parent_expr.kind
|
||||
&& let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IntoIterIntoIter, _)) =
|
||||
call_expr.kind
|
||||
{
|
||||
// Do not suggest `.clone()` in a `for` loop, we already suggest borrowing.
|
||||
} else if let UseSpans::FnSelfUse { kind: CallKind::Normal { .. }, .. } = move_spans
|
||||
{
|
||||
// We already suggest cloning for these cases in `explain_captures`.
|
||||
} else {
|
||||
self.suggest_cloning(err, ty, expr, move_span);
|
||||
}
|
||||
}
|
||||
if let Some(pat) = finder.pat {
|
||||
@ -486,7 +490,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
desired_action: InitializationRequiringAction,
|
||||
span: Span,
|
||||
use_spans: UseSpans<'tcx>,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> Diag<'tcx> {
|
||||
// We need all statements in the body where the binding was assigned to later find all
|
||||
// the branching code paths where the binding *wasn't* assigned to.
|
||||
let inits = &self.move_data.init_path_map[mpi];
|
||||
@ -561,7 +565,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
E0381,
|
||||
"{used} binding {desc}{isnt_initialized}"
|
||||
);
|
||||
use_spans.var_path_only_subdiag(&mut err, desired_action);
|
||||
use_spans.var_path_only_subdiag(self.dcx(), &mut err, desired_action);
|
||||
|
||||
if let InitializationRequiringAction::PartialAssignment
|
||||
| InitializationRequiringAction::Assignment = desired_action
|
||||
@ -613,7 +617,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
if self.sugg_span.is_some() {
|
||||
return;
|
||||
}
|
||||
if let hir::StmtKind::Local(hir::Local { span, ty, init: None, .. }) = &ex.kind
|
||||
|
||||
// FIXME: We make sure that this is a normal top-level binding,
|
||||
// but we could suggest `todo!()` for all uninitalized bindings in the pattern pattern
|
||||
if let hir::StmtKind::Let(hir::Local { span, ty, init: None, pat, .. }) =
|
||||
&ex.kind
|
||||
&& let hir::PatKind::Binding(..) = pat.kind
|
||||
&& span.contains(self.decl_span)
|
||||
{
|
||||
self.sugg_span = ty.map_or(Some(self.decl_span), |ty| Some(ty.span));
|
||||
@ -633,7 +642,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
|
||||
fn suggest_assign_value(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
err: &mut Diag<'_>,
|
||||
moved_place: PlaceRef<'tcx>,
|
||||
sugg_span: Span,
|
||||
) {
|
||||
@ -672,7 +681,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
|
||||
fn suggest_borrow_fn_like(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
err: &mut Diag<'_>,
|
||||
ty: Ty<'tcx>,
|
||||
move_sites: &[MoveSite],
|
||||
value_name: &str,
|
||||
@ -695,7 +704,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
|
||||
// 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
|
||||
// These types seem reasonably opaque enough that they could be instantiated with their
|
||||
// borrowed variants in a function body when we see a move error.
|
||||
let borrow_level = match *ty.kind() {
|
||||
ty::Param(_) => tcx
|
||||
@ -738,13 +747,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
true
|
||||
}
|
||||
|
||||
fn suggest_cloning(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
ty: Ty<'tcx>,
|
||||
expr: &hir::Expr<'_>,
|
||||
span: Span,
|
||||
) {
|
||||
fn suggest_cloning(&self, err: &mut Diag<'_>, ty: Ty<'tcx>, expr: &hir::Expr<'_>, span: Span) {
|
||||
let tcx = self.infcx.tcx;
|
||||
// Try to find predicates on *generic params* that would allow copying `ty`
|
||||
let suggestion =
|
||||
@ -776,7 +779,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn suggest_adding_copy_bounds(&self, err: &mut Diagnostic, ty: Ty<'tcx>, span: Span) {
|
||||
fn suggest_adding_bounds(&self, err: &mut Diag<'_>, ty: Ty<'tcx>, def_id: DefId, span: Span) {
|
||||
let tcx = self.infcx.tcx;
|
||||
let generics = tcx.generics_of(self.mir_def_id());
|
||||
|
||||
@ -789,10 +792,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
};
|
||||
// Try to find predicates on *generic params* that would allow copying `ty`
|
||||
let ocx = ObligationCtxt::new(self.infcx);
|
||||
let copy_did = tcx.require_lang_item(LangItem::Copy, Some(span));
|
||||
let cause = ObligationCause::misc(span, self.mir_def_id());
|
||||
|
||||
ocx.register_bound(cause, self.param_env, ty, copy_did);
|
||||
ocx.register_bound(cause, self.param_env, ty, def_id);
|
||||
let errors = ocx.select_all_or_error();
|
||||
|
||||
// Only emit suggestion if all required predicates are on generic
|
||||
@ -852,13 +854,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
&value_msg,
|
||||
);
|
||||
|
||||
borrow_spans.var_path_only_subdiag(&mut err, crate::InitializationRequiringAction::Borrow);
|
||||
borrow_spans.var_path_only_subdiag(
|
||||
self.dcx(),
|
||||
&mut err,
|
||||
crate::InitializationRequiringAction::Borrow,
|
||||
);
|
||||
|
||||
move_spans.var_subdiag(None, &mut err, None, |kind, var_span| {
|
||||
move_spans.var_subdiag(self.dcx(), &mut err, None, |kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
hir::ClosureKind::Coroutine(_) => MoveUseInCoroutine { var_span },
|
||||
hir::ClosureKind::Closure => MoveUseInClosure { var_span },
|
||||
hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
|
||||
MoveUseInClosure { var_span }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -872,6 +880,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
Some(borrow_span),
|
||||
None,
|
||||
);
|
||||
self.suggest_copy_for_type_in_cloned_ref(&mut err, place);
|
||||
self.buffer_error(err);
|
||||
}
|
||||
|
||||
@ -880,7 +889,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
location: Location,
|
||||
(place, _span): (Place<'tcx>, Span),
|
||||
borrow: &BorrowData<'tcx>,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> Diag<'tcx> {
|
||||
let borrow_spans = self.retrieve_borrow_spans(borrow);
|
||||
let borrow_span = borrow_spans.args_or_use();
|
||||
|
||||
@ -897,7 +906,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
borrow_span,
|
||||
&self.describe_any_place(borrow.borrowed_place.as_ref()),
|
||||
);
|
||||
borrow_spans.var_subdiag(None, &mut err, Some(borrow.kind), |kind, var_span| {
|
||||
borrow_spans.var_subdiag(self.dcx(), &mut err, Some(borrow.kind), |kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
let place = &borrow.borrowed_place;
|
||||
let desc_place = self.describe_any_place(place.as_ref());
|
||||
@ -905,7 +914,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
hir::ClosureKind::Coroutine(_) => {
|
||||
BorrowUsePlaceCoroutine { place: desc_place, var_span, is_single_var: true }
|
||||
}
|
||||
hir::ClosureKind::Closure => {
|
||||
hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
|
||||
BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: true }
|
||||
}
|
||||
}
|
||||
@ -930,7 +939,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
(place, span): (Place<'tcx>, Span),
|
||||
gen_borrow_kind: BorrowKind,
|
||||
issued_borrow: &BorrowData<'tcx>,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> Diag<'tcx> {
|
||||
let issued_spans = self.retrieve_borrow_spans(issued_borrow);
|
||||
let issued_span = issued_spans.args_or_use();
|
||||
|
||||
@ -1045,7 +1054,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
"mutably borrow",
|
||||
);
|
||||
borrow_spans.var_subdiag(
|
||||
None,
|
||||
self.dcx(),
|
||||
&mut err,
|
||||
Some(BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }),
|
||||
|kind, var_span| {
|
||||
@ -1056,7 +1065,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
var_span,
|
||||
is_single_var: true,
|
||||
},
|
||||
hir::ClosureKind::Closure => BorrowUsePlaceClosure {
|
||||
hir::ClosureKind::Closure
|
||||
| hir::ClosureKind::CoroutineClosure(_) => BorrowUsePlaceClosure {
|
||||
place: desc_place,
|
||||
var_span,
|
||||
is_single_var: true,
|
||||
@ -1132,22 +1142,31 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
};
|
||||
|
||||
if issued_spans == borrow_spans {
|
||||
borrow_spans.var_subdiag(None, &mut err, Some(gen_borrow_kind), |kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
hir::ClosureKind::Coroutine(_) => BorrowUsePlaceCoroutine {
|
||||
place: desc_place,
|
||||
var_span,
|
||||
is_single_var: false,
|
||||
},
|
||||
hir::ClosureKind::Closure => {
|
||||
BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: false }
|
||||
borrow_spans.var_subdiag(
|
||||
self.dcx(),
|
||||
&mut err,
|
||||
Some(gen_borrow_kind),
|
||||
|kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
hir::ClosureKind::Coroutine(_) => BorrowUsePlaceCoroutine {
|
||||
place: desc_place,
|
||||
var_span,
|
||||
is_single_var: false,
|
||||
},
|
||||
hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
|
||||
BorrowUsePlaceClosure {
|
||||
place: desc_place,
|
||||
var_span,
|
||||
is_single_var: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
} else {
|
||||
issued_spans.var_subdiag(
|
||||
Some(self.dcx()),
|
||||
self.dcx(),
|
||||
&mut err,
|
||||
Some(issued_borrow.kind),
|
||||
|kind, var_span| {
|
||||
@ -1158,7 +1177,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
hir::ClosureKind::Coroutine(_) => {
|
||||
FirstBorrowUsePlaceCoroutine { place: borrow_place_desc, var_span }
|
||||
}
|
||||
hir::ClosureKind::Closure => {
|
||||
hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
|
||||
FirstBorrowUsePlaceClosure { place: borrow_place_desc, var_span }
|
||||
}
|
||||
}
|
||||
@ -1166,7 +1185,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
);
|
||||
|
||||
borrow_spans.var_subdiag(
|
||||
Some(self.dcx()),
|
||||
self.dcx(),
|
||||
&mut err,
|
||||
Some(gen_borrow_kind),
|
||||
|kind, var_span| {
|
||||
@ -1175,7 +1194,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
hir::ClosureKind::Coroutine(_) => {
|
||||
SecondBorrowUsePlaceCoroutine { place: desc_place, var_span }
|
||||
}
|
||||
hir::ClosureKind::Closure => {
|
||||
hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
|
||||
SecondBorrowUsePlaceClosure { place: desc_place, var_span }
|
||||
}
|
||||
}
|
||||
@ -1200,14 +1219,108 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
);
|
||||
|
||||
self.suggest_using_local_if_applicable(&mut err, location, issued_borrow, explanation);
|
||||
self.suggest_copy_for_type_in_cloned_ref(&mut err, place);
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
fn suggest_copy_for_type_in_cloned_ref(&self, err: &mut Diag<'tcx>, place: Place<'tcx>) {
|
||||
let tcx = self.infcx.tcx;
|
||||
let hir = tcx.hir();
|
||||
let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else { return };
|
||||
struct FindUselessClone<'hir> {
|
||||
pub clones: Vec<&'hir hir::Expr<'hir>>,
|
||||
}
|
||||
impl<'hir> FindUselessClone<'hir> {
|
||||
pub fn new() -> Self {
|
||||
Self { clones: vec![] }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'v> Visitor<'v> for FindUselessClone<'v> {
|
||||
fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
|
||||
// FIXME: use `lookup_method_for_diagnostic`?
|
||||
if let hir::ExprKind::MethodCall(segment, _rcvr, args, _span) = ex.kind
|
||||
&& segment.ident.name == sym::clone
|
||||
&& args.len() == 0
|
||||
{
|
||||
self.clones.push(ex);
|
||||
}
|
||||
hir::intravisit::walk_expr(self, ex);
|
||||
}
|
||||
}
|
||||
let mut expr_finder = FindUselessClone::new();
|
||||
|
||||
let body = hir.body(body_id).value;
|
||||
expr_finder.visit_expr(body);
|
||||
|
||||
pub struct Holds<'tcx> {
|
||||
ty: Ty<'tcx>,
|
||||
holds: bool,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Holds<'tcx> {
|
||||
type Result = std::ops::ControlFlow<()>;
|
||||
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
|
||||
if t == self.ty {
|
||||
self.holds = true;
|
||||
}
|
||||
t.super_visit_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
let mut types_to_constrain = FxIndexSet::default();
|
||||
|
||||
let local_ty = self.body.local_decls[place.local].ty;
|
||||
let typeck_results = tcx.typeck(self.mir_def_id());
|
||||
let clone = tcx.require_lang_item(LangItem::Clone, Some(body.span));
|
||||
for expr in expr_finder.clones {
|
||||
if let hir::ExprKind::MethodCall(_, rcvr, _, span) = expr.kind
|
||||
&& let Some(rcvr_ty) = typeck_results.node_type_opt(rcvr.hir_id)
|
||||
&& let Some(ty) = typeck_results.node_type_opt(expr.hir_id)
|
||||
&& rcvr_ty == ty
|
||||
&& let ty::Ref(_, inner, _) = rcvr_ty.kind()
|
||||
&& let inner = inner.peel_refs()
|
||||
&& let mut v = (Holds { ty: inner, holds: false })
|
||||
&& let _ = v.visit_ty(local_ty)
|
||||
&& v.holds
|
||||
&& let None = self.infcx.type_implements_trait_shallow(clone, inner, self.param_env)
|
||||
{
|
||||
err.span_label(
|
||||
span,
|
||||
format!(
|
||||
"this call doesn't do anything, the result is still `{rcvr_ty}` \
|
||||
because `{inner}` doesn't implement `Clone`",
|
||||
),
|
||||
);
|
||||
types_to_constrain.insert(inner);
|
||||
}
|
||||
}
|
||||
for ty in types_to_constrain {
|
||||
self.suggest_adding_bounds(err, ty, clone, body.span);
|
||||
if let ty::Adt(..) = ty.kind() {
|
||||
// The type doesn't implement Clone.
|
||||
let trait_ref = ty::Binder::dummy(ty::TraitRef::new(self.infcx.tcx, clone, [ty]));
|
||||
let obligation = Obligation::new(
|
||||
self.infcx.tcx,
|
||||
ObligationCause::dummy(),
|
||||
self.param_env,
|
||||
trait_ref,
|
||||
);
|
||||
self.infcx.err_ctxt().suggest_derive(
|
||||
&obligation,
|
||||
err,
|
||||
trait_ref.to_predicate(self.infcx.tcx),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, err))]
|
||||
fn suggest_using_local_if_applicable(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
err: &mut Diag<'_>,
|
||||
location: Location,
|
||||
issued_borrow: &BorrowData<'tcx>,
|
||||
explanation: BorrowExplanation<'tcx>,
|
||||
@ -1303,7 +1416,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
|
||||
fn suggest_slice_method_if_applicable(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
err: &mut Diag<'_>,
|
||||
place: Place<'tcx>,
|
||||
borrowed_place: Place<'tcx>,
|
||||
) {
|
||||
@ -1412,7 +1525,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
/// ```
|
||||
pub(crate) fn explain_iterator_advancement_in_for_loop_if_applicable(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
err: &mut Diag<'_>,
|
||||
span: Span,
|
||||
issued_spans: &UseSpans<'tcx>,
|
||||
) {
|
||||
@ -1538,7 +1651,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
// A bare path doesn't need a `let` assignment, it's already a simple
|
||||
// binding access.
|
||||
// As a new binding wasn't added, we don't need to modify the advancing call.
|
||||
sugg.push((loop_span.with_hi(pat_span.lo()), format!("while let Some(")));
|
||||
sugg.push((loop_span.with_hi(pat_span.lo()), "while let Some(".to_string()));
|
||||
sugg.push((
|
||||
pat_span.shrink_to_hi().with_hi(head.span.lo()),
|
||||
") = ".to_string(),
|
||||
@ -1599,7 +1712,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
/// ```
|
||||
fn suggest_using_closure_argument_instead_of_capture(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
err: &mut Diag<'_>,
|
||||
borrowed_place: Place<'tcx>,
|
||||
issued_spans: &UseSpans<'tcx>,
|
||||
) {
|
||||
@ -1660,8 +1773,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
|
||||
// Check that the parent of the closure is a method call,
|
||||
// with receiver matching with local's type (modulo refs)
|
||||
let parent = hir.parent_id(closure_expr.hir_id);
|
||||
if let hir::Node::Expr(parent) = tcx.hir_node(parent) {
|
||||
if let hir::Node::Expr(parent) = tcx.parent_hir_node(closure_expr.hir_id) {
|
||||
if let hir::ExprKind::MethodCall(_, recv, ..) = parent.kind {
|
||||
let recv_ty = typeck_results.expr_ty(recv);
|
||||
|
||||
@ -1734,7 +1846,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
|
||||
fn suggest_binding_for_closure_capture_self(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
err: &mut Diag<'_>,
|
||||
issued_spans: &UseSpans<'tcx>,
|
||||
) {
|
||||
let UseSpans::ClosureUse { capture_kind_span, .. } = issued_spans else { return };
|
||||
@ -1759,7 +1871,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
fn_decl: hir::FnDecl { inputs, .. },
|
||||
..
|
||||
}) = e.kind
|
||||
&& let Some(hir::Node::Expr(body)) = self.tcx.opt_hir_node(body.hir_id)
|
||||
&& let hir::Node::Expr(body) = self.tcx.hir_node(body.hir_id)
|
||||
{
|
||||
self.suggest_arg = "this: &Self".to_string();
|
||||
if inputs.len() > 0 {
|
||||
@ -1825,11 +1937,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(hir::Node::ImplItem(hir::ImplItem {
|
||||
if let hir::Node::ImplItem(hir::ImplItem {
|
||||
kind: hir::ImplItemKind::Fn(_fn_sig, body_id),
|
||||
..
|
||||
})) = self.infcx.tcx.opt_hir_node(self.mir_hir_id())
|
||||
&& let Some(hir::Node::Expr(expr)) = self.infcx.tcx.opt_hir_node(body_id.hir_id)
|
||||
}) = self.infcx.tcx.hir_node(self.mir_hir_id())
|
||||
&& let hir::Node::Expr(expr) = self.infcx.tcx.hir_node(body_id.hir_id)
|
||||
{
|
||||
let mut finder = ExpressionFinder {
|
||||
capture_span: *capture_kind_span,
|
||||
@ -1981,21 +2093,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
kind: Option<WriteKind>,
|
||||
) {
|
||||
let drop_span = place_span.1;
|
||||
let root_place =
|
||||
self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
|
||||
let borrowed_local = borrow.borrowed_place.local;
|
||||
|
||||
let borrow_spans = self.retrieve_borrow_spans(borrow);
|
||||
let borrow_span = borrow_spans.var_or_use_path_span();
|
||||
|
||||
assert!(root_place.projection.is_empty());
|
||||
let proper_span = self.body.local_decls[root_place.local].source_info.span;
|
||||
let proper_span = self.body.local_decls[borrowed_local].source_info.span;
|
||||
|
||||
let root_place_projection = self.infcx.tcx.mk_place_elems(root_place.projection);
|
||||
|
||||
if self.access_place_error_reported.contains(&(
|
||||
Place { local: root_place.local, projection: root_place_projection },
|
||||
borrow_span,
|
||||
)) {
|
||||
if self.access_place_error_reported.contains(&(Place::from(borrowed_local), borrow_span)) {
|
||||
debug!(
|
||||
"suppressing access_place error when borrow doesn't live long enough for {:?}",
|
||||
borrow_span
|
||||
@ -2003,12 +2108,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
return;
|
||||
}
|
||||
|
||||
self.access_place_error_reported.insert((
|
||||
Place { local: root_place.local, projection: root_place_projection },
|
||||
borrow_span,
|
||||
));
|
||||
self.access_place_error_reported.insert((Place::from(borrowed_local), borrow_span));
|
||||
|
||||
let borrowed_local = borrow.borrowed_place.local;
|
||||
if self.body.local_decls[borrowed_local].is_ref_to_thread_local() {
|
||||
let err =
|
||||
self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span);
|
||||
@ -2129,7 +2230,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
drop_span: Span,
|
||||
borrow_spans: UseSpans<'tcx>,
|
||||
explanation: BorrowExplanation<'tcx>,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> Diag<'tcx> {
|
||||
debug!(
|
||||
"report_local_value_does_not_live_long_enough(\
|
||||
{:?}, {:?}, {:?}, {:?}, {:?}\
|
||||
@ -2219,7 +2320,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
err.span_label(borrow_span, "borrowed value does not live long enough");
|
||||
err.span_label(drop_span, format!("`{name}` dropped here while still borrowed"));
|
||||
|
||||
borrow_spans.args_subdiag(&mut err, |args_span| {
|
||||
borrow_spans.args_subdiag(self.dcx(), &mut err, |args_span| {
|
||||
crate::session_diagnostics::CaptureArgLabel::Capture {
|
||||
is_within: borrow_spans.for_coroutine(),
|
||||
args_span,
|
||||
@ -2304,7 +2405,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
&mut self,
|
||||
drop_span: Span,
|
||||
borrow_span: Span,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> Diag<'tcx> {
|
||||
debug!(
|
||||
"report_thread_local_value_does_not_live_long_enough(\
|
||||
{:?}, {:?}\
|
||||
@ -2329,7 +2430,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
borrow_spans: UseSpans<'tcx>,
|
||||
proper_span: Span,
|
||||
explanation: BorrowExplanation<'tcx>,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> Diag<'tcx> {
|
||||
if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } =
|
||||
explanation
|
||||
{
|
||||
@ -2397,8 +2498,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
let proper_span = proper_span.source_callsite();
|
||||
if let Some(scope) = self.body.source_scopes.get(source_info.scope)
|
||||
&& let ClearCrossCrate::Set(scope_data) = &scope.local_data
|
||||
&& let Some(node) = self.infcx.tcx.opt_hir_node(scope_data.lint_root)
|
||||
&& let Some(id) = node.body_id()
|
||||
&& let Some(id) = self.infcx.tcx.hir_node(scope_data.lint_root).body_id()
|
||||
&& let hir::ExprKind::Block(block, _) = self.infcx.tcx.hir().body(id).value.kind
|
||||
{
|
||||
for stmt in block.stmts {
|
||||
@ -2440,7 +2540,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
"consider consuming the `{ty}` when turning it into an \
|
||||
`Iterator`",
|
||||
),
|
||||
"into_iter".to_string(),
|
||||
"into_iter",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
@ -2479,7 +2579,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
None,
|
||||
);
|
||||
|
||||
borrow_spans.args_subdiag(&mut err, |args_span| {
|
||||
borrow_spans.args_subdiag(self.dcx(), &mut err, |args_span| {
|
||||
crate::session_diagnostics::CaptureArgLabel::Capture {
|
||||
is_within: borrow_spans.for_coroutine(),
|
||||
args_span,
|
||||
@ -2496,7 +2596,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
return_span: Span,
|
||||
category: ConstraintCategory<'tcx>,
|
||||
opt_place_desc: Option<&String>,
|
||||
) -> Option<DiagnosticBuilder<'cx>> {
|
||||
) -> Option<Diag<'tcx>> {
|
||||
let return_kind = match category {
|
||||
ConstraintCategory::Return(_) => "return",
|
||||
ConstraintCategory::Yield => "yield",
|
||||
@ -2531,9 +2631,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
};
|
||||
(format!("{local_kind}`{place_desc}`"), format!("`{place_desc}` is borrowed here"))
|
||||
} else {
|
||||
let root_place =
|
||||
self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
|
||||
let local = root_place.local;
|
||||
let local = borrow.borrowed_place.local;
|
||||
match self.body.local_kind(local) {
|
||||
LocalKind::Arg => (
|
||||
"function parameter".to_string(),
|
||||
@ -2591,7 +2689,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
constraint_span: Span,
|
||||
captured_var: &str,
|
||||
scope: &str,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> Diag<'tcx> {
|
||||
let tcx = self.infcx.tcx;
|
||||
let args_span = use_span.args_or_use();
|
||||
|
||||
@ -2699,7 +2797,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
upvar_span: Span,
|
||||
upvar_name: Symbol,
|
||||
escape_span: Span,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
) -> Diag<'tcx> {
|
||||
let tcx = self.infcx.tcx;
|
||||
|
||||
let escapes_from = tcx.def_descr(self.mir_def_id().to_def_id());
|
||||
@ -2938,11 +3036,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
"assign",
|
||||
);
|
||||
|
||||
loan_spans.var_subdiag(None, &mut err, Some(loan.kind), |kind, var_span| {
|
||||
loan_spans.var_subdiag(self.dcx(), &mut err, Some(loan.kind), |kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span },
|
||||
hir::ClosureKind::Closure => BorrowUseInClosure { var_span },
|
||||
hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
|
||||
BorrowUseInClosure { var_span }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -2954,11 +3054,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
|
||||
let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place);
|
||||
|
||||
loan_spans.var_subdiag(None, &mut err, Some(loan.kind), |kind, var_span| {
|
||||
loan_spans.var_subdiag(self.dcx(), &mut err, Some(loan.kind), |kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span },
|
||||
hir::ClosureKind::Closure => BorrowUseInClosure { var_span },
|
||||
hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
|
||||
BorrowUseInClosure { var_span }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -2977,7 +3079,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
self.buffer_error(err);
|
||||
}
|
||||
|
||||
fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut Diagnostic) {
|
||||
fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut Diag<'_>) {
|
||||
let tcx = self.infcx.tcx;
|
||||
if let (
|
||||
Some(Terminator {
|
||||
@ -3017,7 +3119,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
/// assignment to `x.f`).
|
||||
pub(crate) fn report_illegal_reassignment(
|
||||
&mut self,
|
||||
_location: Location,
|
||||
(place, span): (Place<'tcx>, Span),
|
||||
assigned_span: Span,
|
||||
err_place: Place<'tcx>,
|
||||
@ -3158,7 +3259,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
|
||||
// Define a fallback for when we can't match a closure.
|
||||
let fallback = || {
|
||||
let is_closure = self.infcx.tcx.is_closure_or_coroutine(self.mir_def_id().to_def_id());
|
||||
let is_closure = self.infcx.tcx.is_closure_like(self.mir_def_id().to_def_id());
|
||||
if is_closure {
|
||||
None
|
||||
} else {
|
||||
@ -3369,7 +3470,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
sig: ty::PolyFnSig<'tcx>,
|
||||
) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
|
||||
debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig);
|
||||
let is_closure = self.infcx.tcx.is_closure_or_coroutine(did.to_def_id());
|
||||
let is_closure = self.infcx.tcx.is_closure_like(did.to_def_id());
|
||||
let fn_hir_id = self.infcx.tcx.local_def_id_to_hir_id(did);
|
||||
let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(fn_hir_id)?;
|
||||
|
||||
@ -3513,7 +3614,7 @@ enum AnnotatedBorrowFnSignature<'tcx> {
|
||||
impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
|
||||
/// Annotate the provided diagnostic with information about borrow from the fn signature that
|
||||
/// helps explain.
|
||||
pub(crate) fn emit(&self, cx: &mut MirBorrowckCtxt<'_, 'tcx>, diag: &mut Diagnostic) -> String {
|
||||
pub(crate) fn emit(&self, cx: &mut MirBorrowckCtxt<'_, 'tcx>, diag: &mut Diag<'_>) -> String {
|
||||
match self {
|
||||
&AnnotatedBorrowFnSignature::Closure { argument_ty, argument_span } => {
|
||||
diag.span_label(
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
//! Print diagnostics to explain why values are borrowed.
|
||||
|
||||
use rustc_errors::{Applicability, Diagnostic};
|
||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
|
||||
use rustc_errors::{Applicability, Diag};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_index::IndexSlice;
|
||||
@ -62,7 +65,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
local_names: &IndexSlice<Local, Option<Symbol>>,
|
||||
err: &mut Diagnostic,
|
||||
err: &mut Diag<'_>,
|
||||
borrow_desc: &str,
|
||||
borrow_span: Option<Span>,
|
||||
multiple_borrow_span: Option<(Span, Span)>,
|
||||
@ -87,7 +90,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
||||
if let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = expr.kind
|
||||
&& let [hir::PathSegment { ident, args: None, .. }] = p.segments
|
||||
&& let hir::def::Res::Local(hir_id) = p.res
|
||||
&& let Some(hir::Node::Pat(pat)) = tcx.opt_hir_node(hir_id)
|
||||
&& let hir::Node::Pat(pat) = tcx.hir_node(hir_id)
|
||||
{
|
||||
err.span_label(pat.span, format!("binding `{ident}` declared here"));
|
||||
}
|
||||
@ -303,7 +306,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
||||
fn add_object_lifetime_default_note(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
err: &mut Diag<'_>,
|
||||
unsize_ty: Ty<'tcx>,
|
||||
) {
|
||||
if let ty::Adt(def, args) = unsize_ty.kind() {
|
||||
@ -356,7 +359,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
||||
|
||||
fn add_lifetime_bound_suggestion_to_diagnostic(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
err: &mut Diag<'_>,
|
||||
category: &ConstraintCategory<'tcx>,
|
||||
span: Span,
|
||||
region_name: &RegionName,
|
||||
|
||||
@ -1,6 +1,3 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use rustc_middle::mir::visit::{PlaceContext, Visitor};
|
||||
|
||||
@ -1,6 +1,3 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ use crate::session_diagnostics::{
|
||||
CaptureVarKind, CaptureVarPathUseCause, OnClosureNote,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use rustc_errors::{Applicability, Diagnostic};
|
||||
use rustc_errors::{Applicability, Diag};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorKind, Namespace};
|
||||
use rustc_hir::CoroutineKind;
|
||||
@ -76,11 +76,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
/// LL | for (key, value) in dict {
|
||||
/// | ^^^^
|
||||
/// ```
|
||||
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
|
||||
pub(super) fn add_moved_or_invoked_closure_note(
|
||||
&self,
|
||||
location: Location,
|
||||
place: PlaceRef<'tcx>,
|
||||
diag: &mut Diagnostic,
|
||||
diag: &mut Diag<'_>,
|
||||
) -> bool {
|
||||
debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place);
|
||||
let mut target = place.local_or_deref_local();
|
||||
@ -124,7 +125,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() {
|
||||
let did = did.expect_local();
|
||||
if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
|
||||
diag.eager_subdiagnostic(
|
||||
diag.subdiagnostic(
|
||||
self.dcx(),
|
||||
OnClosureNote::InvokedTwice {
|
||||
place_name: &ty::place_to_string_for_capture(
|
||||
@ -146,7 +147,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() {
|
||||
let did = did.expect_local();
|
||||
if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
|
||||
diag.eager_subdiagnostic(
|
||||
diag.subdiagnostic(
|
||||
self.dcx(),
|
||||
OnClosureNote::MovedTwice {
|
||||
place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place),
|
||||
@ -585,21 +586,25 @@ impl UseSpans<'_> {
|
||||
}
|
||||
|
||||
/// Add a span label to the arguments of the closure, if it exists.
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
pub(super) fn args_subdiag(
|
||||
self,
|
||||
err: &mut Diagnostic,
|
||||
dcx: &rustc_errors::DiagCtxt,
|
||||
err: &mut Diag<'_>,
|
||||
f: impl FnOnce(Span) -> CaptureArgLabel,
|
||||
) {
|
||||
if let UseSpans::ClosureUse { args_span, .. } = self {
|
||||
err.subdiagnostic(f(args_span));
|
||||
err.subdiagnostic(dcx, f(args_span));
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a span label to the use of the captured variable, if it exists.
|
||||
/// only adds label to the `path_span`
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
pub(super) fn var_path_only_subdiag(
|
||||
self,
|
||||
err: &mut Diagnostic,
|
||||
dcx: &rustc_errors::DiagCtxt,
|
||||
err: &mut Diag<'_>,
|
||||
action: crate::InitializationRequiringAction,
|
||||
) {
|
||||
use crate::InitializationRequiringAction::*;
|
||||
@ -607,54 +612,61 @@ impl UseSpans<'_> {
|
||||
if let UseSpans::ClosureUse { closure_kind, path_span, .. } = self {
|
||||
match closure_kind {
|
||||
hir::ClosureKind::Coroutine(_) => {
|
||||
err.subdiagnostic(match action {
|
||||
Borrow => BorrowInCoroutine { path_span },
|
||||
MatchOn | Use => UseInCoroutine { path_span },
|
||||
Assignment => AssignInCoroutine { path_span },
|
||||
PartialAssignment => AssignPartInCoroutine { path_span },
|
||||
});
|
||||
err.subdiagnostic(
|
||||
dcx,
|
||||
match action {
|
||||
Borrow => BorrowInCoroutine { path_span },
|
||||
MatchOn | Use => UseInCoroutine { path_span },
|
||||
Assignment => AssignInCoroutine { path_span },
|
||||
PartialAssignment => AssignPartInCoroutine { path_span },
|
||||
},
|
||||
);
|
||||
}
|
||||
hir::ClosureKind::Closure => {
|
||||
err.subdiagnostic(match action {
|
||||
Borrow => BorrowInClosure { path_span },
|
||||
MatchOn | Use => UseInClosure { path_span },
|
||||
Assignment => AssignInClosure { path_span },
|
||||
PartialAssignment => AssignPartInClosure { path_span },
|
||||
});
|
||||
hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
|
||||
err.subdiagnostic(
|
||||
dcx,
|
||||
match action {
|
||||
Borrow => BorrowInClosure { path_span },
|
||||
MatchOn | Use => UseInClosure { path_span },
|
||||
Assignment => AssignInClosure { path_span },
|
||||
PartialAssignment => AssignPartInClosure { path_span },
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a subdiagnostic to the use of the captured variable, if it exists.
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
pub(super) fn var_subdiag(
|
||||
self,
|
||||
dcx: Option<&rustc_errors::DiagCtxt>,
|
||||
err: &mut Diagnostic,
|
||||
dcx: &rustc_errors::DiagCtxt,
|
||||
err: &mut Diag<'_>,
|
||||
kind: Option<rustc_middle::mir::BorrowKind>,
|
||||
f: impl FnOnce(hir::ClosureKind, Span) -> CaptureVarCause,
|
||||
) {
|
||||
if let UseSpans::ClosureUse { closure_kind, capture_kind_span, path_span, .. } = self {
|
||||
if capture_kind_span != path_span {
|
||||
err.subdiagnostic(match kind {
|
||||
Some(kd) => match kd {
|
||||
rustc_middle::mir::BorrowKind::Shared
|
||||
| rustc_middle::mir::BorrowKind::Fake => {
|
||||
CaptureVarKind::Immut { kind_span: capture_kind_span }
|
||||
}
|
||||
err.subdiagnostic(
|
||||
dcx,
|
||||
match kind {
|
||||
Some(kd) => match kd {
|
||||
rustc_middle::mir::BorrowKind::Shared
|
||||
| rustc_middle::mir::BorrowKind::Fake => {
|
||||
CaptureVarKind::Immut { kind_span: capture_kind_span }
|
||||
}
|
||||
|
||||
rustc_middle::mir::BorrowKind::Mut { .. } => {
|
||||
CaptureVarKind::Mut { kind_span: capture_kind_span }
|
||||
}
|
||||
rustc_middle::mir::BorrowKind::Mut { .. } => {
|
||||
CaptureVarKind::Mut { kind_span: capture_kind_span }
|
||||
}
|
||||
},
|
||||
None => CaptureVarKind::Move { kind_span: capture_kind_span },
|
||||
},
|
||||
None => CaptureVarKind::Move { kind_span: capture_kind_span },
|
||||
});
|
||||
);
|
||||
};
|
||||
let diag = f(closure_kind, path_span);
|
||||
match dcx {
|
||||
Some(hd) => err.eager_subdiagnostic(hd, diag),
|
||||
None => err.subdiagnostic(diag),
|
||||
};
|
||||
err.subdiagnostic(dcx, diag);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1000,9 +1012,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
self.borrow_spans(span, borrow.reserve_location)
|
||||
}
|
||||
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
fn explain_captures(
|
||||
&mut self,
|
||||
err: &mut Diagnostic,
|
||||
err: &mut Diag<'_>,
|
||||
span: Span,
|
||||
move_span: Span,
|
||||
move_spans: UseSpans<'tcx>,
|
||||
@ -1025,26 +1039,40 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
CallKind::FnCall { fn_trait_id, .. }
|
||||
if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() =>
|
||||
{
|
||||
err.subdiagnostic(CaptureReasonLabel::Call {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
});
|
||||
err.subdiagnostic(CaptureReasonNote::FnOnceMoveInCall { var_span });
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonLabel::Call {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
},
|
||||
);
|
||||
err.subdiagnostic(self.dcx(), CaptureReasonNote::FnOnceMoveInCall { var_span });
|
||||
}
|
||||
CallKind::Operator { self_arg, .. } => {
|
||||
CallKind::Operator { self_arg, trait_id, .. } => {
|
||||
let self_arg = self_arg.unwrap();
|
||||
err.subdiagnostic(CaptureReasonLabel::OperatorUse {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonLabel::OperatorUse {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
},
|
||||
);
|
||||
if self.fn_self_span_reported.insert(fn_span) {
|
||||
err.subdiagnostic(CaptureReasonNote::LhsMoveByOperator {
|
||||
span: self_arg.span,
|
||||
});
|
||||
let lang = self.infcx.tcx.lang_items();
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
if [lang.not_trait(), lang.deref_trait(), lang.neg_trait()]
|
||||
.contains(&Some(trait_id))
|
||||
{
|
||||
CaptureReasonNote::UnOpMoveByOperator { span: self_arg.span }
|
||||
} else {
|
||||
CaptureReasonNote::LhsMoveByOperator { span: self_arg.span }
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
CallKind::Normal { self_arg, desugaring, method_did, method_args } => {
|
||||
@ -1061,11 +1089,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
);
|
||||
|
||||
let func = tcx.def_path_str(method_did);
|
||||
err.subdiagnostic(CaptureReasonNote::FuncTakeSelf {
|
||||
func,
|
||||
place_name: place_name.clone(),
|
||||
span: self_arg.span,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonNote::FuncTakeSelf {
|
||||
func,
|
||||
place_name: place_name.clone(),
|
||||
span: self_arg.span,
|
||||
},
|
||||
);
|
||||
}
|
||||
let parent_did = tcx.parent(method_did);
|
||||
let parent_self_ty =
|
||||
@ -1079,7 +1110,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
|
||||
});
|
||||
if is_option_or_result && maybe_reinitialized_locations_is_empty {
|
||||
err.subdiagnostic(CaptureReasonLabel::BorrowContent { var_span });
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonLabel::BorrowContent { var_span },
|
||||
);
|
||||
}
|
||||
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
|
||||
let ty = moved_place.ty(self.body, tcx).ty;
|
||||
@ -1093,18 +1127,24 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
_ => false,
|
||||
};
|
||||
if suggest {
|
||||
err.subdiagnostic(CaptureReasonSuggest::IterateSlice {
|
||||
ty,
|
||||
span: move_span.shrink_to_lo(),
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonSuggest::IterateSlice {
|
||||
ty,
|
||||
span: move_span.shrink_to_lo(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
err.subdiagnostic(CaptureReasonLabel::ImplicitCall {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonLabel::ImplicitCall {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
},
|
||||
);
|
||||
// If the moved place was a `&mut` ref, then we can
|
||||
// suggest to reborrow it where it was moved, so it
|
||||
// will still be valid by the time we get to the usage.
|
||||
@ -1128,19 +1168,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
}
|
||||
} else {
|
||||
if let Some((CallDesugaringKind::Await, _)) = desugaring {
|
||||
err.subdiagnostic(CaptureReasonLabel::Await {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonLabel::Await {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
err.subdiagnostic(CaptureReasonLabel::MethodCall {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonLabel::MethodCall {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
},
|
||||
);
|
||||
}
|
||||
// Erase and shadow everything that could be passed to the new infcx.
|
||||
let ty = moved_place.ty(self.body, tcx).ty;
|
||||
@ -1155,7 +1201,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
)
|
||||
&& self.infcx.can_eq(self.param_env, ty, self_ty)
|
||||
{
|
||||
err.eager_subdiagnostic(
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonSuggest::FreshReborrow {
|
||||
span: move_span.shrink_to_hi(),
|
||||
@ -1187,20 +1233,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
{
|
||||
let msg = match &errors[..] {
|
||||
[] => "you can `clone` the value and consume it, but this \
|
||||
might not be your desired behavior"
|
||||
might not be your desired behavior"
|
||||
.to_string(),
|
||||
[error] => {
|
||||
format!(
|
||||
"you could `clone` the value and consume it, if \
|
||||
the `{}` trait bound could be satisfied",
|
||||
"you could `clone` the value and consume it, if the \
|
||||
`{}` trait bound could be satisfied",
|
||||
error.obligation.predicate,
|
||||
)
|
||||
}
|
||||
[errors @ .., last] => {
|
||||
format!(
|
||||
"you could `clone` the value and consume it, if \
|
||||
the following trait bounds could be satisfied: {} \
|
||||
and `{}`",
|
||||
"you could `clone` the value and consume it, if the \
|
||||
following trait bounds could be satisfied: \
|
||||
{} and `{}`",
|
||||
errors
|
||||
.iter()
|
||||
.map(|e| format!("`{}`", e.obligation.predicate))
|
||||
@ -1239,21 +1285,24 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
}
|
||||
} else {
|
||||
if move_span != span || is_loop_message {
|
||||
err.subdiagnostic(CaptureReasonLabel::MovedHere {
|
||||
move_span,
|
||||
is_partial,
|
||||
is_move_msg,
|
||||
is_loop_message,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonLabel::MovedHere {
|
||||
move_span,
|
||||
is_partial,
|
||||
is_move_msg,
|
||||
is_loop_message,
|
||||
},
|
||||
);
|
||||
}
|
||||
// If the move error occurs due to a loop, don't show
|
||||
// another message for the same span
|
||||
if !is_loop_message {
|
||||
move_spans.var_subdiag(None, err, None, |kind, var_span| match kind {
|
||||
move_spans.var_subdiag(self.dcx(), err, None, |kind, var_span| match kind {
|
||||
hir::ClosureKind::Coroutine(_) => {
|
||||
CaptureVarCause::PartialMoveUseInCoroutine { var_span, is_partial }
|
||||
}
|
||||
hir::ClosureKind::Closure => {
|
||||
hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
|
||||
CaptureVarCause::PartialMoveUseInClosure { var_span, is_partial }
|
||||
}
|
||||
})
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder};
|
||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
|
||||
use rustc_errors::{Applicability, Diag};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex};
|
||||
@ -284,11 +287,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
self.buffer_error(err);
|
||||
}
|
||||
|
||||
fn report_cannot_move_from_static(
|
||||
&mut self,
|
||||
place: Place<'tcx>,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
fn report_cannot_move_from_static(&mut self, place: Place<'tcx>, span: Span) -> Diag<'tcx> {
|
||||
let description = if place.projection.len() == 1 {
|
||||
format!("static item {}", self.describe_any_place(place.as_ref()))
|
||||
} else {
|
||||
@ -310,7 +309,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
deref_target_place: Place<'tcx>,
|
||||
span: Span,
|
||||
use_spans: Option<UseSpans<'tcx>>,
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
) -> Diag<'tcx> {
|
||||
// Inspect the type of the content behind the
|
||||
// borrow to provide feedback about why this
|
||||
// was a move rather than a copy.
|
||||
@ -434,7 +433,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
err
|
||||
}
|
||||
|
||||
fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diagnostic, span: Span) {
|
||||
fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span: Span) {
|
||||
match error {
|
||||
GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => {
|
||||
self.add_borrow_suggestions(err, span);
|
||||
@ -445,12 +444,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
None => "value".to_string(),
|
||||
};
|
||||
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move: false,
|
||||
ty: place_ty,
|
||||
place: &place_desc,
|
||||
span,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move: false,
|
||||
ty: place_ty,
|
||||
place: &place_desc,
|
||||
span,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
binds_to.sort();
|
||||
binds_to.dedup();
|
||||
@ -472,14 +474,17 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
Some(desc) => format!("`{desc}`"),
|
||||
None => "value".to_string(),
|
||||
};
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move: false,
|
||||
ty: place_ty,
|
||||
place: &place_desc,
|
||||
span,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move: false,
|
||||
ty: place_ty,
|
||||
place: &place_desc,
|
||||
span,
|
||||
},
|
||||
);
|
||||
|
||||
use_spans.args_subdiag(err, |args_span| {
|
||||
use_spans.args_subdiag(self.dcx(), err, |args_span| {
|
||||
crate::session_diagnostics::CaptureArgLabel::MoveOutPlace {
|
||||
place: place_desc,
|
||||
args_span,
|
||||
@ -491,7 +496,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn add_borrow_suggestions(&self, err: &mut Diagnostic, span: Span) {
|
||||
fn add_borrow_suggestions(&self, err: &mut Diag<'_>, span: Span) {
|
||||
match self.infcx.tcx.sess.source_map().span_to_snippet(span) {
|
||||
Ok(snippet) if snippet.starts_with('*') => {
|
||||
err.span_suggestion_verbose(
|
||||
@ -512,7 +517,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn add_move_error_suggestions(&self, err: &mut Diagnostic, binds_to: &[Local]) {
|
||||
fn add_move_error_suggestions(&self, err: &mut Diag<'_>, binds_to: &[Local]) {
|
||||
let mut suggestions: Vec<(Span, String, String)> = Vec::new();
|
||||
for local in binds_to {
|
||||
let bind_to = &self.body.local_decls[*local];
|
||||
@ -564,7 +569,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn add_move_error_details(&self, err: &mut Diagnostic, binds_to: &[Local]) {
|
||||
fn add_move_error_details(&self, err: &mut Diag<'_>, binds_to: &[Local]) {
|
||||
for (j, local) in binds_to.iter().enumerate() {
|
||||
let bind_to = &self.body.local_decls[*local];
|
||||
let binding_span = bind_to.source_info.span;
|
||||
@ -577,12 +582,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
|
||||
if binds_to.len() == 1 {
|
||||
let place_desc = &format!("`{}`", self.local_names[*local].unwrap());
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move: false,
|
||||
ty: bind_to.ty,
|
||||
place: place_desc,
|
||||
span: binding_span,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move: false,
|
||||
ty: bind_to.ty,
|
||||
place: place_desc,
|
||||
span: binding_span,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -598,7 +606,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
/// expansion of a packed struct.
|
||||
/// Such errors happen because derive macro expansions shy away from taking
|
||||
/// references to the struct's fields since doing so would be undefined behaviour
|
||||
fn add_note_for_packed_struct_derive(&self, err: &mut Diagnostic, local: Local) {
|
||||
fn add_note_for_packed_struct_derive(&self, err: &mut Diag<'_>, local: Local) {
|
||||
let local_place: PlaceRef<'tcx> = local.into();
|
||||
let local_ty = local_place.ty(self.body.local_decls(), self.infcx.tcx).ty.peel_refs();
|
||||
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
|
||||
use core::ops::ControlFlow;
|
||||
use hir::ExprKind;
|
||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder};
|
||||
use rustc_errors::{Applicability, Diag};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::Node;
|
||||
@ -64,7 +68,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
local,
|
||||
projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
|
||||
} => {
|
||||
debug_assert!(is_closure_or_coroutine(
|
||||
debug_assert!(is_closure_like(
|
||||
Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty
|
||||
));
|
||||
|
||||
@ -123,9 +127,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
{
|
||||
item_msg = access_place_desc;
|
||||
debug_assert!(self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_ref());
|
||||
debug_assert!(is_closure_or_coroutine(
|
||||
the_place_err.ty(self.body, self.infcx.tcx).ty
|
||||
));
|
||||
debug_assert!(is_closure_like(the_place_err.ty(self.body, self.infcx.tcx).ty));
|
||||
|
||||
reason = if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
|
||||
", as it is a captured variable in a `Fn` closure".to_string()
|
||||
@ -198,12 +200,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
{
|
||||
let span = self.body.local_decls[local].source_info.span;
|
||||
mut_error = Some(span);
|
||||
if let Some((buffer, c)) = self.get_buffered_mut_error(span) {
|
||||
if let Some((buffered_err, c)) = self.get_buffered_mut_error(span) {
|
||||
// We've encountered a second (or more) attempt to mutably borrow an
|
||||
// immutable binding, so the likely problem is with the binding
|
||||
// declaration, not the use. We collect these in a single diagnostic
|
||||
// and make the binding the primary span of the error.
|
||||
err = buffer;
|
||||
err = buffered_err;
|
||||
count = c + 1;
|
||||
if count == 2 {
|
||||
err.replace_span_with(span, false);
|
||||
@ -228,7 +230,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
}
|
||||
if suggest {
|
||||
borrow_spans.var_subdiag(
|
||||
None,
|
||||
self.dcx(),
|
||||
&mut err,
|
||||
Some(mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }),
|
||||
|_kind, var_span| {
|
||||
@ -386,7 +388,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
local,
|
||||
projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
|
||||
} => {
|
||||
debug_assert!(is_closure_or_coroutine(
|
||||
debug_assert!(is_closure_like(
|
||||
Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty
|
||||
));
|
||||
|
||||
@ -396,7 +398,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
|
||||
let upvar_hir_id = captured_place.get_root_variable();
|
||||
|
||||
if let Some(Node::Pat(pat)) = self.infcx.tcx.opt_hir_node(upvar_hir_id)
|
||||
if let Node::Pat(pat) = self.infcx.tcx.hir_node(upvar_hir_id)
|
||||
&& let hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, upvar_ident, _) =
|
||||
pat.kind
|
||||
{
|
||||
@ -539,7 +541,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn suggest_map_index_mut_alternatives(&self, ty: Ty<'tcx>, err: &mut Diagnostic, span: Span) {
|
||||
fn suggest_map_index_mut_alternatives(&self, ty: Ty<'tcx>, err: &mut Diag<'tcx>, span: Span) {
|
||||
let Some(adt) = ty.ty_adt_def() else { return };
|
||||
let did = adt.did();
|
||||
if self.infcx.tcx.is_diagnostic_item(sym::HashMap, did)
|
||||
@ -547,7 +549,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
{
|
||||
struct V<'a, 'tcx> {
|
||||
assign_span: Span,
|
||||
err: &'a mut Diagnostic,
|
||||
err: &'a mut Diag<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
suggested: bool,
|
||||
}
|
||||
@ -556,7 +558,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
hir::intravisit::walk_stmt(self, stmt);
|
||||
let expr = match stmt.kind {
|
||||
hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr) => expr,
|
||||
hir::StmtKind::Local(hir::Local { init: Some(expr), .. }) => expr,
|
||||
hir::StmtKind::Let(hir::Local { init: Some(expr), .. }) => expr,
|
||||
_ => {
|
||||
return;
|
||||
}
|
||||
@ -670,11 +672,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
};
|
||||
(
|
||||
true,
|
||||
td.as_local().and_then(|tld| match self.infcx.tcx.opt_hir_node_by_def_id(tld) {
|
||||
Some(Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Trait(_, _, _, _, items),
|
||||
..
|
||||
})) => {
|
||||
td.as_local().and_then(|tld| match self.infcx.tcx.hir_node_by_def_id(tld) {
|
||||
Node::Item(hir::Item { kind: hir::ItemKind::Trait(_, _, _, _, items), .. }) => {
|
||||
let mut f_in_trait_opt = None;
|
||||
for hir::TraitItemRef { id: fi, kind: k, .. } in *items {
|
||||
let hi = fi.hir_id();
|
||||
@ -688,16 +687,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
break;
|
||||
}
|
||||
f_in_trait_opt.and_then(|f_in_trait| {
|
||||
match self.infcx.tcx.opt_hir_node(f_in_trait) {
|
||||
Some(Node::TraitItem(hir::TraitItem {
|
||||
match self.infcx.tcx.hir_node(f_in_trait) {
|
||||
Node::TraitItem(hir::TraitItem {
|
||||
kind:
|
||||
hir::TraitItemKind::Fn(
|
||||
hir::FnSig { decl: hir::FnDecl { inputs, .. }, .. },
|
||||
_,
|
||||
),
|
||||
..
|
||||
})) => {
|
||||
let hir::Ty { span, .. } = inputs[local.index() - 1];
|
||||
}) => {
|
||||
let hir::Ty { span, .. } = *inputs.get(local.index() - 1)?;
|
||||
Some(span)
|
||||
}
|
||||
_ => None,
|
||||
@ -711,7 +710,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
|
||||
fn construct_mut_suggestion_for_local_binding_patterns(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
err: &mut Diag<'_>,
|
||||
local: Local,
|
||||
) {
|
||||
let local_decl = &self.body.local_decls[local];
|
||||
@ -726,30 +725,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
_ => local_decl.source_info.span,
|
||||
};
|
||||
|
||||
struct BindingFinder {
|
||||
span: Span,
|
||||
hir_id: Option<hir::HirId>,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for BindingFinder {
|
||||
fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) {
|
||||
if let hir::StmtKind::Local(local) = s.kind {
|
||||
if local.pat.span == self.span {
|
||||
self.hir_id = Some(local.hir_id);
|
||||
}
|
||||
}
|
||||
hir::intravisit::walk_stmt(self, s);
|
||||
}
|
||||
}
|
||||
|
||||
let def_id = self.body.source.def_id();
|
||||
let hir_id = if let Some(local_def_id) = def_id.as_local()
|
||||
&& let Some(body_id) = self.infcx.tcx.hir().maybe_body_owned_by(local_def_id)
|
||||
{
|
||||
let body = self.infcx.tcx.hir().body(body_id);
|
||||
let mut v = BindingFinder { span: pat_span, hir_id: None };
|
||||
v.visit_body(body);
|
||||
v.hir_id
|
||||
BindingFinder { span: pat_span }.visit_body(body).break_value()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@ -759,10 +740,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
//
|
||||
// `let &b = a;` -> `let &(mut b) = a;`
|
||||
if let Some(hir_id) = hir_id
|
||||
&& let Some(hir::Node::Local(hir::Local {
|
||||
&& let hir::Node::Local(hir::Local {
|
||||
pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. },
|
||||
..
|
||||
})) = self.infcx.tcx.opt_hir_node(hir_id)
|
||||
}) = self.infcx.tcx.hir_node(hir_id)
|
||||
&& let Ok(name) =
|
||||
self.infcx.tcx.sess.source_map().span_to_snippet(local_decl.source_info.span)
|
||||
{
|
||||
@ -789,7 +770,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
tcx: TyCtxt<'_>,
|
||||
closure_local_def_id: hir::def_id::LocalDefId,
|
||||
the_place_err: PlaceRef<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
err: &mut Diag<'_>,
|
||||
) {
|
||||
let tables = tcx.typeck(closure_local_def_id);
|
||||
if let Some((span, closure_kind_origin)) = tcx.closure_kind_origin(closure_local_def_id) {
|
||||
@ -851,24 +832,25 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
|
||||
// Attempt to search similar mutable associated items for suggestion.
|
||||
// In the future, attempt in all path but initially for RHS of for_loop
|
||||
fn suggest_similar_mut_method_for_for_loop(&self, err: &mut Diagnostic, span: Span) {
|
||||
fn suggest_similar_mut_method_for_for_loop(&self, err: &mut Diag<'_>, span: Span) {
|
||||
use hir::{
|
||||
BorrowKind, Expr,
|
||||
ExprKind::{AddrOf, Block, Call, MethodCall},
|
||||
};
|
||||
|
||||
let hir_map = self.infcx.tcx.hir();
|
||||
struct Finder<'tcx> {
|
||||
struct Finder {
|
||||
span: Span,
|
||||
expr: Option<&'tcx Expr<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for Finder<'tcx> {
|
||||
fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
|
||||
if e.span == self.span && self.expr.is_none() {
|
||||
self.expr = Some(e);
|
||||
impl<'tcx> Visitor<'tcx> for Finder {
|
||||
type Result = ControlFlow<&'tcx Expr<'tcx>>;
|
||||
fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) -> Self::Result {
|
||||
if e.span == self.span {
|
||||
ControlFlow::Break(e)
|
||||
} else {
|
||||
hir::intravisit::walk_expr(self, e)
|
||||
}
|
||||
hir::intravisit::walk_expr(self, e);
|
||||
}
|
||||
}
|
||||
if let Some(body_id) = hir_map.maybe_body_owned_by(self.mir_def_id())
|
||||
@ -877,9 +859,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
// `span` corresponds to the expression being iterated, find the `for`-loop desugared
|
||||
// expression with that span in order to identify potential fixes when encountering a
|
||||
// read-only iterator that should be mutable.
|
||||
let mut v = Finder { span, expr: None };
|
||||
v.visit_block(block);
|
||||
if let Some(expr) = v.expr
|
||||
if let ControlFlow::Break(expr) = (Finder { span }).visit_block(block)
|
||||
&& let Call(_, [expr]) = expr.kind
|
||||
{
|
||||
match expr.kind {
|
||||
@ -924,7 +904,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
err.span_suggestion_verbose(
|
||||
expr.span.shrink_to_lo(),
|
||||
"use a mutable iterator instead",
|
||||
"mut ".to_string(),
|
||||
"mut ",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
@ -935,13 +915,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
/// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected.
|
||||
fn expected_fn_found_fn_mut_call(&self, err: &mut Diagnostic, sp: Span, act: &str) {
|
||||
fn expected_fn_found_fn_mut_call(&self, err: &mut Diag<'_>, sp: Span, act: &str) {
|
||||
err.span_label(sp, format!("cannot {act}"));
|
||||
|
||||
let hir = self.infcx.tcx.hir();
|
||||
let closure_id = self.mir_hir_id();
|
||||
let closure_span = self.infcx.tcx.def_span(self.mir_def_id());
|
||||
let fn_call_id = hir.parent_id(closure_id);
|
||||
let fn_call_id = self.infcx.tcx.parent_hir_id(closure_id);
|
||||
let node = self.infcx.tcx.hir_node(fn_call_id);
|
||||
let def_id = hir.enclosing_body_owner(fn_call_id);
|
||||
let mut look_at_return = true;
|
||||
@ -1025,13 +1005,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn suggest_using_iter_mut(&self, err: &mut DiagnosticBuilder<'_>) {
|
||||
fn suggest_using_iter_mut(&self, err: &mut Diag<'_>) {
|
||||
let source = self.body.source;
|
||||
let hir = self.infcx.tcx.hir();
|
||||
if let InstanceDef::Item(def_id) = source.instance
|
||||
&& let Some(Node::Expr(hir::Expr { hir_id, kind, .. })) = hir.get_if_local(def_id)
|
||||
&& let ExprKind::Closure(hir::Closure { kind: hir::ClosureKind::Closure, .. }) = kind
|
||||
&& let Some(Node::Expr(expr)) = hir.find_parent(*hir_id)
|
||||
&& let Node::Expr(expr) = self.infcx.tcx.parent_hir_node(*hir_id)
|
||||
{
|
||||
let mut cur_expr = expr;
|
||||
while let ExprKind::MethodCall(path_segment, recv, _, _) = cur_expr.kind {
|
||||
@ -1066,7 +1046,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn suggest_make_local_mut(&self, err: &mut DiagnosticBuilder<'_>, local: Local, name: Symbol) {
|
||||
fn suggest_make_local_mut(&self, err: &mut Diag<'_>, local: Local, name: Symbol) {
|
||||
let local_decl = &self.body.local_decls[local];
|
||||
|
||||
let (pointer_sigil, pointer_desc) =
|
||||
@ -1178,35 +1158,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
);
|
||||
}
|
||||
Some((false, err_label_span, message)) => {
|
||||
struct BindingFinder {
|
||||
span: Span,
|
||||
hir_id: Option<hir::HirId>,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for BindingFinder {
|
||||
fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) {
|
||||
if let hir::StmtKind::Local(local) = s.kind {
|
||||
if local.pat.span == self.span {
|
||||
self.hir_id = Some(local.hir_id);
|
||||
}
|
||||
}
|
||||
hir::intravisit::walk_stmt(self, s);
|
||||
}
|
||||
}
|
||||
let def_id = self.body.source.def_id();
|
||||
let hir_id = if let Some(local_def_id) = def_id.as_local()
|
||||
&& let Some(body_id) = self.infcx.tcx.hir().maybe_body_owned_by(local_def_id)
|
||||
{
|
||||
let body = self.infcx.tcx.hir().body(body_id);
|
||||
let mut v = BindingFinder { span: err_label_span, hir_id: None };
|
||||
v.visit_body(body);
|
||||
v.hir_id
|
||||
BindingFinder { span: err_label_span }.visit_body(body).break_value()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(hir_id) = hir_id
|
||||
&& let Some(hir::Node::Local(local)) = self.infcx.tcx.opt_hir_node(hir_id)
|
||||
&& let hir::Node::Local(local) = self.infcx.tcx.hir_node(hir_id)
|
||||
{
|
||||
let tables = self.infcx.tcx.typeck(def_id.as_local().unwrap());
|
||||
if let Some(clone_trait) = self.infcx.tcx.lang_items().clone_trait()
|
||||
@ -1332,6 +1295,23 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
struct BindingFinder {
|
||||
span: Span,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for BindingFinder {
|
||||
type Result = ControlFlow<hir::HirId>;
|
||||
fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) -> Self::Result {
|
||||
if let hir::StmtKind::Let(local) = s.kind
|
||||
&& local.pat.span == self.span
|
||||
{
|
||||
ControlFlow::Break(local.hir_id)
|
||||
} else {
|
||||
hir::intravisit::walk_stmt(self, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
@ -1471,8 +1451,9 @@ fn suggest_ampmut<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
fn is_closure_or_coroutine(ty: Ty<'_>) -> bool {
|
||||
ty.is_closure() || ty.is_coroutine()
|
||||
/// If the type is a `Coroutine`, `Closure`, or `CoroutineClosure`
|
||||
fn is_closure_like(ty: Ty<'_>) -> bool {
|
||||
ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure()
|
||||
}
|
||||
|
||||
/// Given a field that needs to be mutable, returns a span where the " mut " could go.
|
||||
@ -1491,11 +1472,9 @@ fn get_mut_span_in_struct_field<'tcx>(
|
||||
if let ty::Ref(_, ty, _) = ty.kind()
|
||||
&& let ty::Adt(def, _) = ty.kind()
|
||||
&& let field = def.all_fields().nth(field.index())?
|
||||
// Use the HIR types to construct the diagnostic message.
|
||||
&& let node = tcx.opt_hir_node_by_def_id(field.did.as_local()?)?
|
||||
// Now we're dealing with the actual struct that we're going to suggest a change to,
|
||||
// we can expect a field that is an immutable reference to a type.
|
||||
&& let hir::Node::Field(field) = node
|
||||
&& let hir::Node::Field(field) = tcx.hir_node_by_def_id(field.did.as_local()?)
|
||||
&& let hir::TyKind::Ref(lt, hir::MutTy { mutbl: hir::Mutability::Not, ty }) = field.ty.kind
|
||||
{
|
||||
return Some(lt.ident.span.between(ty.span));
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
//! Contains utilities for generating suggestions for borrowck errors related to unsatisfied
|
||||
//! outlives constraints.
|
||||
|
||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_errors::Diag;
|
||||
use rustc_middle::ty::RegionVid;
|
||||
use smallvec::SmallVec;
|
||||
use std::collections::BTreeMap;
|
||||
@ -131,14 +134,13 @@ impl OutlivesSuggestionBuilder {
|
||||
|
||||
for (r, bound) in unified.into_iter() {
|
||||
if !unified_already.contains(fr) {
|
||||
suggested.push(SuggestedConstraint::Equal(fr_name.clone(), bound));
|
||||
suggested.push(SuggestedConstraint::Equal(fr_name, bound));
|
||||
unified_already.insert(r);
|
||||
}
|
||||
}
|
||||
|
||||
if !other.is_empty() {
|
||||
let other =
|
||||
other.iter().map(|(_, rname)| rname.clone()).collect::<SmallVec<_>>();
|
||||
let other = other.iter().map(|(_, rname)| *rname).collect::<SmallVec<_>>();
|
||||
suggested.push(SuggestedConstraint::Outlives(fr_name, other))
|
||||
}
|
||||
}
|
||||
@ -155,13 +157,12 @@ impl OutlivesSuggestionBuilder {
|
||||
self.constraints_to_add.entry(fr).or_default().push(outlived_fr);
|
||||
}
|
||||
|
||||
/// Emit an intermediate note on the given `Diagnostic` if the involved regions are
|
||||
/// suggestable.
|
||||
/// Emit an intermediate note on the given `Diag` if the involved regions are suggestable.
|
||||
pub(crate) fn intermediate_suggestion(
|
||||
&mut self,
|
||||
mbcx: &MirBorrowckCtxt<'_, '_>,
|
||||
errci: &ErrorConstraintInfo<'_>,
|
||||
diag: &mut Diagnostic,
|
||||
diag: &mut Diag<'_>,
|
||||
) {
|
||||
// Emit an intermediate note.
|
||||
let fr_name = self.region_vid_to_name(mbcx, errci.fr);
|
||||
@ -251,6 +252,6 @@ impl OutlivesSuggestionBuilder {
|
||||
diag.sort_span = mir_span.shrink_to_hi();
|
||||
|
||||
// Buffer the diagnostic
|
||||
mbcx.buffer_non_error_diag(diag);
|
||||
mbcx.buffer_non_error(diag);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
//! Error reporting machinery for lifetime errors.
|
||||
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, MultiSpan};
|
||||
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res::Def;
|
||||
use rustc_hir::def_id::DefId;
|
||||
@ -75,7 +73,7 @@ impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> {
|
||||
///
|
||||
/// Usually we expect this to either be empty or contain a small number of items, so we can avoid
|
||||
/// allocation most of the time.
|
||||
pub(crate) struct RegionErrors<'tcx>(Vec<RegionErrorKind<'tcx>>, TyCtxt<'tcx>);
|
||||
pub(crate) struct RegionErrors<'tcx>(Vec<(RegionErrorKind<'tcx>, ErrorGuaranteed)>, TyCtxt<'tcx>);
|
||||
|
||||
impl<'tcx> RegionErrors<'tcx> {
|
||||
pub fn new(tcx: TyCtxt<'tcx>) -> Self {
|
||||
@ -84,15 +82,18 @@ impl<'tcx> RegionErrors<'tcx> {
|
||||
#[track_caller]
|
||||
pub fn push(&mut self, val: impl Into<RegionErrorKind<'tcx>>) {
|
||||
let val = val.into();
|
||||
self.1.sess.dcx().delayed_bug(format!("{val:?}"));
|
||||
self.0.push(val);
|
||||
let guar = self.1.sess.dcx().delayed_bug(format!("{val:?}"));
|
||||
self.0.push((val, guar));
|
||||
}
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
pub fn into_iter(self) -> impl Iterator<Item = RegionErrorKind<'tcx>> {
|
||||
pub fn into_iter(self) -> impl Iterator<Item = (RegionErrorKind<'tcx>, ErrorGuaranteed)> {
|
||||
self.0.into_iter()
|
||||
}
|
||||
pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
|
||||
self.0.get(0).map(|x| x.1)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for RegionErrors<'_> {
|
||||
@ -200,9 +201,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
// For generic associated types (GATs) which implied 'static requirement
|
||||
// from higher-ranked trait bounds (HRTB). Try to locate span of the trait
|
||||
// and the span which bounded to the trait for adding 'static lifetime suggestion
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
fn suggest_static_lifetime_for_gat_from_hrtb(
|
||||
&self,
|
||||
diag: &mut DiagnosticBuilder<'_>,
|
||||
diag: &mut Diag<'_>,
|
||||
lower_bound: RegionVid,
|
||||
) {
|
||||
let mut suggestions = vec![];
|
||||
@ -216,7 +219,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
if let Some(id) = placeholder.bound.kind.get_id()
|
||||
&& let Some(placeholder_id) = id.as_local()
|
||||
&& let gat_hir_id = self.infcx.tcx.local_def_id_to_hir_id(placeholder_id)
|
||||
&& let Some(generics_impl) = hir.get_parent(gat_hir_id).generics()
|
||||
&& let Some(generics_impl) = self
|
||||
.infcx
|
||||
.tcx
|
||||
.parent_hir_node(self.infcx.tcx.parent_hir_id(gat_hir_id))
|
||||
.generics()
|
||||
{
|
||||
Some((gat_hir_id, generics_impl))
|
||||
} else {
|
||||
@ -275,7 +282,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
.iter()
|
||||
.rfind(|param| param.def_id.to_def_id() == defid)
|
||||
.is_some() {
|
||||
suggestions.push((bounded_span.shrink_to_hi(), format!(" + 'static")));
|
||||
suggestions.push((bounded_span.shrink_to_hi(), " + 'static".to_string()));
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -299,10 +306,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
let mut last_unexpected_hidden_region: Option<(Span, Ty<'_>, ty::OpaqueTypeKey<'tcx>)> =
|
||||
None;
|
||||
|
||||
for nll_error in nll_errors.into_iter() {
|
||||
for (nll_error, _) in nll_errors.into_iter() {
|
||||
match nll_error {
|
||||
RegionErrorKind::TypeTestError { type_test } => {
|
||||
// Try to convert the lower-bound region into something named we can print for the user.
|
||||
// Try to convert the lower-bound region into something named we can print for
|
||||
// the user.
|
||||
let lower_bound_region = self.to_error_region(type_test.lower_bound);
|
||||
|
||||
let type_test_span = type_test.span;
|
||||
@ -419,6 +427,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
/// ```
|
||||
///
|
||||
/// Here we would be invoked with `fr = 'a` and `outlived_fr = 'b`.
|
||||
// FIXME: make this translatable
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
pub(crate) fn report_region_error(
|
||||
&mut self,
|
||||
fr: RegionVid,
|
||||
@ -568,11 +579,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
/// executing...
|
||||
/// = note: ...therefore, returned references to captured variables will escape the closure
|
||||
/// ```
|
||||
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
|
||||
fn report_fnmut_error(
|
||||
&self,
|
||||
errci: &ErrorConstraintInfo<'tcx>,
|
||||
kind: ReturnConstraint,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
) -> Diag<'tcx> {
|
||||
let ErrorConstraintInfo { outlived_fr, span, .. } = errci;
|
||||
|
||||
let mut output_ty = self.regioncx.universal_regions().unnormalized_output_ty;
|
||||
@ -614,13 +626,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
let upvars_map = self.infcx.tcx.upvars_mentioned(def_id).unwrap();
|
||||
let upvar_def_span = self.infcx.tcx.hir().span(def_hir);
|
||||
let upvar_span = upvars_map.get(&def_hir).unwrap().span;
|
||||
diag.subdiagnostic(VarHereDenote::Defined { span: upvar_def_span });
|
||||
diag.subdiagnostic(VarHereDenote::Captured { span: upvar_span });
|
||||
diag.subdiagnostic(self.dcx(), VarHereDenote::Defined { span: upvar_def_span });
|
||||
diag.subdiagnostic(self.dcx(), VarHereDenote::Captured { span: upvar_span });
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(fr_span) = self.give_region_a_name(*outlived_fr).unwrap().span() {
|
||||
diag.subdiagnostic(VarHereDenote::FnMutInferred { span: fr_span });
|
||||
diag.subdiagnostic(self.dcx(), VarHereDenote::FnMutInferred { span: fr_span });
|
||||
}
|
||||
|
||||
self.suggest_move_on_borrowing_closure(&mut diag);
|
||||
@ -641,10 +653,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
/// | ^^^^^^^^^^ `x` escapes the function body here
|
||||
/// ```
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn report_escaping_data_error(
|
||||
&self,
|
||||
errci: &ErrorConstraintInfo<'tcx>,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
fn report_escaping_data_error(&self, errci: &ErrorConstraintInfo<'tcx>) -> Diag<'tcx> {
|
||||
let ErrorConstraintInfo { span, category, .. } = errci;
|
||||
|
||||
let fr_name_and_span = self.regioncx.get_var_name_and_span_for_region(
|
||||
@ -683,12 +692,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
borrowck_errors::borrowed_data_escapes_closure(self.infcx.tcx, *span, escapes_from);
|
||||
|
||||
if let Some((Some(outlived_fr_name), outlived_fr_span)) = outlived_fr_name_and_span {
|
||||
// FIXME: make this translatable
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
diag.span_label(
|
||||
outlived_fr_span,
|
||||
format!("`{outlived_fr_name}` declared here, outside of the {escapes_from} body",),
|
||||
);
|
||||
}
|
||||
|
||||
// FIXME: make this translatable
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
if let Some((Some(fr_name), fr_span)) = fr_name_and_span {
|
||||
diag.span_label(
|
||||
fr_span,
|
||||
@ -712,6 +727,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
let outlived_fr_region_name = self.give_region_a_name(errci.outlived_fr).unwrap();
|
||||
outlived_fr_region_name.highlight_region_name(&mut diag);
|
||||
|
||||
// FIXME: make this translatable
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
diag.span_label(
|
||||
*span,
|
||||
format!(
|
||||
@ -743,7 +761,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
/// | ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it
|
||||
/// | is returning data with lifetime `'b`
|
||||
/// ```
|
||||
fn report_general_error(&self, errci: &ErrorConstraintInfo<'tcx>) -> DiagnosticBuilder<'tcx> {
|
||||
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
|
||||
fn report_general_error(&self, errci: &ErrorConstraintInfo<'tcx>) -> Diag<'tcx> {
|
||||
let ErrorConstraintInfo {
|
||||
fr,
|
||||
fr_is_local,
|
||||
@ -786,7 +805,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
},
|
||||
};
|
||||
|
||||
diag.subdiagnostic(err_category);
|
||||
diag.subdiagnostic(self.dcx(), err_category);
|
||||
|
||||
self.add_static_impl_trait_suggestion(&mut diag, *fr, fr_name, *outlived_fr);
|
||||
self.suggest_adding_lifetime_params(&mut diag, *fr, *outlived_fr);
|
||||
@ -804,9 +823,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
/// LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + 'a {
|
||||
/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
/// ```
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
fn add_static_impl_trait_suggestion(
|
||||
&self,
|
||||
diag: &mut Diagnostic,
|
||||
diag: &mut Diag<'_>,
|
||||
fr: RegionVid,
|
||||
// We need to pass `fr_name` - computing it again will label it twice.
|
||||
fr_name: RegionName,
|
||||
@ -895,7 +916,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
|
||||
fn maybe_suggest_constrain_dyn_trait_impl(
|
||||
&self,
|
||||
diag: &mut Diagnostic,
|
||||
diag: &mut Diag<'_>,
|
||||
f: Region<'tcx>,
|
||||
o: Region<'tcx>,
|
||||
category: &ConstraintCategory<'tcx>,
|
||||
@ -954,10 +975,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
self.suggest_constrain_dyn_trait_in_impl(diag, &visitor.0, ident, self_ty);
|
||||
}
|
||||
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
#[instrument(skip(self, err), level = "debug")]
|
||||
fn suggest_constrain_dyn_trait_in_impl(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
err: &mut Diag<'_>,
|
||||
found_dids: &FxIndexSet<DefId>,
|
||||
ident: Ident,
|
||||
self_ty: &hir::Ty<'_>,
|
||||
@ -977,7 +1000,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
ident.span,
|
||||
"calling this method introduces the `impl`'s `'static` requirement",
|
||||
);
|
||||
err.subdiagnostic(RequireStaticErr::UsedImpl { multi_span });
|
||||
err.subdiagnostic(self.dcx(), RequireStaticErr::UsedImpl { multi_span });
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_hi(),
|
||||
"consider relaxing the implicit `'static` requirement",
|
||||
@ -990,12 +1013,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
suggested
|
||||
}
|
||||
|
||||
fn suggest_adding_lifetime_params(
|
||||
&self,
|
||||
diag: &mut Diagnostic,
|
||||
sub: RegionVid,
|
||||
sup: RegionVid,
|
||||
) {
|
||||
fn suggest_adding_lifetime_params(&self, diag: &mut Diag<'_>, sub: RegionVid, sup: RegionVid) {
|
||||
let (Some(sub), Some(sup)) = (self.to_error_region(sub), self.to_error_region(sup)) else {
|
||||
return;
|
||||
};
|
||||
@ -1021,7 +1039,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
suggest_adding_lifetime_params(self.infcx.tcx, sub, ty_sup, ty_sub, diag);
|
||||
}
|
||||
|
||||
fn suggest_move_on_borrowing_closure(&self, diag: &mut Diagnostic) {
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
fn suggest_move_on_borrowing_closure(&self, diag: &mut Diag<'_>) {
|
||||
let map = self.infcx.tcx.hir();
|
||||
let body_id = map.body_owned_by(self.mir_def_id());
|
||||
let expr = &map.body(body_id).value.peel_blocks();
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
|
||||
use std::fmt::{self, Display};
|
||||
use std::iter;
|
||||
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_data_structures::fx::IndexEntry;
|
||||
use rustc_errors::Diag;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_middle::ty::print::RegionHighlightMode;
|
||||
@ -14,7 +18,7 @@ use crate::{universal_regions::DefiningTy, MirBorrowckCtxt};
|
||||
|
||||
/// A name for a particular region used in emitting diagnostics. This name could be a generated
|
||||
/// name like `'1`, a name used by the user like `'a`, or a name like `'static`.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(crate) struct RegionName {
|
||||
/// The name of the region (interned).
|
||||
pub(crate) name: Symbol,
|
||||
@ -25,7 +29,7 @@ pub(crate) struct RegionName {
|
||||
/// Denotes the source of a region that is named by a `RegionName`. For example, a free region that
|
||||
/// was named by the user would get `NamedLateParamRegion` and `'static` lifetime would get `Static`.
|
||||
/// This helps to print the right kinds of diagnostics.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(crate) enum RegionNameSource {
|
||||
/// A bound (not free) region that was instantiated at the def site (not an HRTB).
|
||||
NamedEarlyParamRegion(Span),
|
||||
@ -42,7 +46,7 @@ pub(crate) enum RegionNameSource {
|
||||
/// The region corresponding to the return type of a closure.
|
||||
AnonRegionFromOutput(RegionNameHighlight, &'static str),
|
||||
/// The region from a type yielded by a coroutine.
|
||||
AnonRegionFromYieldTy(Span, String),
|
||||
AnonRegionFromYieldTy(Span, Symbol),
|
||||
/// An anonymous region from an async fn.
|
||||
AnonRegionFromAsyncFn(Span),
|
||||
/// An anonymous region from an impl self type or trait
|
||||
@ -51,7 +55,7 @@ pub(crate) enum RegionNameSource {
|
||||
|
||||
/// Describes what to highlight to explain to the user that we're giving an anonymous region a
|
||||
/// synthesized name, and how to highlight it.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(crate) enum RegionNameHighlight {
|
||||
/// The anonymous region corresponds to a reference that was found by traversing the type in the HIR.
|
||||
MatchedHirTy(Span),
|
||||
@ -59,11 +63,11 @@ pub(crate) enum RegionNameHighlight {
|
||||
MatchedAdtAndSegment(Span),
|
||||
/// The anonymous region corresponds to a region where the type annotation is completely missing
|
||||
/// from the code, e.g. in a closure arguments `|x| { ... }`, where `x` is a reference.
|
||||
CannotMatchHirTy(Span, String),
|
||||
CannotMatchHirTy(Span, Symbol),
|
||||
/// The anonymous region corresponds to a region where the type annotation is completely missing
|
||||
/// from the code, and *even if* we print out the full name of the type, the region name won't
|
||||
/// be included. This currently occurs for opaque types like `impl Future`.
|
||||
Occluded(Span, String),
|
||||
Occluded(Span, Symbol),
|
||||
}
|
||||
|
||||
impl RegionName {
|
||||
@ -102,7 +106,7 @@ impl RegionName {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn highlight_region_name(&self, diag: &mut Diagnostic) {
|
||||
pub(crate) fn highlight_region_name(&self, diag: &mut Diag<'_>) {
|
||||
match &self.source {
|
||||
RegionNameSource::NamedLateParamRegion(span)
|
||||
| RegionNameSource::NamedEarlyParamRegion(span) => {
|
||||
@ -187,9 +191,9 @@ impl Display for RegionName {
|
||||
}
|
||||
}
|
||||
|
||||
impl rustc_errors::IntoDiagnosticArg for RegionName {
|
||||
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue {
|
||||
self.to_string().into_diagnostic_arg()
|
||||
impl rustc_errors::IntoDiagArg for RegionName {
|
||||
fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
|
||||
self.to_string().into_diag_arg()
|
||||
}
|
||||
}
|
||||
|
||||
@ -247,25 +251,28 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
|
||||
assert!(self.regioncx.universal_regions().is_universal_region(fr));
|
||||
|
||||
if let Some(value) = self.region_names.try_borrow_mut().unwrap().get(&fr) {
|
||||
return Some(value.clone());
|
||||
match self.region_names.borrow_mut().entry(fr) {
|
||||
IndexEntry::Occupied(precomputed_name) => Some(*precomputed_name.get()),
|
||||
IndexEntry::Vacant(slot) => {
|
||||
let new_name = self
|
||||
.give_name_from_error_region(fr)
|
||||
.or_else(|| self.give_name_if_anonymous_region_appears_in_arguments(fr))
|
||||
.or_else(|| self.give_name_if_anonymous_region_appears_in_upvars(fr))
|
||||
.or_else(|| self.give_name_if_anonymous_region_appears_in_output(fr))
|
||||
.or_else(|| self.give_name_if_anonymous_region_appears_in_yield_ty(fr))
|
||||
.or_else(|| self.give_name_if_anonymous_region_appears_in_impl_signature(fr))
|
||||
.or_else(|| {
|
||||
self.give_name_if_anonymous_region_appears_in_arg_position_impl_trait(fr)
|
||||
});
|
||||
|
||||
if let Some(new_name) = new_name {
|
||||
slot.insert(new_name);
|
||||
}
|
||||
debug!("give_region_a_name: gave name {:?}", new_name);
|
||||
|
||||
new_name
|
||||
}
|
||||
}
|
||||
|
||||
let value = self
|
||||
.give_name_from_error_region(fr)
|
||||
.or_else(|| self.give_name_if_anonymous_region_appears_in_arguments(fr))
|
||||
.or_else(|| self.give_name_if_anonymous_region_appears_in_upvars(fr))
|
||||
.or_else(|| self.give_name_if_anonymous_region_appears_in_output(fr))
|
||||
.or_else(|| self.give_name_if_anonymous_region_appears_in_yield_ty(fr))
|
||||
.or_else(|| self.give_name_if_anonymous_region_appears_in_impl_signature(fr))
|
||||
.or_else(|| self.give_name_if_anonymous_region_appears_in_arg_position_impl_trait(fr));
|
||||
|
||||
if let Some(value) = &value {
|
||||
self.region_names.try_borrow_mut().unwrap().insert(fr, value.clone());
|
||||
}
|
||||
|
||||
debug!("give_region_a_name: gave name {:?}", value);
|
||||
value
|
||||
}
|
||||
|
||||
/// Checks for the case where `fr` maps to something that the
|
||||
@ -324,9 +331,13 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
ty::BoundRegionKind::BrEnv => {
|
||||
let def_ty = self.regioncx.universal_regions().defining_ty;
|
||||
|
||||
let DefiningTy::Closure(_, args) = def_ty else {
|
||||
// Can't have BrEnv in functions, constants or coroutines.
|
||||
bug!("BrEnv outside of closure.");
|
||||
let closure_kind = match def_ty {
|
||||
DefiningTy::Closure(_, args) => args.as_closure().kind(),
|
||||
DefiningTy::CoroutineClosure(_, args) => args.as_coroutine_closure().kind(),
|
||||
_ => {
|
||||
// Can't have BrEnv in functions, constants or coroutines.
|
||||
bug!("BrEnv outside of closure.");
|
||||
}
|
||||
};
|
||||
let hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }) =
|
||||
tcx.hir().expect_expr(self.mir_hir_id()).kind
|
||||
@ -334,21 +345,18 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
bug!("Closure is not defined by a closure expr");
|
||||
};
|
||||
let region_name = self.synthesize_region_name();
|
||||
|
||||
let closure_kind_ty = args.as_closure().kind_ty();
|
||||
let note = match closure_kind_ty.to_opt_closure_kind() {
|
||||
Some(ty::ClosureKind::Fn) => {
|
||||
let note = match closure_kind {
|
||||
ty::ClosureKind::Fn => {
|
||||
"closure implements `Fn`, so references to captured variables \
|
||||
can't escape the closure"
|
||||
}
|
||||
Some(ty::ClosureKind::FnMut) => {
|
||||
ty::ClosureKind::FnMut => {
|
||||
"closure implements `FnMut`, so references to captured variables \
|
||||
can't escape the closure"
|
||||
}
|
||||
Some(ty::ClosureKind::FnOnce) => {
|
||||
ty::ClosureKind::FnOnce => {
|
||||
bug!("BrEnv in a `FnOnce` closure");
|
||||
}
|
||||
None => bug!("Closure kind not inferred in borrow check"),
|
||||
};
|
||||
|
||||
Some(RegionName {
|
||||
@ -456,9 +464,9 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
);
|
||||
if type_name.contains(&format!("'{counter}")) {
|
||||
// Only add a label if we can confirm that a region was labelled.
|
||||
RegionNameHighlight::CannotMatchHirTy(span, type_name)
|
||||
RegionNameHighlight::CannotMatchHirTy(span, Symbol::intern(&type_name))
|
||||
} else {
|
||||
RegionNameHighlight::Occluded(span, type_name)
|
||||
RegionNameHighlight::Occluded(span, Symbol::intern(&type_name))
|
||||
}
|
||||
}
|
||||
|
||||
@ -618,9 +626,9 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
| GenericArgKind::Const(_),
|
||||
_,
|
||||
) => {
|
||||
// HIR lowering sometimes doesn't catch this in erroneous
|
||||
// programs, so we need to use span_delayed_bug here. See #82126.
|
||||
self.dcx().span_delayed_bug(
|
||||
// This was previously a `span_delayed_bug` and could be
|
||||
// reached by the test for #82126, but no longer.
|
||||
self.dcx().span_bug(
|
||||
hir_arg.span(),
|
||||
format!("unmatched arg and hir arg: found {kind:?} vs {hir_arg:?}"),
|
||||
);
|
||||
@ -692,7 +700,10 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Async,
|
||||
hir::CoroutineSource::Closure,
|
||||
)) => " of async closure",
|
||||
))
|
||||
| hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => {
|
||||
" of async closure"
|
||||
}
|
||||
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Async,
|
||||
@ -719,7 +730,10 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Gen,
|
||||
hir::CoroutineSource::Closure,
|
||||
)) => " of gen closure",
|
||||
))
|
||||
| hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Gen) => {
|
||||
" of gen closure"
|
||||
}
|
||||
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Gen,
|
||||
@ -743,7 +757,10 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::AsyncGen,
|
||||
hir::CoroutineSource::Closure,
|
||||
)) => " of async gen closure",
|
||||
))
|
||||
| hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::AsyncGen) => {
|
||||
" of async gen closure"
|
||||
}
|
||||
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::AsyncGen,
|
||||
@ -878,7 +895,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
|
||||
Some(RegionName {
|
||||
name: self.synthesize_region_name(),
|
||||
source: RegionNameSource::AnonRegionFromYieldTy(yield_span, type_name),
|
||||
source: RegionNameSource::AnonRegionFromYieldTy(yield_span, Symbol::intern(&type_name)),
|
||||
})
|
||||
}
|
||||
|
||||
@ -970,7 +987,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
Some(RegionName {
|
||||
name: region_name,
|
||||
source: RegionNameSource::AnonRegionFromArgument(
|
||||
RegionNameHighlight::CannotMatchHirTy(arg_span, arg_name?.to_string()),
|
||||
RegionNameHighlight::CannotMatchHirTy(arg_span, arg_name?),
|
||||
),
|
||||
})
|
||||
} else {
|
||||
|
||||
@ -1,6 +1,3 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
||||
use crate::region_infer::RegionInferenceContext;
|
||||
use rustc_index::IndexSlice;
|
||||
use rustc_middle::mir::{Body, Local};
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
use crate::location::{LocationIndex, LocationTable};
|
||||
use crate::BorrowIndex;
|
||||
use polonius_engine::AllFacts as PoloniusFacts;
|
||||
use polonius_engine::Atom;
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::mir::Local;
|
||||
use rustc_middle::ty::{RegionVid, TyCtxt};
|
||||
use rustc_mir_dataflow::move_paths::MovePathIndex;
|
||||
@ -26,20 +25,10 @@ impl polonius_engine::FactTypes for RustcFacts {
|
||||
|
||||
pub type AllFacts = PoloniusFacts<RustcFacts>;
|
||||
|
||||
pub(crate) trait AllFactsExt {
|
||||
#[extension(pub(crate) trait AllFactsExt)]
|
||||
impl AllFacts {
|
||||
/// Returns `true` if there is a need to gather `AllFacts` given the
|
||||
/// current `-Z` flags.
|
||||
fn enabled(tcx: TyCtxt<'_>) -> bool;
|
||||
|
||||
fn write_to_dir(
|
||||
&self,
|
||||
dir: impl AsRef<Path>,
|
||||
location_table: &LocationTable,
|
||||
) -> Result<(), Box<dyn Error>>;
|
||||
}
|
||||
|
||||
impl AllFactsExt for AllFacts {
|
||||
/// Return
|
||||
fn enabled(tcx: TyCtxt<'_>) -> bool {
|
||||
tcx.sess.opts.unstable_opts.nll_facts
|
||||
|| tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled()
|
||||
|
||||
@ -3,8 +3,10 @@
|
||||
#![allow(internal_features)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(associated_type_bounds)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(never_type)]
|
||||
@ -19,7 +21,7 @@ extern crate tracing;
|
||||
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::graph::dominators::Dominators;
|
||||
use rustc_errors::{Diagnostic, DiagnosticBuilder};
|
||||
use rustc_errors::Diag;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_index::bit_set::{BitSet, ChunkedBitSet};
|
||||
@ -110,23 +112,21 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def: LocalDefId) -> &BorrowCheckResult<'_> {
|
||||
let (input_body, promoted) = tcx.mir_promoted(def);
|
||||
debug!("run query mir_borrowck: {}", tcx.def_path_str(def));
|
||||
|
||||
if input_body.borrow().should_skip() {
|
||||
debug!("Skipping borrowck because of injected body");
|
||||
let input_body: &Body<'_> = &input_body.borrow();
|
||||
|
||||
if input_body.should_skip() || input_body.tainted_by_errors.is_some() {
|
||||
debug!("Skipping borrowck because of injected body or tainted body");
|
||||
// Let's make up a borrowck result! Fun times!
|
||||
let result = BorrowCheckResult {
|
||||
concrete_opaque_types: FxIndexMap::default(),
|
||||
closure_requirements: None,
|
||||
used_mut_upvars: SmallVec::new(),
|
||||
tainted_by_errors: None,
|
||||
tainted_by_errors: input_body.tainted_by_errors,
|
||||
};
|
||||
return tcx.arena.alloc(result);
|
||||
}
|
||||
|
||||
let hir_owner = tcx.local_def_id_to_hir_id(def).owner;
|
||||
|
||||
let infcx =
|
||||
tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id)).build();
|
||||
let input_body: &Body<'_> = &input_body.borrow();
|
||||
let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::bind(tcx, def)).build();
|
||||
let promoted: &IndexSlice<_, _> = &promoted.borrow();
|
||||
let opt_closure_req = do_mir_borrowck(&infcx, input_body, promoted, None).0;
|
||||
debug!("mir_borrowck done");
|
||||
@ -173,12 +173,11 @@ fn do_mir_borrowck<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
let mut errors = error::BorrowckErrors::new(infcx.tcx);
|
||||
let mut diags = diags::BorrowckDiags::new();
|
||||
|
||||
// Gather the upvars of a closure, if any.
|
||||
if let Some(e) = input_body.tainted_by_errors {
|
||||
infcx.set_tainted_by_errors(e);
|
||||
errors.set_tainted_by_errors(e);
|
||||
}
|
||||
|
||||
// Replace all regions with fresh inference variables. This
|
||||
@ -244,7 +243,7 @@ fn do_mir_borrowck<'tcx>(
|
||||
®ioncx,
|
||||
&opt_closure_req,
|
||||
&opaque_type_values,
|
||||
&mut errors,
|
||||
&mut diags,
|
||||
);
|
||||
|
||||
// The various `flow_*` structures can be large. We drop `flow_inits` here
|
||||
@ -305,11 +304,11 @@ fn do_mir_borrowck<'tcx>(
|
||||
next_region_name: RefCell::new(1),
|
||||
polonius_output: None,
|
||||
move_errors: Vec::new(),
|
||||
errors,
|
||||
diags,
|
||||
};
|
||||
MoveVisitor { ctxt: &mut promoted_mbcx }.visit_body(promoted_body);
|
||||
promoted_mbcx.report_move_errors();
|
||||
errors = promoted_mbcx.errors;
|
||||
diags = promoted_mbcx.diags;
|
||||
|
||||
struct MoveVisitor<'a, 'cx, 'tcx> {
|
||||
ctxt: &'a mut MirBorrowckCtxt<'cx, 'tcx>,
|
||||
@ -346,7 +345,7 @@ fn do_mir_borrowck<'tcx>(
|
||||
next_region_name: RefCell::new(1),
|
||||
polonius_output,
|
||||
move_errors: Vec::new(),
|
||||
errors,
|
||||
diags,
|
||||
};
|
||||
|
||||
// Compute and report region errors, if any.
|
||||
@ -574,7 +573,7 @@ struct MirBorrowckCtxt<'cx, 'tcx> {
|
||||
/// Results of Polonius analysis.
|
||||
polonius_output: Option<Rc<PoloniusOutput>>,
|
||||
|
||||
errors: error::BorrowckErrors<'tcx>,
|
||||
diags: diags::BorrowckDiags<'tcx>,
|
||||
move_errors: Vec<MoveError<'tcx>>,
|
||||
}
|
||||
|
||||
@ -722,7 +721,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro
|
||||
operands,
|
||||
options: _,
|
||||
line_spans: _,
|
||||
destination: _,
|
||||
targets: _,
|
||||
unwind: _,
|
||||
} => {
|
||||
for op in operands {
|
||||
@ -748,7 +747,8 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro
|
||||
}
|
||||
InlineAsmOperand::Const { value: _ }
|
||||
| InlineAsmOperand::SymFn { value: _ }
|
||||
| InlineAsmOperand::SymStatic { def_id: _ } => {}
|
||||
| InlineAsmOperand::SymStatic { def_id: _ }
|
||||
| InlineAsmOperand::Label { target_index: _ } => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1035,7 +1035,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
self,
|
||||
self.infcx.tcx,
|
||||
self.body,
|
||||
location,
|
||||
(sd, place_span.0),
|
||||
&borrow_set,
|
||||
|borrow_index| borrows_in_scope.contains(borrow_index),
|
||||
@ -1304,7 +1303,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
// moved into the closure and subsequently used by the closure,
|
||||
// in order to populate our used_mut set.
|
||||
match **aggregate_kind {
|
||||
AggregateKind::Closure(def_id, _) | AggregateKind::Coroutine(def_id, _) => {
|
||||
AggregateKind::Closure(def_id, _)
|
||||
| AggregateKind::CoroutineClosure(def_id, _)
|
||||
| AggregateKind::Coroutine(def_id, _) => {
|
||||
let def_id = def_id.expect_local();
|
||||
let BorrowCheckResult { used_mut_upvars, .. } =
|
||||
self.infcx.tcx.mir_borrowck(def_id);
|
||||
@ -1610,6 +1611,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
| ty::FnPtr(_)
|
||||
| ty::Dynamic(_, _, _)
|
||||
| ty::Closure(_, _)
|
||||
| ty::CoroutineClosure(_, _)
|
||||
| ty::Coroutine(_, _)
|
||||
| ty::CoroutineWitness(..)
|
||||
| ty::Never
|
||||
@ -1634,7 +1636,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
return;
|
||||
}
|
||||
}
|
||||
ty::Closure(_, _) | ty::Coroutine(_, _) | ty::Tuple(_) => (),
|
||||
ty::Closure(..)
|
||||
| ty::CoroutineClosure(..)
|
||||
| ty::Coroutine(_, _)
|
||||
| ty::Tuple(_) => (),
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(_)
|
||||
@ -2125,7 +2130,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
| WriteKind::MutableBorrow(BorrowKind::Fake),
|
||||
) => {
|
||||
if self.is_mutable(place.as_ref(), is_local_mutation_allowed).is_err()
|
||||
&& !self.has_buffered_errors()
|
||||
&& !self.has_buffered_diags()
|
||||
{
|
||||
// rust-lang/rust#46908: In pure NLL mode this code path should be
|
||||
// unreachable, but we use `span_delayed_bug` because we can hit this when
|
||||
@ -2167,7 +2172,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
// report the error as an illegal reassignment
|
||||
let init = &self.move_data.inits[init_index];
|
||||
let assigned_span = init.span(self.body);
|
||||
self.report_illegal_reassignment(location, (place, span), assigned_span, place);
|
||||
self.report_illegal_reassignment((place, span), assigned_span, place);
|
||||
} else {
|
||||
self.report_mutability_error(place, span, the_place_err, error_access, location)
|
||||
}
|
||||
@ -2383,17 +2388,30 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
mod error {
|
||||
mod diags {
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub struct BorrowckErrors<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
enum BufferedDiag<'tcx> {
|
||||
Error(Diag<'tcx>),
|
||||
NonError(Diag<'tcx, ()>),
|
||||
}
|
||||
|
||||
impl<'tcx> BufferedDiag<'tcx> {
|
||||
fn sort_span(&self) -> Span {
|
||||
match self {
|
||||
BufferedDiag::Error(diag) => diag.sort_span,
|
||||
BufferedDiag::NonError(diag) => diag.sort_span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BorrowckDiags<'tcx> {
|
||||
/// This field keeps track of move errors that are to be reported for given move indices.
|
||||
///
|
||||
/// There are situations where many errors can be reported for a single move out (see #53807)
|
||||
/// and we want only the best of those errors.
|
||||
/// There are situations where many errors can be reported for a single move out (see
|
||||
/// #53807) and we want only the best of those errors.
|
||||
///
|
||||
/// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the
|
||||
/// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of
|
||||
@ -2404,62 +2422,48 @@ mod error {
|
||||
/// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary
|
||||
/// when errors in the map are being re-added to the error buffer so that errors with the
|
||||
/// same primary span come out in a consistent order.
|
||||
buffered_move_errors:
|
||||
BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>)>,
|
||||
buffered_mut_errors: FxIndexMap<Span, (DiagnosticBuilder<'tcx>, usize)>,
|
||||
/// Buffer of diagnostics to be reported. Uses `Diagnostic` rather than `DiagnosticBuilder`
|
||||
/// because it has a mixture of error diagnostics and non-error diagnostics.
|
||||
buffered: Vec<Diagnostic>,
|
||||
/// Set to Some if we emit an error during borrowck
|
||||
tainted_by_errors: Option<ErrorGuaranteed>,
|
||||
buffered_move_errors: BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, Diag<'tcx>)>,
|
||||
|
||||
buffered_mut_errors: FxIndexMap<Span, (Diag<'tcx>, usize)>,
|
||||
|
||||
/// Buffer of diagnostics to be reported. A mixture of error and non-error diagnostics.
|
||||
buffered_diags: Vec<BufferedDiag<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> BorrowckErrors<'tcx> {
|
||||
pub fn new(tcx: TyCtxt<'tcx>) -> Self {
|
||||
BorrowckErrors {
|
||||
tcx,
|
||||
impl<'tcx> BorrowckDiags<'tcx> {
|
||||
pub fn new() -> Self {
|
||||
BorrowckDiags {
|
||||
buffered_move_errors: BTreeMap::new(),
|
||||
buffered_mut_errors: Default::default(),
|
||||
buffered: Default::default(),
|
||||
tainted_by_errors: None,
|
||||
buffered_diags: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_>) {
|
||||
if let None = self.tainted_by_errors {
|
||||
self.tainted_by_errors = Some(self.tcx.dcx().span_delayed_bug(
|
||||
t.span.clone_ignoring_labels(),
|
||||
"diagnostic buffered but not emitted",
|
||||
))
|
||||
}
|
||||
self.buffered.push(t.into_diagnostic());
|
||||
pub fn buffer_error(&mut self, diag: Diag<'tcx>) {
|
||||
self.buffered_diags.push(BufferedDiag::Error(diag));
|
||||
}
|
||||
|
||||
pub fn buffer_non_error_diag(&mut self, t: DiagnosticBuilder<'_, ()>) {
|
||||
self.buffered.push(t.into_diagnostic());
|
||||
}
|
||||
|
||||
pub fn set_tainted_by_errors(&mut self, e: ErrorGuaranteed) {
|
||||
self.tainted_by_errors = Some(e);
|
||||
pub fn buffer_non_error(&mut self, diag: Diag<'tcx, ()>) {
|
||||
self.buffered_diags.push(BufferedDiag::NonError(diag));
|
||||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_>) {
|
||||
self.errors.buffer_error(t);
|
||||
pub fn buffer_error(&mut self, diag: Diag<'tcx>) {
|
||||
self.diags.buffer_error(diag);
|
||||
}
|
||||
|
||||
pub fn buffer_non_error_diag(&mut self, t: DiagnosticBuilder<'_, ()>) {
|
||||
self.errors.buffer_non_error_diag(t);
|
||||
pub fn buffer_non_error(&mut self, diag: Diag<'tcx, ()>) {
|
||||
self.diags.buffer_non_error(diag);
|
||||
}
|
||||
|
||||
pub fn buffer_move_error(
|
||||
&mut self,
|
||||
move_out_indices: Vec<MoveOutIndex>,
|
||||
place_and_err: (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>),
|
||||
place_and_err: (PlaceRef<'tcx>, Diag<'tcx>),
|
||||
) -> bool {
|
||||
if let Some((_, diag)) =
|
||||
self.errors.buffered_move_errors.insert(move_out_indices, place_and_err)
|
||||
self.diags.buffered_move_errors.insert(move_out_indices, place_and_err)
|
||||
{
|
||||
// Cancel the old diagnostic so we don't ICE
|
||||
diag.cancel();
|
||||
@ -2469,51 +2473,54 @@ mod error {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_buffered_mut_error(
|
||||
&mut self,
|
||||
span: Span,
|
||||
) -> Option<(DiagnosticBuilder<'tcx>, usize)> {
|
||||
self.errors.buffered_mut_errors.remove(&span)
|
||||
pub fn get_buffered_mut_error(&mut self, span: Span) -> Option<(Diag<'tcx>, usize)> {
|
||||
// FIXME(#120456) - is `swap_remove` correct?
|
||||
self.diags.buffered_mut_errors.swap_remove(&span)
|
||||
}
|
||||
|
||||
pub fn buffer_mut_error(&mut self, span: Span, t: DiagnosticBuilder<'tcx>, count: usize) {
|
||||
self.errors.buffered_mut_errors.insert(span, (t, count));
|
||||
pub fn buffer_mut_error(&mut self, span: Span, diag: Diag<'tcx>, count: usize) {
|
||||
self.diags.buffered_mut_errors.insert(span, (diag, count));
|
||||
}
|
||||
|
||||
pub fn emit_errors(&mut self) -> Option<ErrorGuaranteed> {
|
||||
let mut res = None;
|
||||
|
||||
// Buffer any move errors that we collected and de-duplicated.
|
||||
for (_, (_, diag)) in std::mem::take(&mut self.errors.buffered_move_errors) {
|
||||
for (_, (_, diag)) in std::mem::take(&mut self.diags.buffered_move_errors) {
|
||||
// We have already set tainted for this error, so just buffer it.
|
||||
self.errors.buffered.push(diag.into_diagnostic());
|
||||
self.diags.buffered_diags.push(BufferedDiag::Error(diag));
|
||||
}
|
||||
for (_, (mut diag, count)) in std::mem::take(&mut self.errors.buffered_mut_errors) {
|
||||
for (_, (mut diag, count)) in std::mem::take(&mut self.diags.buffered_mut_errors) {
|
||||
if count > 10 {
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
diag.note(format!("...and {} other attempted mutable borrows", count - 10));
|
||||
}
|
||||
self.errors.buffered.push(diag.into_diagnostic());
|
||||
self.diags.buffered_diags.push(BufferedDiag::Error(diag));
|
||||
}
|
||||
|
||||
if !self.errors.buffered.is_empty() {
|
||||
self.errors.buffered.sort_by_key(|diag| diag.sort_span);
|
||||
|
||||
let dcx = self.dcx();
|
||||
for diag in self.errors.buffered.drain(..) {
|
||||
dcx.emit_diagnostic(diag);
|
||||
if !self.diags.buffered_diags.is_empty() {
|
||||
self.diags.buffered_diags.sort_by_key(|buffered_diag| buffered_diag.sort_span());
|
||||
for buffered_diag in self.diags.buffered_diags.drain(..) {
|
||||
match buffered_diag {
|
||||
BufferedDiag::Error(diag) => res = Some(diag.emit()),
|
||||
BufferedDiag::NonError(diag) => diag.emit(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.errors.tainted_by_errors
|
||||
res
|
||||
}
|
||||
|
||||
pub fn has_buffered_errors(&self) -> bool {
|
||||
self.errors.buffered.is_empty()
|
||||
pub(crate) fn has_buffered_diags(&self) -> bool {
|
||||
self.diags.buffered_diags.is_empty()
|
||||
}
|
||||
|
||||
pub fn has_move_error(
|
||||
&self,
|
||||
move_out_indices: &[MoveOutIndex],
|
||||
) -> Option<&(PlaceRef<'tcx>, DiagnosticBuilder<'cx>)> {
|
||||
self.errors.buffered_move_errors.get(move_out_indices)
|
||||
) -> Option<&(PlaceRef<'tcx>, Diag<'tcx>)> {
|
||||
self.diags.buffered_move_errors.get(move_out_indices)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::mir::{BasicBlock, Body, Location};
|
||||
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
//! The entry point of the NLL borrow checker.
|
||||
|
||||
use polonius_engine::{Algorithm, Output};
|
||||
@ -184,14 +182,11 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
|
||||
|
||||
// Solve the region constraints.
|
||||
let (closure_region_requirements, nll_errors) =
|
||||
regioncx.solve(infcx, param_env, body, polonius_output.clone());
|
||||
regioncx.solve(infcx, body, polonius_output.clone());
|
||||
|
||||
if !nll_errors.is_empty() {
|
||||
if let Some(guar) = nll_errors.has_errors() {
|
||||
// Suppress unhelpful extra errors in `infer_opaque_types`.
|
||||
infcx.set_tainted_by_errors(infcx.dcx().span_delayed_bug(
|
||||
body.span,
|
||||
"`compute_regions` tainted `infcx` with errors but did not emit any errors",
|
||||
));
|
||||
infcx.set_tainted_by_errors(guar);
|
||||
}
|
||||
|
||||
let remapped_opaque_tys = regioncx.infer_opaque_types(infcx, opaque_type_values);
|
||||
@ -264,7 +259,7 @@ pub(super) fn dump_annotation<'tcx>(
|
||||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
|
||||
opaque_type_values: &FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>,
|
||||
errors: &mut crate::error::BorrowckErrors<'tcx>,
|
||||
diags: &mut crate::diags::BorrowckDiags<'tcx>,
|
||||
) {
|
||||
let tcx = infcx.tcx;
|
||||
let base_def_id = tcx.typeck_root_def_id(body.source.def_id());
|
||||
@ -310,7 +305,7 @@ pub(super) fn dump_annotation<'tcx>(
|
||||
err.note(format!("Inferred opaque type values:\n{opaque_type_values:#?}"));
|
||||
}
|
||||
|
||||
errors.buffer_non_error_diag(err);
|
||||
diags.buffer_non_error(err);
|
||||
}
|
||||
|
||||
fn for_each_region_constraint<'tcx>(
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
use crate::borrow_set::{BorrowData, BorrowSet, TwoPhaseActivation};
|
||||
use crate::places_conflict;
|
||||
use crate::AccessDepth;
|
||||
@ -29,7 +27,6 @@ pub(super) fn each_borrow_involving_path<'tcx, F, I, S>(
|
||||
s: &mut S,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
_location: Location,
|
||||
access_place: (AccessDepth, Place<'tcx>),
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
is_candidate: I,
|
||||
@ -164,7 +161,7 @@ pub(crate) fn is_upvar_field_projection<'tcx>(
|
||||
match place_ref.last_projection() {
|
||||
Some((place_base, ProjectionElem::Field(field, _ty))) => {
|
||||
let base_ty = place_base.ty(body, tcx).ty;
|
||||
if (base_ty.is_closure() || base_ty.is_coroutine())
|
||||
if (base_ty.is_closure() || base_ty.is_coroutine() || base_ty.is_coroutine_closure())
|
||||
&& (!by_ref || upvars[field.index()].is_by_ref())
|
||||
{
|
||||
Some(field)
|
||||
|
||||
@ -1,26 +1,16 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
use crate::borrow_set::LocalsStateAtExit;
|
||||
use rustc_hir as hir;
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::mir::ProjectionElem;
|
||||
use rustc_middle::mir::{Body, Mutability, Place};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
|
||||
/// Extension methods for the `Place` type.
|
||||
pub trait PlaceExt<'tcx> {
|
||||
#[extension(pub trait PlaceExt<'tcx>)]
|
||||
impl<'tcx> Place<'tcx> {
|
||||
/// Returns `true` if we can safely ignore borrows of this place.
|
||||
/// This is true whenever there is no action that the user can do
|
||||
/// to the place `self` that would invalidate the borrow. This is true
|
||||
/// for borrows of raw pointer dereferents as well as shared references.
|
||||
fn ignore_borrow(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
locals_state_at_exit: &LocalsStateAtExit,
|
||||
) -> bool;
|
||||
}
|
||||
|
||||
impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
|
||||
fn ignore_borrow(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
||||
@ -50,8 +50,6 @@
|
||||
//! and either equal or disjoint.
|
||||
//! - If we did run out of access, the borrow can access a part of it.
|
||||
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
use crate::ArtificialField;
|
||||
use crate::Overlap;
|
||||
use crate::{AccessDepth, Deep, Shallow};
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
use rustc_data_structures::graph::dominators::Dominators;
|
||||
use rustc_middle::mir::visit::Visitor;
|
||||
use rustc_middle::mir::{self, BasicBlock, Body, Location, NonDivergingIntrinsic, Place, Rvalue};
|
||||
@ -163,7 +161,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'cx, 'tcx> {
|
||||
operands,
|
||||
options: _,
|
||||
line_spans: _,
|
||||
destination: _,
|
||||
targets: _,
|
||||
unwind: _,
|
||||
} => {
|
||||
for op in operands {
|
||||
@ -184,7 +182,8 @@ impl<'cx, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'cx, 'tcx> {
|
||||
}
|
||||
InlineAsmOperand::Const { value: _ }
|
||||
| InlineAsmOperand::SymFn { value: _ }
|
||||
| InlineAsmOperand::SymStatic { def_id: _ } => {}
|
||||
| InlineAsmOperand::SymStatic { def_id: _ }
|
||||
| InlineAsmOperand::Label { target_index: _ } => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -342,7 +341,6 @@ impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> {
|
||||
self,
|
||||
self.tcx,
|
||||
self.body,
|
||||
location,
|
||||
(sd, place),
|
||||
self.borrow_set,
|
||||
|_| true,
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
use rustc_middle::mir::visit::Visitor;
|
||||
use rustc_middle::mir::{
|
||||
Body, Local, Location, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind,
|
||||
|
||||
@ -1,9 +1,4 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
//! From the NLL RFC: "The deep [aka 'supporting'] prefixes for an
|
||||
//! place are formed by stripping away fields and derefs, except that
|
||||
//! we stop when we reach the deref of a shared reference. [...] "
|
||||
//!
|
||||
//! From the NLL RFC:
|
||||
//! "Shallow prefixes are found by stripping away fields, but stop at
|
||||
//! any dereference. So: writing a path like `a` is illegal if `a.b`
|
||||
//! is borrowed. But: writing `a` is legal if `*a` is borrowed,
|
||||
@ -11,9 +6,7 @@
|
||||
|
||||
use super::MirBorrowckCtxt;
|
||||
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::mir::{Body, PlaceRef, ProjectionElem};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_middle::mir::{PlaceRef, ProjectionElem};
|
||||
|
||||
pub trait IsPrefixOf<'tcx> {
|
||||
fn is_prefix_of(&self, other: PlaceRef<'tcx>) -> bool;
|
||||
@ -27,9 +20,7 @@ impl<'tcx> IsPrefixOf<'tcx> for PlaceRef<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct Prefixes<'cx, 'tcx> {
|
||||
body: &'cx Body<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
pub(super) struct Prefixes<'tcx> {
|
||||
kind: PrefixSet,
|
||||
next: Option<PlaceRef<'tcx>>,
|
||||
}
|
||||
@ -41,24 +32,18 @@ pub(super) enum PrefixSet {
|
||||
All,
|
||||
/// Stops at any dereference.
|
||||
Shallow,
|
||||
/// Stops at the deref of a shared reference.
|
||||
Supporting,
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
/// Returns an iterator over the prefixes of `place`
|
||||
/// (inclusive) from longest to smallest, potentially
|
||||
/// terminating the iteration early based on `kind`.
|
||||
pub(super) fn prefixes(
|
||||
&self,
|
||||
place_ref: PlaceRef<'tcx>,
|
||||
kind: PrefixSet,
|
||||
) -> Prefixes<'cx, 'tcx> {
|
||||
Prefixes { next: Some(place_ref), kind, body: self.body, tcx: self.infcx.tcx }
|
||||
pub(super) fn prefixes(&self, place_ref: PlaceRef<'tcx>, kind: PrefixSet) -> Prefixes<'tcx> {
|
||||
Prefixes { next: Some(place_ref), kind }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
|
||||
impl<'tcx> Iterator for Prefixes<'tcx> {
|
||||
type Item = PlaceRef<'tcx>;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let mut cursor = self.next?;
|
||||
@ -93,57 +78,23 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
|
||||
panic!("Subtype projection is not allowed before borrow check")
|
||||
}
|
||||
ProjectionElem::Deref => {
|
||||
// (handled below)
|
||||
match self.kind {
|
||||
PrefixSet::Shallow => {
|
||||
// Shallow prefixes are found by stripping away
|
||||
// fields, but stop at *any* dereference.
|
||||
// So we can just stop the traversal now.
|
||||
self.next = None;
|
||||
return Some(cursor);
|
||||
}
|
||||
PrefixSet::All => {
|
||||
// All prefixes: just blindly enqueue the base
|
||||
// of the projection.
|
||||
self.next = Some(cursor_base);
|
||||
return Some(cursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(elem, ProjectionElem::Deref);
|
||||
|
||||
match self.kind {
|
||||
PrefixSet::Shallow => {
|
||||
// Shallow prefixes are found by stripping away
|
||||
// fields, but stop at *any* dereference.
|
||||
// So we can just stop the traversal now.
|
||||
self.next = None;
|
||||
return Some(cursor);
|
||||
}
|
||||
PrefixSet::All => {
|
||||
// All prefixes: just blindly enqueue the base
|
||||
// of the projection.
|
||||
self.next = Some(cursor_base);
|
||||
return Some(cursor);
|
||||
}
|
||||
PrefixSet::Supporting => {
|
||||
// Fall through!
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(self.kind, PrefixSet::Supporting);
|
||||
// Supporting prefixes: strip away fields and
|
||||
// derefs, except we stop at the deref of a shared
|
||||
// reference.
|
||||
|
||||
let ty = cursor_base.ty(self.body, self.tcx).ty;
|
||||
match ty.kind() {
|
||||
ty::RawPtr(_) | ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Not) => {
|
||||
// don't continue traversing over derefs of raw pointers or shared
|
||||
// borrows.
|
||||
self.next = None;
|
||||
return Some(cursor);
|
||||
}
|
||||
|
||||
ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Mut) => {
|
||||
self.next = Some(cursor_base);
|
||||
return Some(cursor);
|
||||
}
|
||||
|
||||
ty::Adt(..) if ty.is_box() => {
|
||||
self.next = Some(cursor_base);
|
||||
return Some(cursor);
|
||||
}
|
||||
|
||||
_ => panic!("unknown type fed to Projection Deref."),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
//! As part of generating the regions, if you enable `-Zdump-mir=nll`,
|
||||
//! we will generate an annotated copy of the MIR that includes the
|
||||
//! state of region inference. This code handles emitting the region
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
//! This module provides linkage between RegionInferenceContext and
|
||||
//! `rustc_graphviz` traits, specialized to attaching borrowck analysis
|
||||
//! data to rendered labels.
|
||||
|
||||
@ -5,7 +5,7 @@ use rustc_data_structures::binary_search_util;
|
||||
use rustc_data_structures::frozen::Frozen;
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::graph::scc::Sccs;
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_errors::Diag;
|
||||
use rustc_hir::def_id::CRATE_DEF_ID;
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_infer::infer::outlives::test_type_match;
|
||||
@ -592,7 +592,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
}
|
||||
|
||||
/// Adds annotations for `#[rustc_regions]`; see `UniversalRegions::annotate`.
|
||||
pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diagnostic) {
|
||||
pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diag<'_, ()>) {
|
||||
self.universal_regions.annotate(tcx, err)
|
||||
}
|
||||
|
||||
@ -658,12 +658,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
pub(super) fn solve(
|
||||
&mut self,
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
polonius_output: Option<Rc<PoloniusOutput>>,
|
||||
) -> (Option<ClosureRegionRequirements<'tcx>>, RegionErrors<'tcx>) {
|
||||
let mir_def_id = body.source.def_id();
|
||||
self.propagate_constraints(body);
|
||||
self.propagate_constraints();
|
||||
|
||||
let mut errors_buffer = RegionErrors::new(infcx.tcx);
|
||||
|
||||
@ -674,7 +673,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
// eagerly.
|
||||
let mut outlives_requirements = infcx.tcx.is_typeck_child(mir_def_id).then(Vec::new);
|
||||
|
||||
self.check_type_tests(infcx, body, outlives_requirements.as_mut(), &mut errors_buffer);
|
||||
self.check_type_tests(infcx, outlives_requirements.as_mut(), &mut errors_buffer);
|
||||
|
||||
debug!(?errors_buffer);
|
||||
debug!(?outlives_requirements);
|
||||
@ -717,8 +716,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
/// for each region variable until all the constraints are
|
||||
/// satisfied. Note that some values may grow **too** large to be
|
||||
/// feasible, but we check this later.
|
||||
#[instrument(skip(self, _body), level = "debug")]
|
||||
fn propagate_constraints(&mut self, _body: &Body<'tcx>) {
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn propagate_constraints(&mut self) {
|
||||
debug!("constraints={:#?}", {
|
||||
let mut constraints: Vec<_> = self.outlives_constraints().collect();
|
||||
constraints.sort_by_key(|c| (c.sup, c.sub));
|
||||
@ -932,7 +931,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
fn check_type_tests(
|
||||
&self,
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
|
||||
errors_buffer: &mut RegionErrors<'tcx>,
|
||||
) {
|
||||
@ -957,12 +955,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
}
|
||||
|
||||
if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements {
|
||||
if self.try_promote_type_test(
|
||||
infcx,
|
||||
body,
|
||||
type_test,
|
||||
propagated_outlives_requirements,
|
||||
) {
|
||||
if self.try_promote_type_test(infcx, type_test, propagated_outlives_requirements) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -1016,7 +1009,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
fn try_promote_type_test(
|
||||
&self,
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
type_test: &TypeTest<'tcx>,
|
||||
propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement<'tcx>>,
|
||||
) -> bool {
|
||||
@ -1179,35 +1171,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
Some(ClosureOutlivesSubject::Ty(ClosureOutlivesSubjectTy::bind(tcx, ty)))
|
||||
}
|
||||
|
||||
/// Returns a universally quantified region that outlives the
|
||||
/// value of `r` (`r` may be existentially or universally
|
||||
/// quantified).
|
||||
///
|
||||
/// Since `r` is (potentially) an existential region, it has some
|
||||
/// value which may include (a) any number of points in the CFG
|
||||
/// and (b) any number of `end('x)` elements of universally
|
||||
/// quantified regions. To convert this into a single universal
|
||||
/// region we do as follows:
|
||||
///
|
||||
/// - Ignore the CFG points in `'r`. All universally quantified regions
|
||||
/// include the CFG anyhow.
|
||||
/// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding
|
||||
/// a result `'y`.
|
||||
#[instrument(skip(self), level = "debug", ret)]
|
||||
pub(crate) fn universal_upper_bound(&self, r: RegionVid) -> RegionVid {
|
||||
debug!(r = %self.region_value_str(r));
|
||||
|
||||
// Find the smallest universal region that contains all other
|
||||
// universal regions within `region`.
|
||||
let mut lub = self.universal_regions.fr_fn_body;
|
||||
let r_scc = self.constraint_sccs.scc(r);
|
||||
for ur in self.scc_values.universal_regions_outlived_by(r_scc) {
|
||||
lub = self.universal_region_relations.postdom_upper_bound(lub, ur);
|
||||
}
|
||||
|
||||
lub
|
||||
}
|
||||
|
||||
/// Like `universal_upper_bound`, but returns an approximation more suitable
|
||||
/// for diagnostics. If `r` contains multiple disjoint universal regions
|
||||
/// (e.g. 'a and 'b in `fn foo<'a, 'b> { ... }`, we pick the lower-numbered region.
|
||||
|
||||
@ -6,6 +6,7 @@ use rustc_hir::OpaqueTyOrigin;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_infer::infer::TyCtxtInferExt as _;
|
||||
use rustc_infer::traits::{Obligation, ObligationCause};
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::traits::DefiningAnchor;
|
||||
use rustc_middle::ty::visit::TypeVisitableExt;
|
||||
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
|
||||
@ -45,7 +46,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
/// be allowed:
|
||||
/// `fn f<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { x }`
|
||||
///
|
||||
/// Then we map the regions in both the type and the subst to their
|
||||
/// Then we map the regions in both the type and the generic parameters to their
|
||||
/// `external_name` giving `concrete_type = &'a i32`,
|
||||
/// `args = ['static, 'a]`. This will then allow
|
||||
/// `infer_opaque_definition_from_instantiation` to determine that
|
||||
@ -77,9 +78,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
let args = opaque_type_key.args;
|
||||
debug!(?concrete_type, ?args);
|
||||
|
||||
let mut subst_regions = vec![self.universal_regions.fr_static];
|
||||
let mut arg_regions = vec![self.universal_regions.fr_static];
|
||||
|
||||
let to_universal_region = |vid, subst_regions: &mut Vec<_>| {
|
||||
let to_universal_region = |vid, arg_regions: &mut Vec<_>| {
|
||||
trace!(?vid);
|
||||
let scc = self.constraint_sccs.scc(vid);
|
||||
trace!(?scc);
|
||||
@ -88,11 +89,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
}) {
|
||||
Some(region) => {
|
||||
let vid = self.universal_regions.to_region_vid(region);
|
||||
subst_regions.push(vid);
|
||||
arg_regions.push(vid);
|
||||
region
|
||||
}
|
||||
None => {
|
||||
subst_regions.push(vid);
|
||||
arg_regions.push(vid);
|
||||
ty::Region::new_error_with_message(
|
||||
infcx.tcx,
|
||||
concrete_type.span,
|
||||
@ -106,10 +107,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
// This will ensure they get precedence when folding the regions in the concrete type.
|
||||
if let Some(&ci) = member_constraints.get(&opaque_type_key) {
|
||||
for &vid in self.member_constraints.choice_regions(ci) {
|
||||
to_universal_region(vid, &mut subst_regions);
|
||||
to_universal_region(vid, &mut arg_regions);
|
||||
}
|
||||
}
|
||||
debug!(?subst_regions);
|
||||
debug!(?arg_regions);
|
||||
|
||||
// Next, insert universal regions from args, so we can translate regions that appear
|
||||
// in them but are not subject to member constraints, for instance closure args.
|
||||
@ -119,18 +120,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
return region;
|
||||
}
|
||||
let vid = self.to_region_vid(region);
|
||||
to_universal_region(vid, &mut subst_regions)
|
||||
to_universal_region(vid, &mut arg_regions)
|
||||
});
|
||||
debug!(?universal_args);
|
||||
debug!(?subst_regions);
|
||||
debug!(?arg_regions);
|
||||
|
||||
// Deduplicate the set of regions while keeping the chosen order.
|
||||
let subst_regions = subst_regions.into_iter().collect::<FxIndexSet<_>>();
|
||||
debug!(?subst_regions);
|
||||
let arg_regions = arg_regions.into_iter().collect::<FxIndexSet<_>>();
|
||||
debug!(?arg_regions);
|
||||
|
||||
let universal_concrete_type =
|
||||
infcx.tcx.fold_regions(concrete_type, |region, _| match *region {
|
||||
ty::ReVar(vid) => subst_regions
|
||||
ty::ReVar(vid) => arg_regions
|
||||
.iter()
|
||||
.find(|ur_vid| self.eval_equal(vid, **ur_vid))
|
||||
.and_then(|ur_vid| self.definitions[*ur_vid].external_name)
|
||||
@ -152,12 +153,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
if let Some(prev) = result.get_mut(&opaque_type_key.def_id) {
|
||||
if prev.ty != ty {
|
||||
let guar = ty.error_reported().err().unwrap_or_else(|| {
|
||||
prev.report_mismatch(
|
||||
&OpaqueHiddenType { ty, span: concrete_type.span },
|
||||
opaque_type_key.def_id,
|
||||
infcx.tcx,
|
||||
)
|
||||
.emit()
|
||||
let (Ok(e) | Err(e)) = prev
|
||||
.build_mismatch_error(
|
||||
&OpaqueHiddenType { ty, span: concrete_type.span },
|
||||
opaque_type_key.def_id,
|
||||
infcx.tcx,
|
||||
)
|
||||
.map(|d| d.emit());
|
||||
e
|
||||
});
|
||||
prev.ty = Ty::new_error(infcx.tcx, guar);
|
||||
}
|
||||
@ -225,15 +228,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait InferCtxtExt<'tcx> {
|
||||
fn infer_opaque_definition_from_instantiation(
|
||||
&self,
|
||||
opaque_type_key: OpaqueTypeKey<'tcx>,
|
||||
instantiated_ty: OpaqueHiddenType<'tcx>,
|
||||
) -> Ty<'tcx>;
|
||||
}
|
||||
|
||||
impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
||||
#[extension(pub trait InferCtxtExt<'tcx>)]
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
/// Given the fully resolved, instantiated type for an opaque
|
||||
/// type, i.e., the value of an inference variable like C1 or C2
|
||||
/// (*), computes the "definition type" for an opaque type
|
||||
@ -315,13 +311,13 @@ fn check_opaque_type_well_formed<'tcx>(
|
||||
parent_def_id = tcx.local_parent(parent_def_id);
|
||||
}
|
||||
|
||||
// FIXME(-Znext-solver): We probably should use `DefiningAnchor::Error`
|
||||
// FIXME(-Znext-solver): We probably should use `DefiningAnchor::Bind(&[])`
|
||||
// and prepopulate this `InferCtxt` with known opaque values, rather than
|
||||
// using the `Bind` anchor here. For now it's fine.
|
||||
let infcx = tcx
|
||||
.infer_ctxt()
|
||||
.with_next_trait_solver(next_trait_solver)
|
||||
.with_opaque_type_inference(DefiningAnchor::Bind(parent_def_id))
|
||||
.with_opaque_type_inference(DefiningAnchor::bind(tcx, parent_def_id))
|
||||
.build();
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
let identity_args = GenericArgs::identity_for_item(tcx, def_id);
|
||||
@ -371,14 +367,17 @@ fn check_opaque_type_parameter_valid(
|
||||
span: Span,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
let opaque_ty_hir = tcx.hir().expect_item(opaque_type_key.def_id);
|
||||
let is_ty_alias = match opaque_ty_hir.expect_opaque_ty().origin {
|
||||
OpaqueTyOrigin::TyAlias { .. } => true,
|
||||
OpaqueTyOrigin::AsyncFn(..) | OpaqueTyOrigin::FnReturn(..) => false,
|
||||
let (parent, is_ty_alias) = match opaque_ty_hir.expect_opaque_ty().origin {
|
||||
OpaqueTyOrigin::TyAlias { parent, .. } => (parent, true),
|
||||
OpaqueTyOrigin::AsyncFn(parent) | OpaqueTyOrigin::FnReturn(parent) => (parent, false),
|
||||
};
|
||||
|
||||
let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
|
||||
let parent_generics = tcx.generics_of(parent);
|
||||
let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default();
|
||||
for (i, arg) in opaque_type_key.args.iter().enumerate() {
|
||||
|
||||
// Only check the parent generics, which will ignore any of the
|
||||
// duplicated lifetime args that come from reifying late-bounds.
|
||||
for (i, arg) in opaque_type_key.args.iter().take(parent_generics.count()).enumerate() {
|
||||
if let Err(guar) = arg.error_reported() {
|
||||
return Err(guar);
|
||||
}
|
||||
@ -399,7 +398,7 @@ fn check_opaque_type_parameter_valid(
|
||||
seen_params.entry(arg).or_default().push(i);
|
||||
} else {
|
||||
// Prevent `fn foo() -> Foo<u32>` from being defining.
|
||||
let opaque_param = opaque_generics.param_at(i, tcx);
|
||||
let opaque_param = parent_generics.param_at(i, tcx);
|
||||
let kind = opaque_param.kind.descr();
|
||||
|
||||
return Err(tcx.dcx().emit_err(NonGenericOpaqueTypeParam {
|
||||
@ -413,11 +412,13 @@ fn check_opaque_type_parameter_valid(
|
||||
|
||||
for (_, indices) in seen_params {
|
||||
if indices.len() > 1 {
|
||||
let descr = opaque_generics.param_at(indices[0], tcx).kind.descr();
|
||||
let descr = parent_generics.param_at(indices[0], tcx).kind.descr();
|
||||
let spans: Vec<_> = indices
|
||||
.into_iter()
|
||||
.map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
|
||||
.map(|i| tcx.def_span(parent_generics.param_at(i, tcx).def_id))
|
||||
.collect();
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
return Err(tcx
|
||||
.dcx()
|
||||
.struct_span_err(span, "non-defining opaque type use in defining scope")
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
use crate::constraints::ConstraintSccIndex;
|
||||
use crate::RegionInferenceContext;
|
||||
use itertools::Itertools;
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_index::bit_set::SparseBitMatrix;
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
use crate::BorrowckInferCtxt;
|
||||
use rustc_index::IndexSlice;
|
||||
use rustc_infer::infer::NllRegionVariableOrigin;
|
||||
|
||||
@ -368,6 +368,11 @@ pub(crate) enum CaptureReasonNote {
|
||||
#[primary_span]
|
||||
var_span: Span,
|
||||
},
|
||||
#[note(borrowck_calling_operator_moves)]
|
||||
UnOpMoveByOperator {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[note(borrowck_calling_operator_moves_lhs)]
|
||||
LhsMoveByOperator {
|
||||
#[primary_span]
|
||||
@ -454,8 +459,10 @@ pub(crate) enum TypeNoCopy<'a, 'tcx> {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(borrowck_simd_shuffle_last_const)]
|
||||
pub(crate) struct SimdShuffleLastConst {
|
||||
#[diag(borrowck_simd_intrinsic_arg_const)]
|
||||
pub(crate) struct SimdIntrinsicArgConst {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub arg: usize,
|
||||
pub intrinsic: String,
|
||||
}
|
||||
|
||||
@ -100,7 +100,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
locations: Locations,
|
||||
) {
|
||||
for (predicate, span) in instantiated_predicates {
|
||||
debug!(?predicate);
|
||||
debug!(?span, ?predicate);
|
||||
let category = ConstraintCategory::Predicate(span);
|
||||
let predicate = self.normalize_with_category(predicate, locations, category);
|
||||
self.prove_predicate(predicate, locations, category);
|
||||
|
||||
@ -5,10 +5,13 @@ use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelega
|
||||
use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
|
||||
use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
|
||||
use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory};
|
||||
use rustc_middle::ty::GenericArgKind;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_middle::ty::{TypeFoldable, TypeVisitableExt};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::solve::deeply_normalize;
|
||||
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
|
||||
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
|
||||
|
||||
use crate::{
|
||||
constraints::OutlivesConstraint,
|
||||
@ -33,6 +36,7 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> {
|
||||
/// our special inference variable there, we would mess that up.
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
locations: Locations,
|
||||
span: Span,
|
||||
@ -47,6 +51,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||
universal_regions: &'a UniversalRegions<'tcx>,
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
locations: Locations,
|
||||
span: Span,
|
||||
@ -59,6 +64,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||
universal_regions,
|
||||
region_bound_pairs,
|
||||
implicit_region_bound,
|
||||
param_env,
|
||||
known_type_outlives_obligations,
|
||||
locations,
|
||||
span,
|
||||
@ -137,36 +143,68 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||
// Extract out various useful fields we'll need below.
|
||||
let ConstraintConversion {
|
||||
tcx,
|
||||
infcx,
|
||||
region_bound_pairs,
|
||||
implicit_region_bound,
|
||||
known_type_outlives_obligations,
|
||||
..
|
||||
} = *self;
|
||||
|
||||
let ty::OutlivesPredicate(k1, r2) = predicate;
|
||||
match k1.unpack() {
|
||||
GenericArgKind::Lifetime(r1) => {
|
||||
let r1_vid = self.to_region_vid(r1);
|
||||
let r2_vid = self.to_region_vid(r2);
|
||||
self.add_outlives(r1_vid, r2_vid, constraint_category);
|
||||
let mut outlives_predicates = vec![(predicate, constraint_category)];
|
||||
for iteration in 0.. {
|
||||
if outlives_predicates.is_empty() {
|
||||
break;
|
||||
}
|
||||
|
||||
GenericArgKind::Type(t1) => {
|
||||
// we don't actually use this for anything, but
|
||||
// the `TypeOutlives` code needs an origin.
|
||||
let origin = infer::RelateParamBound(DUMMY_SP, t1, None);
|
||||
|
||||
TypeOutlives::new(
|
||||
&mut *self,
|
||||
tcx,
|
||||
region_bound_pairs,
|
||||
Some(implicit_region_bound),
|
||||
known_type_outlives_obligations,
|
||||
)
|
||||
.type_must_outlive(origin, t1, r2, constraint_category);
|
||||
if !self.tcx.recursion_limit().value_within_limit(iteration) {
|
||||
bug!(
|
||||
"FIXME(-Znext-solver): Overflowed when processing region obligations: {outlives_predicates:#?}"
|
||||
);
|
||||
}
|
||||
|
||||
GenericArgKind::Const(_) => unreachable!(),
|
||||
let mut next_outlives_predicates = vec![];
|
||||
for (ty::OutlivesPredicate(k1, r2), constraint_category) in outlives_predicates {
|
||||
match k1.unpack() {
|
||||
GenericArgKind::Lifetime(r1) => {
|
||||
let r1_vid = self.to_region_vid(r1);
|
||||
let r2_vid = self.to_region_vid(r2);
|
||||
self.add_outlives(r1_vid, r2_vid, constraint_category);
|
||||
}
|
||||
|
||||
GenericArgKind::Type(mut t1) => {
|
||||
// Normalize the type we receive from a `TypeOutlives` obligation
|
||||
// in the new trait solver.
|
||||
if infcx.next_trait_solver() {
|
||||
t1 = self.normalize_and_add_type_outlives_constraints(
|
||||
t1,
|
||||
&mut next_outlives_predicates,
|
||||
);
|
||||
}
|
||||
|
||||
// we don't actually use this for anything, but
|
||||
// the `TypeOutlives` code needs an origin.
|
||||
let origin = infer::RelateParamBound(self.span, t1, None);
|
||||
|
||||
TypeOutlives::new(
|
||||
&mut *self,
|
||||
tcx,
|
||||
region_bound_pairs,
|
||||
Some(implicit_region_bound),
|
||||
known_type_outlives_obligations,
|
||||
)
|
||||
.type_must_outlive(
|
||||
origin,
|
||||
t1,
|
||||
r2,
|
||||
constraint_category,
|
||||
);
|
||||
}
|
||||
|
||||
GenericArgKind::Const(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
outlives_predicates = next_outlives_predicates;
|
||||
}
|
||||
}
|
||||
|
||||
@ -232,6 +270,42 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||
debug!("add_type_test(type_test={:?})", type_test);
|
||||
self.constraints.type_tests.push(type_test);
|
||||
}
|
||||
|
||||
fn normalize_and_add_type_outlives_constraints(
|
||||
&self,
|
||||
ty: Ty<'tcx>,
|
||||
next_outlives_predicates: &mut Vec<(
|
||||
ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>,
|
||||
ConstraintCategory<'tcx>,
|
||||
)>,
|
||||
) -> Ty<'tcx> {
|
||||
let result = CustomTypeOp::new(
|
||||
|ocx| {
|
||||
deeply_normalize(
|
||||
ocx.infcx.at(&ObligationCause::dummy_with_span(self.span), self.param_env),
|
||||
ty,
|
||||
)
|
||||
.map_err(|_| NoSolution)
|
||||
},
|
||||
"normalize type outlives obligation",
|
||||
)
|
||||
.fully_perform(self.infcx, self.span);
|
||||
|
||||
match result {
|
||||
Ok(TypeOpOutput { output: ty, constraints, .. }) => {
|
||||
if let Some(constraints) = constraints {
|
||||
assert!(
|
||||
constraints.member_constraints.is_empty(),
|
||||
"no member constraints expected from normalizing: {:#?}",
|
||||
constraints.member_constraints
|
||||
);
|
||||
next_outlives_predicates.extend(constraints.outlives.iter().copied());
|
||||
}
|
||||
ty
|
||||
}
|
||||
Err(_) => ty,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'b, 'tcx> {
|
||||
|
||||
@ -8,8 +8,11 @@ use rustc_infer::infer::region_constraints::GenericKind;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::traits::query::OutlivesBound;
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt};
|
||||
use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
|
||||
use rustc_span::{ErrorGuaranteed, Span};
|
||||
use rustc_trait_selection::solve::deeply_normalize;
|
||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
|
||||
use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
|
||||
use std::rc::Rc;
|
||||
use type_op::TypeOpOutput;
|
||||
@ -52,7 +55,6 @@ pub(crate) struct CreateResult<'tcx> {
|
||||
pub(crate) fn create<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
universal_regions: &Rc<UniversalRegions<'tcx>>,
|
||||
constraints: &mut MirTypeckRegionConstraints<'tcx>,
|
||||
@ -60,7 +62,6 @@ pub(crate) fn create<'tcx>(
|
||||
UniversalRegionRelationsBuilder {
|
||||
infcx,
|
||||
param_env,
|
||||
known_type_outlives_obligations,
|
||||
implicit_region_bound,
|
||||
constraints,
|
||||
universal_regions: universal_regions.clone(),
|
||||
@ -178,7 +179,6 @@ impl UniversalRegionRelations<'_> {
|
||||
struct UniversalRegionRelationsBuilder<'this, 'tcx> {
|
||||
infcx: &'this InferCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
universal_regions: Rc<UniversalRegions<'tcx>>,
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
constraints: &'this mut MirTypeckRegionConstraints<'tcx>,
|
||||
@ -222,6 +222,32 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||
self.relate_universal_regions(fr, fr_fn_body);
|
||||
}
|
||||
|
||||
// Normalize the assumptions we use to borrowck the program.
|
||||
let mut constraints = vec![];
|
||||
let mut known_type_outlives_obligations = vec![];
|
||||
for bound in param_env.caller_bounds() {
|
||||
let Some(mut outlives) = bound.as_type_outlives_clause() else { continue };
|
||||
|
||||
// In the new solver, normalize the type-outlives obligation assumptions.
|
||||
if self.infcx.next_trait_solver() {
|
||||
match deeply_normalize(
|
||||
self.infcx.at(&ObligationCause::misc(span, defining_ty_def_id), self.param_env),
|
||||
outlives,
|
||||
) {
|
||||
Ok(normalized_outlives) => {
|
||||
outlives = normalized_outlives;
|
||||
}
|
||||
Err(e) => {
|
||||
self.infcx.err_ctxt().report_fulfillment_errors(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
known_type_outlives_obligations.push(outlives);
|
||||
}
|
||||
let known_type_outlives_obligations =
|
||||
self.infcx.tcx.arena.alloc_slice(&known_type_outlives_obligations);
|
||||
|
||||
let unnormalized_input_output_tys = self
|
||||
.universal_regions
|
||||
.unnormalized_input_tys
|
||||
@ -239,12 +265,11 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||
// the `relations` is built.
|
||||
let mut normalized_inputs_and_output =
|
||||
Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1);
|
||||
let mut constraints = vec![];
|
||||
for ty in unnormalized_input_output_tys {
|
||||
debug!("build: input_or_output={:?}", ty);
|
||||
// We add implied bounds from both the unnormalized and normalized ty.
|
||||
// See issue #87748
|
||||
let constraints_unnorm = self.add_implied_bounds(ty);
|
||||
let constraints_unnorm = self.add_implied_bounds(ty, span);
|
||||
if let Some(c) = constraints_unnorm {
|
||||
constraints.push(c)
|
||||
}
|
||||
@ -274,7 +299,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||
// ```
|
||||
// Both &Self::Bar and &() are WF
|
||||
if ty != norm_ty {
|
||||
let constraints_norm = self.add_implied_bounds(norm_ty);
|
||||
let constraints_norm = self.add_implied_bounds(norm_ty, span);
|
||||
if let Some(c) = constraints_norm {
|
||||
constraints.push(c)
|
||||
}
|
||||
@ -286,25 +311,37 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||
// Add implied bounds from impl header.
|
||||
if matches!(tcx.def_kind(defining_ty_def_id), DefKind::AssocFn | DefKind::AssocConst) {
|
||||
for &(ty, _) in tcx.assumed_wf_types(tcx.local_parent(defining_ty_def_id)) {
|
||||
let Ok(TypeOpOutput { output: norm_ty, constraints: c, .. }) = self
|
||||
let result: Result<_, ErrorGuaranteed> = self
|
||||
.param_env
|
||||
.and(type_op::normalize::Normalize::new(ty))
|
||||
.fully_perform(self.infcx, span)
|
||||
else {
|
||||
tcx.dcx().span_delayed_bug(span, format!("failed to normalize {ty:?}"));
|
||||
.fully_perform(self.infcx, span);
|
||||
let Ok(TypeOpOutput { output: norm_ty, constraints: c, .. }) = result else {
|
||||
continue;
|
||||
};
|
||||
|
||||
constraints.extend(c);
|
||||
|
||||
// We currently add implied bounds from the normalized ty only.
|
||||
// This is more conservative and matches wfcheck behavior.
|
||||
let c = self.add_implied_bounds(norm_ty);
|
||||
let c = self.add_implied_bounds(norm_ty, span);
|
||||
constraints.extend(c);
|
||||
}
|
||||
}
|
||||
|
||||
for c in constraints {
|
||||
self.push_region_constraints(c, span);
|
||||
constraint_conversion::ConstraintConversion::new(
|
||||
self.infcx,
|
||||
&self.universal_regions,
|
||||
&self.region_bound_pairs,
|
||||
self.implicit_region_bound,
|
||||
param_env,
|
||||
known_type_outlives_obligations,
|
||||
Locations::All(span),
|
||||
span,
|
||||
ConstraintCategory::Internal,
|
||||
self.constraints,
|
||||
)
|
||||
.convert_all(c);
|
||||
}
|
||||
|
||||
CreateResult {
|
||||
@ -313,40 +350,26 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||
outlives: self.outlives.freeze(),
|
||||
inverse_outlives: self.inverse_outlives.freeze(),
|
||||
}),
|
||||
known_type_outlives_obligations: self.known_type_outlives_obligations,
|
||||
known_type_outlives_obligations,
|
||||
region_bound_pairs: self.region_bound_pairs,
|
||||
normalized_inputs_and_output,
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(self, data), level = "debug")]
|
||||
fn push_region_constraints(&mut self, data: &QueryRegionConstraints<'tcx>, span: Span) {
|
||||
debug!("constraints generated: {:#?}", data);
|
||||
|
||||
constraint_conversion::ConstraintConversion::new(
|
||||
self.infcx,
|
||||
&self.universal_regions,
|
||||
&self.region_bound_pairs,
|
||||
self.implicit_region_bound,
|
||||
self.known_type_outlives_obligations,
|
||||
Locations::All(span),
|
||||
span,
|
||||
ConstraintCategory::Internal,
|
||||
self.constraints,
|
||||
)
|
||||
.convert_all(data);
|
||||
}
|
||||
|
||||
/// Update the type of a single local, which should represent
|
||||
/// either the return type of the MIR or one of its arguments. At
|
||||
/// the same time, compute and add any implied bounds that come
|
||||
/// from this local.
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn add_implied_bounds(&mut self, ty: Ty<'tcx>) -> Option<&'tcx QueryRegionConstraints<'tcx>> {
|
||||
fn add_implied_bounds(
|
||||
&mut self,
|
||||
ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
) -> Option<&'tcx QueryRegionConstraints<'tcx>> {
|
||||
let TypeOpOutput { output: bounds, constraints, .. } = self
|
||||
.param_env
|
||||
.and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
|
||||
.fully_perform(self.infcx, DUMMY_SP)
|
||||
.fully_perform(self.infcx, span)
|
||||
.map_err(|_: ErrorGuaranteed| debug!("failed to compute implied bounds {:?}", ty))
|
||||
.ok()?;
|
||||
debug!(?bounds, ?constraints);
|
||||
|
||||
@ -7,13 +7,18 @@
|
||||
//! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
|
||||
//! contain revealed `impl Trait` values).
|
||||
|
||||
use std::assert_matches::assert_matches;
|
||||
|
||||
use itertools::Itertools;
|
||||
use rustc_infer::infer::BoundRegionConversionTime;
|
||||
use rustc_hir as hir;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::{BoundRegionConversionTime, RegionVariableOrigin};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::universal_regions::UniversalRegions;
|
||||
use crate::renumber::RegionCtxt;
|
||||
use crate::universal_regions::{DefiningTy, UniversalRegions};
|
||||
|
||||
use super::{Locations, TypeChecker};
|
||||
|
||||
@ -23,9 +28,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
#[instrument(skip(self, body), level = "debug")]
|
||||
pub(super) fn check_signature_annotation(&mut self, body: &Body<'tcx>) {
|
||||
let mir_def_id = body.source.def_id().expect_local();
|
||||
if !self.tcx().is_closure_or_coroutine(mir_def_id.to_def_id()) {
|
||||
|
||||
if !self.tcx().is_closure_like(mir_def_id.to_def_id()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let user_provided_poly_sig = self.tcx().closure_user_provided_sig(mir_def_id);
|
||||
|
||||
// Instantiate the canonicalized variables from user-provided signature
|
||||
@ -34,12 +41,75 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
// so that they represent the view from "inside" the closure.
|
||||
let user_provided_sig = self
|
||||
.instantiate_canonical_with_fresh_inference_vars(body.span, &user_provided_poly_sig);
|
||||
let user_provided_sig = self.infcx.instantiate_binder_with_fresh_vars(
|
||||
let mut user_provided_sig = self.infcx.instantiate_binder_with_fresh_vars(
|
||||
body.span,
|
||||
BoundRegionConversionTime::FnCall,
|
||||
user_provided_sig,
|
||||
);
|
||||
|
||||
// FIXME(async_closures): It's kind of wacky that we must apply this
|
||||
// transformation here, since we do the same thing in HIR typeck.
|
||||
// Maybe we could just fix up the canonicalized signature during HIR typeck?
|
||||
if let DefiningTy::CoroutineClosure(_, args) =
|
||||
self.borrowck_context.universal_regions.defining_ty
|
||||
{
|
||||
assert_matches!(
|
||||
self.tcx().coroutine_kind(self.tcx().coroutine_for_closure(mir_def_id)),
|
||||
Some(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Async,
|
||||
hir::CoroutineSource::Closure
|
||||
)),
|
||||
"this needs to be modified if we're lowering non-async closures"
|
||||
);
|
||||
// Make sure to use the args from `DefiningTy` so the right NLL region vids are prepopulated
|
||||
// into the type.
|
||||
let args = args.as_coroutine_closure();
|
||||
let tupled_upvars_ty = ty::CoroutineClosureSignature::tupled_upvars_by_closure_kind(
|
||||
self.tcx(),
|
||||
args.kind(),
|
||||
Ty::new_tup(self.tcx(), user_provided_sig.inputs()),
|
||||
args.tupled_upvars_ty(),
|
||||
args.coroutine_captures_by_ref_ty(),
|
||||
self.infcx.next_region_var(RegionVariableOrigin::MiscVariable(body.span), || {
|
||||
RegionCtxt::Unknown
|
||||
}),
|
||||
);
|
||||
|
||||
let next_ty_var = || {
|
||||
self.infcx.next_ty_var(TypeVariableOrigin {
|
||||
span: body.span,
|
||||
kind: TypeVariableOriginKind::MiscVariable,
|
||||
})
|
||||
};
|
||||
let output_ty = Ty::new_coroutine(
|
||||
self.tcx(),
|
||||
self.tcx().coroutine_for_closure(mir_def_id),
|
||||
ty::CoroutineArgs::new(
|
||||
self.tcx(),
|
||||
ty::CoroutineArgsParts {
|
||||
parent_args: args.parent_args(),
|
||||
kind_ty: Ty::from_closure_kind(self.tcx(), args.kind()),
|
||||
return_ty: user_provided_sig.output(),
|
||||
tupled_upvars_ty,
|
||||
// For async closures, none of these can be annotated, so just fill
|
||||
// them with fresh ty vars.
|
||||
resume_ty: next_ty_var(),
|
||||
yield_ty: next_ty_var(),
|
||||
witness: next_ty_var(),
|
||||
},
|
||||
)
|
||||
.args,
|
||||
);
|
||||
|
||||
user_provided_sig = self.tcx().mk_fn_sig(
|
||||
user_provided_sig.inputs().iter().copied(),
|
||||
output_ty,
|
||||
user_provided_sig.c_variadic,
|
||||
user_provided_sig.unsafety,
|
||||
user_provided_sig.abi,
|
||||
);
|
||||
}
|
||||
|
||||
let is_coroutine_with_implicit_resume_ty = self.tcx().is_coroutine(mir_def_id.to_def_id())
|
||||
&& user_provided_sig.inputs().is_empty();
|
||||
|
||||
@ -84,8 +154,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
if argument_index + 1 >= body.local_decls.len() {
|
||||
self.tcx()
|
||||
.dcx()
|
||||
.span_delayed_bug(body.span, "found more normalized_input_ty than local_decls");
|
||||
break;
|
||||
.span_bug(body.span, "found more normalized_input_ty than local_decls");
|
||||
}
|
||||
|
||||
// In MIR, argument N is stored in local N+1.
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
//! This pass type-checks the MIR to ensure it is not broken.
|
||||
|
||||
use std::rc::Rc;
|
||||
@ -39,7 +37,7 @@ use rustc_mir_dataflow::points::DenseLocationMap;
|
||||
use rustc_span::def_id::CRATE_DEF_ID;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_span::Span;
|
||||
use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
|
||||
use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints;
|
||||
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
|
||||
@ -51,7 +49,7 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
|
||||
use rustc_mir_dataflow::move_paths::MoveData;
|
||||
use rustc_mir_dataflow::ResultsCursor;
|
||||
|
||||
use crate::session_diagnostics::{MoveUnsized, SimdShuffleLastConst};
|
||||
use crate::session_diagnostics::{MoveUnsized, SimdIntrinsicArgConst};
|
||||
use crate::{
|
||||
borrow_set::BorrowSet,
|
||||
constraints::{OutlivesConstraint, OutlivesConstraintSet},
|
||||
@ -156,10 +154,6 @@ pub(crate) fn type_check<'mir, 'tcx>(
|
||||
} = free_region_relations::create(
|
||||
infcx,
|
||||
param_env,
|
||||
// FIXME(-Znext-solver): These are unnormalized. Normalize them.
|
||||
infcx.tcx.arena.alloc_from_iter(
|
||||
param_env.caller_bounds().iter().filter_map(|clause| clause.as_type_outlives_clause()),
|
||||
),
|
||||
implicit_region_bound,
|
||||
universal_regions,
|
||||
&mut constraints,
|
||||
@ -217,7 +211,6 @@ pub(crate) fn type_check<'mir, 'tcx>(
|
||||
CustomTypeOp::new(
|
||||
|ocx| {
|
||||
ocx.infcx.register_member_constraints(
|
||||
param_env,
|
||||
opaque_type_key,
|
||||
decl.hidden_type.ty,
|
||||
decl.hidden_type.span,
|
||||
@ -227,14 +220,13 @@ pub(crate) fn type_check<'mir, 'tcx>(
|
||||
"opaque_type_map",
|
||||
),
|
||||
);
|
||||
let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type);
|
||||
let hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type);
|
||||
trace!("finalized opaque type {:?} to {:#?}", opaque_type_key, hidden_type.ty.kind());
|
||||
if hidden_type.has_non_region_infer() {
|
||||
let reported = infcx.dcx().span_delayed_bug(
|
||||
infcx.dcx().span_bug(
|
||||
decl.hidden_type.span,
|
||||
format!("could not resolve {:#?}", hidden_type.ty.kind()),
|
||||
);
|
||||
hidden_type.ty = Ty::new_error(infcx.tcx, reported);
|
||||
}
|
||||
|
||||
(opaque_type_key, hidden_type)
|
||||
@ -808,6 +800,14 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
||||
}),
|
||||
};
|
||||
}
|
||||
ty::CoroutineClosure(_, args) => {
|
||||
return match args.as_coroutine_closure().upvar_tys().get(field.index()) {
|
||||
Some(&ty) => Ok(ty),
|
||||
None => Err(FieldAccessError::OutOfRange {
|
||||
field_count: args.as_coroutine_closure().upvar_tys().len(),
|
||||
}),
|
||||
};
|
||||
}
|
||||
ty::Coroutine(_, args) => {
|
||||
// Only prefix fields (upvars and current state) are
|
||||
// accessible without a variant index.
|
||||
@ -1013,7 +1013,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
) -> Self {
|
||||
let mut checker = Self {
|
||||
infcx,
|
||||
last_span: DUMMY_SP,
|
||||
last_span: body.span,
|
||||
body,
|
||||
user_type_annotations: &body.user_type_annotations,
|
||||
param_env,
|
||||
@ -1066,7 +1066,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
&cause,
|
||||
param_env,
|
||||
hidden_ty.ty,
|
||||
true,
|
||||
&mut obligations,
|
||||
)?;
|
||||
|
||||
@ -1088,10 +1087,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
);
|
||||
|
||||
if result.is_err() {
|
||||
self.infcx.dcx().span_delayed_bug(
|
||||
self.body.span,
|
||||
"failed re-defining predefined opaques in mir typeck",
|
||||
);
|
||||
self.infcx
|
||||
.dcx()
|
||||
.span_bug(self.body.span, "failed re-defining predefined opaques in mir typeck");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1136,6 +1134,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
self.borrowck_context.universal_regions,
|
||||
self.region_bound_pairs,
|
||||
self.implicit_region_bound,
|
||||
self.param_env,
|
||||
self.known_type_outlives_obligations,
|
||||
locations,
|
||||
locations.span(self.body),
|
||||
@ -1430,7 +1429,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
return;
|
||||
}
|
||||
};
|
||||
let (sig, map) = tcx.instantiate_bound_regions(sig, |br| {
|
||||
let (unnormalized_sig, map) = tcx.instantiate_bound_regions(sig, |br| {
|
||||
use crate::renumber::RegionCtxt;
|
||||
|
||||
let region_ctxt_fn = || {
|
||||
@ -1452,7 +1451,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
region_ctxt_fn,
|
||||
)
|
||||
});
|
||||
debug!(?sig);
|
||||
debug!(?unnormalized_sig);
|
||||
// IMPORTANT: We have to prove well formed for the function signature before
|
||||
// we normalize it, as otherwise types like `<&'a &'b () as Trait>::Assoc`
|
||||
// get normalized away, causing us to ignore the `'b: 'a` bound used by the function.
|
||||
@ -1462,7 +1461,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
//
|
||||
// See #91068 for an example.
|
||||
self.prove_predicates(
|
||||
sig.inputs_and_output.iter().map(|ty| {
|
||||
unnormalized_sig.inputs_and_output.iter().map(|ty| {
|
||||
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(
|
||||
ty.into(),
|
||||
)))
|
||||
@ -1470,7 +1469,23 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
term_location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
);
|
||||
let sig = self.normalize(sig, term_location);
|
||||
|
||||
let sig = self.normalize(unnormalized_sig, term_location);
|
||||
// HACK(#114936): `WF(sig)` does not imply `WF(normalized(sig))`
|
||||
// with built-in `Fn` implementations, since the impl may not be
|
||||
// well-formed itself.
|
||||
if sig != unnormalized_sig {
|
||||
self.prove_predicates(
|
||||
sig.inputs_and_output.iter().map(|ty| {
|
||||
ty::Binder::dummy(ty::PredicateKind::Clause(
|
||||
ty::ClauseKind::WellFormed(ty.into()),
|
||||
))
|
||||
}),
|
||||
term_location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
);
|
||||
}
|
||||
|
||||
self.check_call_dest(body, term, &sig, *destination, *target, term_location);
|
||||
|
||||
// The ordinary liveness rules will ensure that all
|
||||
@ -1648,16 +1663,22 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
|
||||
let func_ty = func.ty(body, self.infcx.tcx);
|
||||
if let ty::FnDef(def_id, _) = *func_ty.kind() {
|
||||
if self.tcx().is_intrinsic(def_id) {
|
||||
match self.tcx().item_name(def_id) {
|
||||
sym::simd_shuffle => {
|
||||
if !matches!(args[2], Spanned { node: Operand::Constant(_), .. }) {
|
||||
self.tcx()
|
||||
.dcx()
|
||||
.emit_err(SimdShuffleLastConst { span: term.source_info.span });
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
// Some of the SIMD intrinsics are special: they need a particular argument to be a constant.
|
||||
// (Eventually this should use const-generics, but those are not up for the task yet:
|
||||
// https://github.com/rust-lang/rust/issues/85229.)
|
||||
if let Some(name @ (sym::simd_shuffle | sym::simd_insert | sym::simd_extract)) =
|
||||
self.tcx().intrinsic(def_id).map(|i| i.name)
|
||||
{
|
||||
let idx = match name {
|
||||
sym::simd_shuffle => 2,
|
||||
_ => 1,
|
||||
};
|
||||
if !matches!(args[idx], Spanned { node: Operand::Constant(_), .. }) {
|
||||
self.tcx().dcx().emit_err(SimdIntrinsicArgConst {
|
||||
span: term.source_info.span,
|
||||
arg: idx + 1,
|
||||
intrinsic: name.to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1749,8 +1770,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
self.assert_iscleanup(body, block_data, real_target, is_cleanup);
|
||||
self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup);
|
||||
}
|
||||
TerminatorKind::InlineAsm { destination, unwind, .. } => {
|
||||
if let Some(target) = destination {
|
||||
TerminatorKind::InlineAsm { ref targets, unwind, .. } => {
|
||||
for &target in targets {
|
||||
self.assert_iscleanup(body, block_data, target, is_cleanup);
|
||||
}
|
||||
self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup);
|
||||
@ -1875,6 +1896,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
}),
|
||||
}
|
||||
}
|
||||
AggregateKind::CoroutineClosure(_, args) => {
|
||||
match args.as_coroutine_closure().upvar_tys().get(field_index.as_usize()) {
|
||||
Some(ty) => Ok(*ty),
|
||||
None => Err(FieldAccessError::OutOfRange {
|
||||
field_count: args.as_coroutine_closure().upvar_tys().len(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
AggregateKind::Array(ty) => Ok(ty),
|
||||
AggregateKind::Tuple => {
|
||||
unreachable!("This should have been covered in check_rvalues");
|
||||
@ -1971,6 +2000,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
ConstraintCategory::SizedBound,
|
||||
);
|
||||
}
|
||||
&Rvalue::NullaryOp(NullOp::UbCheck(_), _) => {}
|
||||
|
||||
Rvalue::ShallowInitBox(operand, ty) => {
|
||||
self.check_operand(operand, location);
|
||||
@ -2478,6 +2508,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
AggregateKind::Tuple => None,
|
||||
AggregateKind::Closure(_, _) => None,
|
||||
AggregateKind::Coroutine(_, _) => None,
|
||||
AggregateKind::CoroutineClosure(_, _) => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -2705,7 +2736,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
// desugaring. A closure gets desugared to a struct, and
|
||||
// these extra requirements are basically like where
|
||||
// clauses on the struct.
|
||||
AggregateKind::Closure(def_id, args) | AggregateKind::Coroutine(def_id, args) => (
|
||||
AggregateKind::Closure(def_id, args)
|
||||
| AggregateKind::CoroutineClosure(def_id, args)
|
||||
| AggregateKind::Coroutine(def_id, args) => (
|
||||
def_id,
|
||||
self.prove_closure_bounds(
|
||||
tcx,
|
||||
@ -2740,9 +2773,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
self.borrowck_context.universal_regions,
|
||||
self.region_bound_pairs,
|
||||
self.implicit_region_bound,
|
||||
self.param_env,
|
||||
self.known_type_outlives_obligations,
|
||||
locations,
|
||||
DUMMY_SP, // irrelevant; will be overridden.
|
||||
self.body.span, // irrelevant; will be overridden.
|
||||
ConstraintCategory::Boring, // same as above.
|
||||
self.borrowck_context.constraints,
|
||||
)
|
||||
@ -2754,10 +2788,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
let typeck_root_args = ty::GenericArgs::identity_for_item(tcx, typeck_root_def_id);
|
||||
|
||||
let parent_args = match tcx.def_kind(def_id) {
|
||||
DefKind::Closure if tcx.is_coroutine(def_id.to_def_id()) => {
|
||||
args.as_coroutine().parent_args()
|
||||
// We don't want to dispatch on 3 different kind of closures here, so take
|
||||
// advantage of the fact that the `parent_args` is the same length as the
|
||||
// `typeck_root_args`.
|
||||
DefKind::Closure => {
|
||||
// FIXME(async_closures): It may be useful to add a debug assert here
|
||||
// to actually call `type_of` and check the `parent_args` are the same
|
||||
// length as the `typeck_root_args`.
|
||||
&args[..typeck_root_args.len()]
|
||||
}
|
||||
DefKind::Closure => args.as_closure().parent_args(),
|
||||
DefKind::InlineConst => args.as_inline_const().parent_args(),
|
||||
other => bug!("unexpected item {:?}", other),
|
||||
};
|
||||
|
||||
@ -1,11 +1,15 @@
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_infer::infer::nll_relate::{TypeRelating, TypeRelatingDelegate};
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::NllRegionVariableOrigin;
|
||||
use rustc_infer::traits::PredicateObligations;
|
||||
use rustc_infer::infer::{ObligationEmittingRelation, StructurallyRelateAliases};
|
||||
use rustc_infer::traits::{Obligation, PredicateObligations};
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::ty::relate::TypeRelation;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::fold::FnMutDelegate;
|
||||
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
@ -32,12 +36,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
locations: Locations,
|
||||
category: ConstraintCategory<'tcx>,
|
||||
) -> Result<(), NoSolution> {
|
||||
TypeRelating::new(
|
||||
self.infcx,
|
||||
NllTypeRelatingDelegate::new(self, locations, category, UniverseInfo::relate(a, b)),
|
||||
v,
|
||||
)
|
||||
.relate(a, b)?;
|
||||
NllTypeRelating::new(self, locations, category, UniverseInfo::relate(a, b), v)
|
||||
.relate(a, b)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -49,9 +49,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
locations: Locations,
|
||||
category: ConstraintCategory<'tcx>,
|
||||
) -> Result<(), NoSolution> {
|
||||
TypeRelating::new(
|
||||
self.infcx,
|
||||
NllTypeRelatingDelegate::new(self, locations, category, UniverseInfo::other()),
|
||||
NllTypeRelating::new(
|
||||
self,
|
||||
locations,
|
||||
category,
|
||||
UniverseInfo::other(),
|
||||
ty::Variance::Invariant,
|
||||
)
|
||||
.relate(a, b)?;
|
||||
@ -59,7 +61,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
|
||||
pub struct NllTypeRelating<'me, 'bccx, 'tcx> {
|
||||
type_checker: &'me mut TypeChecker<'bccx, 'tcx>,
|
||||
|
||||
/// Where (and why) is this relation taking place?
|
||||
@ -71,26 +73,179 @@ struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
|
||||
/// Information so that error reporting knows what types we are relating
|
||||
/// when reporting a bound region error.
|
||||
universe_info: UniverseInfo<'tcx>,
|
||||
|
||||
/// How are we relating `a` and `b`?
|
||||
///
|
||||
/// - Covariant means `a <: b`.
|
||||
/// - Contravariant means `b <: a`.
|
||||
/// - Invariant means `a == b`.
|
||||
/// - Bivariant means that it doesn't matter.
|
||||
ambient_variance: ty::Variance,
|
||||
|
||||
ambient_variance_info: ty::VarianceDiagInfo<'tcx>,
|
||||
}
|
||||
|
||||
impl<'me, 'bccx, 'tcx> NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
|
||||
fn new(
|
||||
impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> {
|
||||
pub fn new(
|
||||
type_checker: &'me mut TypeChecker<'bccx, 'tcx>,
|
||||
locations: Locations,
|
||||
category: ConstraintCategory<'tcx>,
|
||||
universe_info: UniverseInfo<'tcx>,
|
||||
ambient_variance: ty::Variance,
|
||||
) -> Self {
|
||||
Self { type_checker, locations, category, universe_info }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
|
||||
fn span(&self) -> Span {
|
||||
self.locations.span(self.type_checker.body)
|
||||
Self {
|
||||
type_checker,
|
||||
locations,
|
||||
category,
|
||||
universe_info,
|
||||
ambient_variance,
|
||||
ambient_variance_info: ty::VarianceDiagInfo::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn param_env(&self) -> ty::ParamEnv<'tcx> {
|
||||
self.type_checker.param_env
|
||||
fn ambient_covariance(&self) -> bool {
|
||||
match self.ambient_variance {
|
||||
ty::Variance::Covariant | ty::Variance::Invariant => true,
|
||||
ty::Variance::Contravariant | ty::Variance::Bivariant => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn ambient_contravariance(&self) -> bool {
|
||||
match self.ambient_variance {
|
||||
ty::Variance::Contravariant | ty::Variance::Invariant => true,
|
||||
ty::Variance::Covariant | ty::Variance::Bivariant => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn relate_opaques(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
|
||||
let infcx = self.type_checker.infcx;
|
||||
debug_assert!(!infcx.next_trait_solver());
|
||||
// `handle_opaque_type` cannot handle subtyping, so to support subtyping
|
||||
// we instead eagerly generalize here. This is a bit of a mess but will go
|
||||
// away once we're using the new solver.
|
||||
//
|
||||
// Given `opaque rel B`, we create a new infer var `ty_vid` constrain it
|
||||
// by using `ty_vid rel B` and then finally and end by equating `ty_vid` to
|
||||
// the opaque.
|
||||
let mut enable_subtyping = |ty, opaque_is_expected| {
|
||||
let ty_vid = infcx.next_ty_var_id_in_universe(
|
||||
TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::MiscVariable,
|
||||
span: self.span(),
|
||||
},
|
||||
ty::UniverseIndex::ROOT,
|
||||
);
|
||||
|
||||
let variance = if opaque_is_expected {
|
||||
self.ambient_variance
|
||||
} else {
|
||||
self.ambient_variance.xform(ty::Contravariant)
|
||||
};
|
||||
|
||||
self.type_checker.infcx.instantiate_ty_var(
|
||||
self,
|
||||
opaque_is_expected,
|
||||
ty_vid,
|
||||
variance,
|
||||
ty,
|
||||
)?;
|
||||
Ok(infcx.resolve_vars_if_possible(Ty::new_infer(infcx.tcx, ty::TyVar(ty_vid))))
|
||||
};
|
||||
|
||||
let (a, b) = match (a.kind(), b.kind()) {
|
||||
(&ty::Alias(ty::Opaque, ..), _) => (a, enable_subtyping(b, true)?),
|
||||
(_, &ty::Alias(ty::Opaque, ..)) => (enable_subtyping(a, false)?, b),
|
||||
_ => unreachable!(
|
||||
"expected at least one opaque type in `relate_opaques`, got {a} and {b}."
|
||||
),
|
||||
};
|
||||
let cause = ObligationCause::dummy_with_span(self.span());
|
||||
let obligations = infcx.handle_opaque_type(a, b, &cause, self.param_env())?.obligations;
|
||||
self.register_obligations(obligations);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn enter_forall<T, U>(
|
||||
&mut self,
|
||||
binder: ty::Binder<'tcx, T>,
|
||||
f: impl FnOnce(&mut Self, T) -> U,
|
||||
) -> U
|
||||
where
|
||||
T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy,
|
||||
{
|
||||
let value = if let Some(inner) = binder.no_bound_vars() {
|
||||
inner
|
||||
} else {
|
||||
let infcx = self.type_checker.infcx;
|
||||
let mut lazy_universe = None;
|
||||
let delegate = FnMutDelegate {
|
||||
regions: &mut |br: ty::BoundRegion| {
|
||||
// The first time this closure is called, create a
|
||||
// new universe for the placeholders we will make
|
||||
// from here out.
|
||||
let universe = lazy_universe.unwrap_or_else(|| {
|
||||
let universe = self.create_next_universe();
|
||||
lazy_universe = Some(universe);
|
||||
universe
|
||||
});
|
||||
|
||||
let placeholder = ty::PlaceholderRegion { universe, bound: br };
|
||||
debug!(?placeholder);
|
||||
let placeholder_reg = self.next_placeholder_region(placeholder);
|
||||
debug!(?placeholder_reg);
|
||||
|
||||
placeholder_reg
|
||||
},
|
||||
types: &mut |_bound_ty: ty::BoundTy| {
|
||||
unreachable!("we only replace regions in nll_relate, not types")
|
||||
},
|
||||
consts: &mut |_bound_var: ty::BoundVar, _ty| {
|
||||
unreachable!("we only replace regions in nll_relate, not consts")
|
||||
},
|
||||
};
|
||||
|
||||
infcx.tcx.replace_bound_vars_uncached(binder, delegate)
|
||||
};
|
||||
|
||||
debug!(?value);
|
||||
f(self, value)
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn instantiate_binder_with_existentials<T>(&mut self, binder: ty::Binder<'tcx, T>) -> T
|
||||
where
|
||||
T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy,
|
||||
{
|
||||
if let Some(inner) = binder.no_bound_vars() {
|
||||
return inner;
|
||||
}
|
||||
|
||||
let infcx = self.type_checker.infcx;
|
||||
let mut reg_map = FxHashMap::default();
|
||||
let delegate = FnMutDelegate {
|
||||
regions: &mut |br: ty::BoundRegion| {
|
||||
if let Some(ex_reg_var) = reg_map.get(&br) {
|
||||
return *ex_reg_var;
|
||||
} else {
|
||||
let ex_reg_var = self.next_existential_region_var(true, br.kind.get_name());
|
||||
debug!(?ex_reg_var);
|
||||
reg_map.insert(br, ex_reg_var);
|
||||
|
||||
ex_reg_var
|
||||
}
|
||||
},
|
||||
types: &mut |_bound_ty: ty::BoundTy| {
|
||||
unreachable!("we only replace regions in nll_relate, not types")
|
||||
},
|
||||
consts: &mut |_bound_var: ty::BoundVar, _ty| {
|
||||
unreachable!("we only replace regions in nll_relate, not consts")
|
||||
},
|
||||
};
|
||||
|
||||
let replaced = infcx.tcx.replace_bound_vars_uncached(binder, delegate);
|
||||
debug!(?replaced);
|
||||
|
||||
replaced
|
||||
}
|
||||
|
||||
fn create_next_universe(&mut self) -> ty::UniverseIndex {
|
||||
@ -143,22 +298,6 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
|
||||
reg
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
|
||||
let reg = self.type_checker.infcx.next_nll_region_var_in_universe(
|
||||
NllRegionVariableOrigin::Existential { from_forall: false },
|
||||
universe,
|
||||
);
|
||||
|
||||
if cfg!(debug_assertions) {
|
||||
let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut();
|
||||
let prev = var_to_origin.insert(reg.as_var(), RegionCtxt::Existential(None));
|
||||
assert_eq!(prev, None);
|
||||
}
|
||||
|
||||
reg
|
||||
}
|
||||
|
||||
fn push_outlives(
|
||||
&mut self,
|
||||
sup: ty::Region<'tcx>,
|
||||
@ -179,9 +318,249 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn forbid_inference_vars() -> bool {
|
||||
true
|
||||
impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.type_checker.infcx.tcx
|
||||
}
|
||||
|
||||
fn tag(&self) -> &'static str {
|
||||
"nll::subtype"
|
||||
}
|
||||
|
||||
#[instrument(skip(self, info), level = "trace", ret)]
|
||||
fn relate_with_variance<T: Relate<'tcx>>(
|
||||
&mut self,
|
||||
variance: ty::Variance,
|
||||
info: ty::VarianceDiagInfo<'tcx>,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> RelateResult<'tcx, T> {
|
||||
let old_ambient_variance = self.ambient_variance;
|
||||
self.ambient_variance = self.ambient_variance.xform(variance);
|
||||
self.ambient_variance_info = self.ambient_variance_info.xform(info);
|
||||
|
||||
debug!(?self.ambient_variance);
|
||||
// In a bivariant context this always succeeds.
|
||||
let r = if self.ambient_variance == ty::Variance::Bivariant {
|
||||
Ok(a)
|
||||
} else {
|
||||
self.relate(a, b)
|
||||
};
|
||||
|
||||
self.ambient_variance = old_ambient_variance;
|
||||
|
||||
r
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||
let infcx = self.type_checker.infcx;
|
||||
|
||||
let a = self.type_checker.infcx.shallow_resolve(a);
|
||||
assert!(!b.has_non_region_infer(), "unexpected inference var {:?}", b);
|
||||
|
||||
if a == b {
|
||||
return Ok(a);
|
||||
}
|
||||
|
||||
match (a.kind(), b.kind()) {
|
||||
(_, &ty::Infer(ty::TyVar(_))) => {
|
||||
span_bug!(
|
||||
self.span(),
|
||||
"should not be relating type variables on the right in MIR typeck"
|
||||
);
|
||||
}
|
||||
|
||||
(&ty::Infer(ty::TyVar(a_vid)), _) => {
|
||||
infcx.instantiate_ty_var(self, true, a_vid, self.ambient_variance, b)?
|
||||
}
|
||||
|
||||
(
|
||||
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
|
||||
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
|
||||
) if a_def_id == b_def_id || infcx.next_trait_solver() => {
|
||||
infcx.super_combine_tys(self, a, b).map(|_| ()).or_else(|err| {
|
||||
// This behavior is only there for the old solver, the new solver
|
||||
// shouldn't ever fail. Instead, it unconditionally emits an
|
||||
// alias-relate goal.
|
||||
assert!(!self.type_checker.infcx.next_trait_solver());
|
||||
self.tcx().dcx().span_delayed_bug(
|
||||
self.span(),
|
||||
"failure to relate an opaque to itself should result in an error later on",
|
||||
);
|
||||
if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) }
|
||||
})?;
|
||||
}
|
||||
(&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
|
||||
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
|
||||
if def_id.is_local() && !self.type_checker.infcx.next_trait_solver() =>
|
||||
{
|
||||
self.relate_opaques(a, b)?;
|
||||
}
|
||||
|
||||
_ => {
|
||||
debug!(?a, ?b, ?self.ambient_variance);
|
||||
|
||||
// Will also handle unification of `IntVar` and `FloatVar`.
|
||||
self.type_checker.infcx.super_combine_tys(self, a, b)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "trace")]
|
||||
fn regions(
|
||||
&mut self,
|
||||
a: ty::Region<'tcx>,
|
||||
b: ty::Region<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::Region<'tcx>> {
|
||||
debug!(?self.ambient_variance);
|
||||
|
||||
if self.ambient_covariance() {
|
||||
// Covariant: &'a u8 <: &'b u8. Hence, `'a: 'b`.
|
||||
self.push_outlives(a, b, self.ambient_variance_info);
|
||||
}
|
||||
|
||||
if self.ambient_contravariance() {
|
||||
// Contravariant: &'b u8 <: &'a u8. Hence, `'b: 'a`.
|
||||
self.push_outlives(b, a, self.ambient_variance_info);
|
||||
}
|
||||
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
fn consts(
|
||||
&mut self,
|
||||
a: ty::Const<'tcx>,
|
||||
b: ty::Const<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::Const<'tcx>> {
|
||||
let a = self.type_checker.infcx.shallow_resolve(a);
|
||||
assert!(!a.has_non_region_infer(), "unexpected inference var {:?}", a);
|
||||
assert!(!b.has_non_region_infer(), "unexpected inference var {:?}", b);
|
||||
|
||||
self.type_checker.infcx.super_combine_consts(self, a, b)
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "trace")]
|
||||
fn binders<T>(
|
||||
&mut self,
|
||||
a: ty::Binder<'tcx, T>,
|
||||
b: ty::Binder<'tcx, T>,
|
||||
) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
|
||||
where
|
||||
T: Relate<'tcx>,
|
||||
{
|
||||
// We want that
|
||||
//
|
||||
// ```
|
||||
// for<'a> fn(&'a u32) -> &'a u32 <:
|
||||
// fn(&'b u32) -> &'b u32
|
||||
// ```
|
||||
//
|
||||
// but not
|
||||
//
|
||||
// ```
|
||||
// fn(&'a u32) -> &'a u32 <:
|
||||
// for<'b> fn(&'b u32) -> &'b u32
|
||||
// ```
|
||||
//
|
||||
// We therefore proceed as follows:
|
||||
//
|
||||
// - Instantiate binders on `b` universally, yielding a universe U1.
|
||||
// - Instantiate binders on `a` existentially in U1.
|
||||
|
||||
debug!(?self.ambient_variance);
|
||||
|
||||
if let (Some(a), Some(b)) = (a.no_bound_vars(), b.no_bound_vars()) {
|
||||
// Fast path for the common case.
|
||||
self.relate(a, b)?;
|
||||
return Ok(ty::Binder::dummy(a));
|
||||
}
|
||||
|
||||
match self.ambient_variance {
|
||||
ty::Variance::Covariant => {
|
||||
// Covariance, so we want `for<..> A <: for<..> B` --
|
||||
// therefore we compare any instantiation of A (i.e., A
|
||||
// instantiated with existentials) against every
|
||||
// instantiation of B (i.e., B instantiated with
|
||||
// universals).
|
||||
|
||||
// Note: the order here is important. Create the placeholders first, otherwise
|
||||
// we assign the wrong universe to the existential!
|
||||
self.enter_forall(b, |this, b| {
|
||||
let a = this.instantiate_binder_with_existentials(a);
|
||||
this.relate(a, b)
|
||||
})?;
|
||||
}
|
||||
|
||||
ty::Variance::Contravariant => {
|
||||
// Contravariance, so we want `for<..> A :> for<..> B` --
|
||||
// therefore we compare every instantiation of A (i.e., A
|
||||
// instantiated with universals) against any
|
||||
// instantiation of B (i.e., B instantiated with
|
||||
// existentials). Opposite of above.
|
||||
|
||||
// Note: the order here is important. Create the placeholders first, otherwise
|
||||
// we assign the wrong universe to the existential!
|
||||
self.enter_forall(a, |this, a| {
|
||||
let b = this.instantiate_binder_with_existentials(b);
|
||||
this.relate(a, b)
|
||||
})?;
|
||||
}
|
||||
|
||||
ty::Variance::Invariant => {
|
||||
// Invariant, so we want `for<..> A == for<..> B` --
|
||||
// therefore we want `exists<..> A == for<..> B` and
|
||||
// `exists<..> B == for<..> A`.
|
||||
//
|
||||
// See the comment in `fn Equate::binders` for more details.
|
||||
|
||||
// Note: the order here is important. Create the placeholders first, otherwise
|
||||
// we assign the wrong universe to the existential!
|
||||
self.enter_forall(b, |this, b| {
|
||||
let a = this.instantiate_binder_with_existentials(a);
|
||||
this.relate(a, b)
|
||||
})?;
|
||||
// Note: the order here is important. Create the placeholders first, otherwise
|
||||
// we assign the wrong universe to the existential!
|
||||
self.enter_forall(a, |this, a| {
|
||||
let b = this.instantiate_binder_with_existentials(b);
|
||||
this.relate(a, b)
|
||||
})?;
|
||||
}
|
||||
|
||||
ty::Variance::Bivariant => {}
|
||||
}
|
||||
|
||||
Ok(a)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'bccx, 'tcx> ObligationEmittingRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
|
||||
fn span(&self) -> Span {
|
||||
self.locations.span(self.type_checker.body)
|
||||
}
|
||||
|
||||
fn structurally_relate_aliases(&self) -> StructurallyRelateAliases {
|
||||
StructurallyRelateAliases::No
|
||||
}
|
||||
|
||||
fn param_env(&self) -> ty::ParamEnv<'tcx> {
|
||||
self.type_checker.param_env
|
||||
}
|
||||
|
||||
fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>) {
|
||||
self.register_obligations(
|
||||
obligations
|
||||
.into_iter()
|
||||
.map(|to_pred| {
|
||||
Obligation::new(self.tcx(), ObligationCause::dummy(), self.param_env(), to_pred)
|
||||
})
|
||||
.collect(),
|
||||
);
|
||||
}
|
||||
|
||||
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
|
||||
@ -196,4 +575,28 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
|
||||
self.register_predicates([ty::Binder::dummy(match self.ambient_variance {
|
||||
ty::Variance::Covariant => ty::PredicateKind::AliasRelate(
|
||||
a.into(),
|
||||
b.into(),
|
||||
ty::AliasRelationDirection::Subtype,
|
||||
),
|
||||
// a :> b is b <: a
|
||||
ty::Variance::Contravariant => ty::PredicateKind::AliasRelate(
|
||||
b.into(),
|
||||
a.into(),
|
||||
ty::AliasRelationDirection::Subtype,
|
||||
),
|
||||
ty::Variance::Invariant => ty::PredicateKind::AliasRelate(
|
||||
a.into(),
|
||||
b.into(),
|
||||
ty::AliasRelationDirection::Equate,
|
||||
),
|
||||
ty::Variance::Bivariant => {
|
||||
unreachable!("cannot defer an alias-relate goal with Bivariant variance (yet?)")
|
||||
}
|
||||
})]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,13 +12,17 @@
|
||||
//! The code in this file doesn't *do anything* with those results; it
|
||||
//! just returns them for other code to use.
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::Diagnostic;
|
||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_errors::Diag;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::BodyOwnerKind;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_infer::infer::NllRegionVariableOrigin;
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::{self, InlineConstArgs, InlineConstArgsParts, RegionVid, Ty, TyCtxt};
|
||||
@ -97,6 +101,13 @@ pub enum DefiningTy<'tcx> {
|
||||
/// `ClosureArgs::coroutine_return_ty`.
|
||||
Coroutine(DefId, GenericArgsRef<'tcx>),
|
||||
|
||||
/// The MIR is a special kind of closure that returns coroutines.
|
||||
///
|
||||
/// See the documentation on `CoroutineClosureSignature` for details
|
||||
/// on how to construct the callable signature of the coroutine from
|
||||
/// its args.
|
||||
CoroutineClosure(DefId, GenericArgsRef<'tcx>),
|
||||
|
||||
/// The MIR is a fn item with the given `DefId` and args. The signature
|
||||
/// of the function can be bound then with the `fn_sig` query.
|
||||
FnDef(DefId, GenericArgsRef<'tcx>),
|
||||
@ -119,6 +130,7 @@ impl<'tcx> DefiningTy<'tcx> {
|
||||
pub fn upvar_tys(self) -> &'tcx ty::List<Ty<'tcx>> {
|
||||
match self {
|
||||
DefiningTy::Closure(_, args) => args.as_closure().upvar_tys(),
|
||||
DefiningTy::CoroutineClosure(_, args) => args.as_coroutine_closure().upvar_tys(),
|
||||
DefiningTy::Coroutine(_, args) => args.as_coroutine().upvar_tys(),
|
||||
DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => {
|
||||
ty::List::empty()
|
||||
@ -131,7 +143,9 @@ impl<'tcx> DefiningTy<'tcx> {
|
||||
/// user's code.
|
||||
pub fn implicit_inputs(self) -> usize {
|
||||
match self {
|
||||
DefiningTy::Closure(..) | DefiningTy::Coroutine(..) => 1,
|
||||
DefiningTy::Closure(..)
|
||||
| DefiningTy::CoroutineClosure(..)
|
||||
| DefiningTy::Coroutine(..) => 1,
|
||||
DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => 0,
|
||||
}
|
||||
}
|
||||
@ -147,6 +161,7 @@ impl<'tcx> DefiningTy<'tcx> {
|
||||
pub fn def_id(&self) -> DefId {
|
||||
match *self {
|
||||
DefiningTy::Closure(def_id, ..)
|
||||
| DefiningTy::CoroutineClosure(def_id, ..)
|
||||
| DefiningTy::Coroutine(def_id, ..)
|
||||
| DefiningTy::FnDef(def_id, ..)
|
||||
| DefiningTy::Const(def_id, ..)
|
||||
@ -166,7 +181,7 @@ struct UniversalRegionIndices<'tcx> {
|
||||
/// basically equivalent to an `GenericArgs`, except that it also
|
||||
/// contains an entry for `ReStatic` -- it might be nice to just
|
||||
/// use an args, and then handle `ReStatic` another way.
|
||||
indices: FxHashMap<ty::Region<'tcx>, RegionVid>,
|
||||
indices: FxIndexMap<ty::Region<'tcx>, RegionVid>,
|
||||
|
||||
/// The vid assigned to `'static`. Used only for diagnostics.
|
||||
pub fr_static: RegionVid,
|
||||
@ -311,9 +326,6 @@ impl<'tcx> UniversalRegions<'tcx> {
|
||||
}
|
||||
|
||||
/// Gets an iterator over all the early-bound regions that have names.
|
||||
/// Iteration order may be unstable, so this should only be used when
|
||||
/// iteration order doesn't affect anything
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
pub fn named_universal_regions<'s>(
|
||||
&'s self,
|
||||
) -> impl Iterator<Item = (ty::Region<'tcx>, ty::RegionVid)> + 's {
|
||||
@ -331,7 +343,7 @@ impl<'tcx> UniversalRegions<'tcx> {
|
||||
/// that this region imposes on others. The methods in this file
|
||||
/// handle the part about dumping the inference context internal
|
||||
/// state.
|
||||
pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diagnostic) {
|
||||
pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diag<'_, ()>) {
|
||||
match self.defining_ty {
|
||||
DefiningTy::Closure(def_id, args) => {
|
||||
let v = with_no_trimmed_paths!(
|
||||
@ -355,6 +367,9 @@ impl<'tcx> UniversalRegions<'tcx> {
|
||||
err.note(format!("late-bound region is {:?}", self.to_region_vid(r)));
|
||||
});
|
||||
}
|
||||
DefiningTy::CoroutineClosure(..) => {
|
||||
todo!()
|
||||
}
|
||||
DefiningTy::Coroutine(def_id, args) => {
|
||||
let v = with_no_trimmed_paths!(
|
||||
args[tcx.generics_of(def_id).parent_count..]
|
||||
@ -568,6 +583,9 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
match *defining_ty.kind() {
|
||||
ty::Closure(def_id, args) => DefiningTy::Closure(def_id, args),
|
||||
ty::Coroutine(def_id, args) => DefiningTy::Coroutine(def_id, args),
|
||||
ty::CoroutineClosure(def_id, args) => {
|
||||
DefiningTy::CoroutineClosure(def_id, args)
|
||||
}
|
||||
ty::FnDef(def_id, args) => DefiningTy::FnDef(def_id, args),
|
||||
_ => span_bug!(
|
||||
tcx.def_span(self.mir_def),
|
||||
@ -623,6 +641,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
let identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id);
|
||||
let fr_args = match defining_ty {
|
||||
DefiningTy::Closure(_, args)
|
||||
| DefiningTy::CoroutineClosure(_, args)
|
||||
| DefiningTy::Coroutine(_, args)
|
||||
| DefiningTy::InlineConst(_, args) => {
|
||||
// In the case of closures, we rely on the fact that
|
||||
@ -702,6 +721,55 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
ty::Binder::dummy(inputs_and_output)
|
||||
}
|
||||
|
||||
// Construct the signature of the CoroutineClosure for the purposes of borrowck.
|
||||
// This is pretty straightforward -- we:
|
||||
// 1. first grab the `coroutine_closure_sig`,
|
||||
// 2. compute the self type (`&`/`&mut`/no borrow),
|
||||
// 3. flatten the tupled_input_tys,
|
||||
// 4. construct the correct generator type to return with
|
||||
// `CoroutineClosureSignature::to_coroutine_given_kind_and_upvars`.
|
||||
// Then we wrap it all up into a list of inputs and output.
|
||||
DefiningTy::CoroutineClosure(def_id, args) => {
|
||||
assert_eq!(self.mir_def.to_def_id(), def_id);
|
||||
let closure_sig = args.as_coroutine_closure().coroutine_closure_sig();
|
||||
let bound_vars = tcx.mk_bound_variable_kinds_from_iter(
|
||||
closure_sig
|
||||
.bound_vars()
|
||||
.iter()
|
||||
.chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))),
|
||||
);
|
||||
let br = ty::BoundRegion {
|
||||
var: ty::BoundVar::from_usize(bound_vars.len() - 1),
|
||||
kind: ty::BrEnv,
|
||||
};
|
||||
let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br);
|
||||
let closure_kind = args.as_coroutine_closure().kind();
|
||||
|
||||
let closure_ty = tcx.closure_env_ty(
|
||||
Ty::new_coroutine_closure(tcx, def_id, args),
|
||||
closure_kind,
|
||||
env_region,
|
||||
);
|
||||
|
||||
let inputs = closure_sig.skip_binder().tupled_inputs_ty.tuple_fields();
|
||||
let output = closure_sig.skip_binder().to_coroutine_given_kind_and_upvars(
|
||||
tcx,
|
||||
args.as_coroutine_closure().parent_args(),
|
||||
tcx.coroutine_for_closure(def_id),
|
||||
closure_kind,
|
||||
env_region,
|
||||
args.as_coroutine_closure().tupled_upvars_ty(),
|
||||
args.as_coroutine_closure().coroutine_captures_by_ref_ty(),
|
||||
);
|
||||
|
||||
ty::Binder::bind_with_vars(
|
||||
tcx.mk_type_list_from_iter(
|
||||
iter::once(closure_ty).chain(inputs).chain(iter::once(output)),
|
||||
),
|
||||
bound_vars,
|
||||
)
|
||||
}
|
||||
|
||||
DefiningTy::FnDef(def_id, _) => {
|
||||
let sig = tcx.fn_sig(def_id).instantiate_identity();
|
||||
let sig = indices.fold_to_region_vids(tcx, sig);
|
||||
@ -726,27 +794,8 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
trait InferCtxtExt<'tcx> {
|
||||
fn replace_free_regions_with_nll_infer_vars<T>(
|
||||
&self,
|
||||
origin: NllRegionVariableOrigin,
|
||||
value: T,
|
||||
) -> T
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>;
|
||||
|
||||
fn replace_bound_regions_with_nll_infer_vars<T>(
|
||||
&self,
|
||||
origin: NllRegionVariableOrigin,
|
||||
all_outlive_scope: LocalDefId,
|
||||
value: ty::Binder<'tcx, T>,
|
||||
indices: &mut UniversalRegionIndices<'tcx>,
|
||||
) -> T
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>;
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> {
|
||||
#[extension(trait InferCtxtExt<'tcx>)]
|
||||
impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> {
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn replace_free_regions_with_nll_infer_vars<T>(
|
||||
&self,
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_middle::mir::visit::{PlaceContext, Visitor};
|
||||
use rustc_middle::mir::{
|
||||
@ -60,7 +58,8 @@ impl GatherUsedMutsVisitor<'_, '_, '_> {
|
||||
// be those that were never initialized - we will consider those as being used as
|
||||
// they will either have been removed by unreachable code optimizations; or linted
|
||||
// as unused variables.
|
||||
self.never_initialized_mut_locals.remove(&into.local);
|
||||
// FIXME(#120456) - is `swap_remove` correct?
|
||||
self.never_initialized_mut_locals.swap_remove(&into.local);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -19,6 +19,8 @@ builtin_macros_asm_expected_other = expected operand, {$is_global_asm ->
|
||||
|
||||
builtin_macros_asm_explicit_register_name = explicit register arguments cannot have names
|
||||
|
||||
builtin_macros_asm_mayunwind = asm labels are not allowed with the `may_unwind` option
|
||||
|
||||
builtin_macros_asm_modifier_invalid = asm template modifier must be a single character
|
||||
|
||||
builtin_macros_asm_mutually_exclusive = the `{$opt1}` and `{$opt2}` options are mutually exclusive
|
||||
@ -221,12 +223,6 @@ builtin_macros_requires_cfg_pattern =
|
||||
macro requires a cfg-pattern as an argument
|
||||
.label = cfg-pattern required
|
||||
|
||||
builtin_macros_should_panic = functions using `#[should_panic]` must return `()`
|
||||
|
||||
builtin_macros_test_arg_non_lifetime = functions used as tests can not have any non-lifetime generic parameters
|
||||
|
||||
builtin_macros_test_args = functions used as tests can not have any arguments
|
||||
|
||||
builtin_macros_test_bad_fn = {$kind} functions cannot be used for tests
|
||||
.label = `{$kind}` because of this
|
||||
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
use ast::token::IdentIsRaw;
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, Delimiter};
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||
use rustc_errors::PResult;
|
||||
use rustc_expand::base::{self, *};
|
||||
use rustc_expand::base::*;
|
||||
use rustc_index::bit_set::GrowableBitSet;
|
||||
use rustc_parse::parser::Parser;
|
||||
use rustc_parse_format as parse;
|
||||
use rustc_session::lint;
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::symbol::{kw, sym, Symbol};
|
||||
use rustc_span::{InnerSpan, Span};
|
||||
use rustc_span::{ErrorGuaranteed, InnerSpan, Span};
|
||||
use rustc_target::asm::InlineAsmArch;
|
||||
use smallvec::smallvec;
|
||||
|
||||
@ -35,19 +35,17 @@ fn parse_args<'a>(
|
||||
is_global_asm: bool,
|
||||
) -> PResult<'a, AsmArgs> {
|
||||
let mut p = ecx.new_parser_from_tts(tts);
|
||||
let sess = &ecx.sess.parse_sess;
|
||||
parse_asm_args(&mut p, sess, sp, is_global_asm)
|
||||
parse_asm_args(&mut p, sp, is_global_asm)
|
||||
}
|
||||
|
||||
// Primarily public for rustfmt consumption.
|
||||
// Internal consumers should continue to leverage `expand_asm`/`expand__global_asm`
|
||||
pub fn parse_asm_args<'a>(
|
||||
p: &mut Parser<'a>,
|
||||
sess: &'a ParseSess,
|
||||
sp: Span,
|
||||
is_global_asm: bool,
|
||||
) -> PResult<'a, AsmArgs> {
|
||||
let dcx = &sess.dcx;
|
||||
let dcx = &p.psess.dcx;
|
||||
|
||||
if p.token == token::Eof {
|
||||
return Err(dcx.create_err(errors::AsmRequiresTemplate { span: sp }));
|
||||
@ -166,6 +164,9 @@ pub fn parse_asm_args<'a>(
|
||||
path: path.clone(),
|
||||
};
|
||||
ast::InlineAsmOperand::Sym { sym }
|
||||
} else if !is_global_asm && p.eat_keyword(sym::label) {
|
||||
let block = p.parse_block()?;
|
||||
ast::InlineAsmOperand::Label { block }
|
||||
} else if allow_templates {
|
||||
let template = p.parse_expr()?;
|
||||
// If it can't possibly expand to a string, provide diagnostics here to include other
|
||||
@ -242,6 +243,7 @@ pub fn parse_asm_args<'a>(
|
||||
let mut have_real_output = false;
|
||||
let mut outputs_sp = vec![];
|
||||
let mut regclass_outputs = vec![];
|
||||
let mut labels_sp = vec![];
|
||||
for (op, op_sp) in &args.operands {
|
||||
match op {
|
||||
ast::InlineAsmOperand::Out { reg, expr, .. }
|
||||
@ -259,6 +261,9 @@ pub fn parse_asm_args<'a>(
|
||||
regclass_outputs.push(*op_sp);
|
||||
}
|
||||
}
|
||||
ast::InlineAsmOperand::Label { .. } => {
|
||||
labels_sp.push(*op_sp);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@ -270,6 +275,9 @@ pub fn parse_asm_args<'a>(
|
||||
// Bail out now since this is likely to confuse MIR
|
||||
return Err(err);
|
||||
}
|
||||
if args.options.contains(ast::InlineAsmOptions::MAY_UNWIND) && !labels_sp.is_empty() {
|
||||
dcx.emit_err(errors::AsmMayUnwind { labels_sp });
|
||||
}
|
||||
|
||||
if args.clobber_abis.len() > 0 {
|
||||
if is_global_asm {
|
||||
@ -298,7 +306,7 @@ pub fn parse_asm_args<'a>(
|
||||
fn err_duplicate_option(p: &mut Parser<'_>, symbol: Symbol, span: Span) {
|
||||
// Tool-only output
|
||||
let full_span = if p.token.kind == token::Comma { span.to(p.token.span) } else { span };
|
||||
p.sess.dcx.emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span });
|
||||
p.psess.dcx.emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span });
|
||||
}
|
||||
|
||||
/// Try to set the provided option in the provided `AsmArgs`.
|
||||
@ -370,7 +378,7 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a,
|
||||
p.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
|
||||
|
||||
if p.eat(&token::CloseDelim(Delimiter::Parenthesis)) {
|
||||
return Err(p.sess.dcx.create_err(errors::NonABI { span: p.token.span }));
|
||||
return Err(p.psess.dcx.create_err(errors::NonABI { span: p.token.span }));
|
||||
}
|
||||
|
||||
let mut new_abis = Vec::new();
|
||||
@ -381,7 +389,7 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a,
|
||||
}
|
||||
Err(opt_lit) => {
|
||||
let span = opt_lit.map_or(p.token.span, |lit| lit.span);
|
||||
let mut err = p.sess.dcx.struct_span_err(span, "expected string literal");
|
||||
let mut err = p.psess.dcx.struct_span_err(span, "expected string literal");
|
||||
err.span_label(span, "not a string literal");
|
||||
return Err(err);
|
||||
}
|
||||
@ -416,7 +424,7 @@ fn parse_reg<'a>(
|
||||
) -> PResult<'a, ast::InlineAsmRegOrRegClass> {
|
||||
p.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
|
||||
let result = match p.token.uninterpolate().kind {
|
||||
token::Ident(name, false) => ast::InlineAsmRegOrRegClass::RegClass(name),
|
||||
token::Ident(name, IdentIsRaw::No) => ast::InlineAsmRegOrRegClass::RegClass(name),
|
||||
token::Literal(token::Lit { kind: token::LitKind::Str, symbol, suffix: _ }) => {
|
||||
*explicit_reg = true;
|
||||
ast::InlineAsmRegOrRegClass::Reg(symbol)
|
||||
@ -432,7 +440,10 @@ fn parse_reg<'a>(
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::InlineAsm> {
|
||||
fn expand_preparsed_asm(
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
args: AsmArgs,
|
||||
) -> ExpandResult<Result<ast::InlineAsm, ErrorGuaranteed>, ()> {
|
||||
let mut template = vec![];
|
||||
// Register operands are implicitly used since they are not allowed to be
|
||||
// referenced in the template string.
|
||||
@ -454,16 +465,20 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
|
||||
|
||||
let msg = "asm template must be a string literal";
|
||||
let template_sp = template_expr.span;
|
||||
let (template_str, template_style, template_span) =
|
||||
match expr_to_spanned_string(ecx, template_expr, msg) {
|
||||
let (template_str, template_style, template_span) = {
|
||||
let ExpandResult::Ready(mac) = expr_to_spanned_string(ecx, template_expr, msg) else {
|
||||
return ExpandResult::Retry(());
|
||||
};
|
||||
match mac {
|
||||
Ok(template_part) => template_part,
|
||||
Err(err) => {
|
||||
if let Some((err, _)) = err {
|
||||
err.emit();
|
||||
}
|
||||
return None;
|
||||
return ExpandResult::Ready(Err(match err {
|
||||
Ok((err, _)) => err.emit(),
|
||||
Err(guar) => guar,
|
||||
}));
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
let str_style = match template_style {
|
||||
ast::StrStyle::Cooked => None,
|
||||
@ -494,7 +509,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
|
||||
};
|
||||
|
||||
if template_str.contains(".intel_syntax") {
|
||||
ecx.parse_sess().buffer_lint(
|
||||
ecx.psess().buffer_lint(
|
||||
lint::builtin::BAD_ASM_STYLE,
|
||||
find_span(".intel_syntax"),
|
||||
ecx.current_expansion.lint_node_id,
|
||||
@ -502,7 +517,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
|
||||
);
|
||||
}
|
||||
if template_str.contains(".att_syntax") {
|
||||
ecx.parse_sess().buffer_lint(
|
||||
ecx.psess().buffer_lint(
|
||||
lint::builtin::BAD_ASM_STYLE,
|
||||
find_span(".att_syntax"),
|
||||
ecx.current_expansion.lint_node_id,
|
||||
@ -550,8 +565,8 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
|
||||
let err_sp = template_span.from_inner(InnerSpan::new(span.start, span.end));
|
||||
e.span_label(err_sp, label);
|
||||
}
|
||||
e.emit();
|
||||
return None;
|
||||
let guar = e.emit();
|
||||
return ExpandResult::Ready(Err(guar));
|
||||
}
|
||||
|
||||
curarg = parser.curarg;
|
||||
@ -718,52 +733,57 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
|
||||
}
|
||||
}
|
||||
|
||||
Some(ast::InlineAsm {
|
||||
ExpandResult::Ready(Ok(ast::InlineAsm {
|
||||
template,
|
||||
template_strs: template_strs.into_boxed_slice(),
|
||||
operands: args.operands,
|
||||
clobber_abis: args.clobber_abis,
|
||||
options: args.options,
|
||||
line_spans,
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
pub(super) fn expand_asm<'cx>(
|
||||
ecx: &'cx mut ExtCtxt<'_>,
|
||||
sp: Span,
|
||||
tts: TokenStream,
|
||||
) -> Box<dyn base::MacResult + 'cx> {
|
||||
match parse_args(ecx, sp, tts, false) {
|
||||
) -> MacroExpanderResult<'cx> {
|
||||
ExpandResult::Ready(match parse_args(ecx, sp, tts, false) {
|
||||
Ok(args) => {
|
||||
let expr = if let Some(inline_asm) = expand_preparsed_asm(ecx, args) {
|
||||
P(ast::Expr {
|
||||
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, args) else {
|
||||
return ExpandResult::Retry(());
|
||||
};
|
||||
let expr = match mac {
|
||||
Ok(inline_asm) => P(ast::Expr {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
kind: ast::ExprKind::InlineAsm(P(inline_asm)),
|
||||
span: sp,
|
||||
attrs: ast::AttrVec::new(),
|
||||
tokens: None,
|
||||
})
|
||||
} else {
|
||||
DummyResult::raw_expr(sp, true)
|
||||
}),
|
||||
Err(guar) => DummyResult::raw_expr(sp, Some(guar)),
|
||||
};
|
||||
MacEager::expr(expr)
|
||||
}
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
DummyResult::any(sp)
|
||||
let guar = err.emit();
|
||||
DummyResult::any(sp, guar)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn expand_global_asm<'cx>(
|
||||
ecx: &'cx mut ExtCtxt<'_>,
|
||||
sp: Span,
|
||||
tts: TokenStream,
|
||||
) -> Box<dyn base::MacResult + 'cx> {
|
||||
match parse_args(ecx, sp, tts, true) {
|
||||
) -> MacroExpanderResult<'cx> {
|
||||
ExpandResult::Ready(match parse_args(ecx, sp, tts, true) {
|
||||
Ok(args) => {
|
||||
if let Some(inline_asm) = expand_preparsed_asm(ecx, args) {
|
||||
MacEager::items(smallvec![P(ast::Item {
|
||||
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, args) else {
|
||||
return ExpandResult::Retry(());
|
||||
};
|
||||
match mac {
|
||||
Ok(inline_asm) => MacEager::items(smallvec![P(ast::Item {
|
||||
ident: Ident::empty(),
|
||||
attrs: ast::AttrVec::new(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
@ -773,16 +793,15 @@ pub(super) fn expand_global_asm<'cx>(
|
||||
kind: ast::VisibilityKind::Inherited,
|
||||
tokens: None,
|
||||
},
|
||||
span: ecx.with_def_site_ctxt(sp),
|
||||
span: sp,
|
||||
tokens: None,
|
||||
})])
|
||||
} else {
|
||||
DummyResult::any(sp)
|
||||
})]),
|
||||
Err(guar) => DummyResult::any(sp, guar),
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
DummyResult::any(sp)
|
||||
let guar = err.emit();
|
||||
DummyResult::any(sp, guar)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ use rustc_ast::tokenstream::{DelimSpan, TokenStream};
|
||||
use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, Path, PathSegment, UnOp};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::PResult;
|
||||
use rustc_expand::base::{DummyResult, ExtCtxt, MacEager, MacResult};
|
||||
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
|
||||
use rustc_parse::parser::Parser;
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
@ -19,12 +19,12 @@ pub fn expand_assert<'cx>(
|
||||
cx: &'cx mut ExtCtxt<'_>,
|
||||
span: Span,
|
||||
tts: TokenStream,
|
||||
) -> Box<dyn MacResult + 'cx> {
|
||||
) -> MacroExpanderResult<'cx> {
|
||||
let Assert { cond_expr, custom_message } = match parse_assert(cx, span, tts) {
|
||||
Ok(assert) => assert,
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
return DummyResult::any(span);
|
||||
let guar = err.emit();
|
||||
return ExpandResult::Ready(DummyResult::any(span, guar));
|
||||
}
|
||||
};
|
||||
|
||||
@ -92,7 +92,7 @@ pub fn expand_assert<'cx>(
|
||||
expr_if_not(cx, call_site_span, cond_expr, then, None)
|
||||
};
|
||||
|
||||
MacEager::expr(expr)
|
||||
ExpandResult::Ready(MacEager::expr(expr))
|
||||
}
|
||||
|
||||
struct Assert {
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
use rustc_ast::{
|
||||
ptr::P,
|
||||
token,
|
||||
token::Delimiter,
|
||||
token::{self, Delimiter, IdentIsRaw},
|
||||
tokenstream::{DelimSpan, TokenStream, TokenTree},
|
||||
BinOpKind, BorrowKind, DelimArgs, Expr, ExprKind, ItemKind, MacCall, MethodCall, Mutability,
|
||||
Path, PathSegment, Stmt, StructRest, UnOp, UseTree, UseTreeKind, DUMMY_NODE_ID,
|
||||
@ -170,7 +169,10 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
||||
];
|
||||
let captures = self.capture_decls.iter().flat_map(|cap| {
|
||||
[
|
||||
TokenTree::token_joint_hidden(token::Ident(cap.ident.name, false), cap.ident.span),
|
||||
TokenTree::token_joint_hidden(
|
||||
token::Ident(cap.ident.name, IdentIsRaw::No),
|
||||
cap.ident.span,
|
||||
),
|
||||
TokenTree::token_alone(token::Comma, self.span),
|
||||
]
|
||||
});
|
||||
@ -301,7 +303,8 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
||||
| ExprKind::Closure(_)
|
||||
| ExprKind::ConstBlock(_)
|
||||
| ExprKind::Continue(_)
|
||||
| ExprKind::Err
|
||||
| ExprKind::Dummy
|
||||
| ExprKind::Err(_)
|
||||
| ExprKind::Field(_, _)
|
||||
| ExprKind::ForLoop { .. }
|
||||
| ExprKind::FormatArgs(_)
|
||||
|
||||
@ -8,17 +8,17 @@ use rustc_ast::token;
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_attr as attr;
|
||||
use rustc_errors::PResult;
|
||||
use rustc_expand::base::{self, *};
|
||||
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
|
||||
use rustc_span::Span;
|
||||
|
||||
pub fn expand_cfg(
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
sp: Span,
|
||||
tts: TokenStream,
|
||||
) -> Box<dyn base::MacResult + 'static> {
|
||||
) -> MacroExpanderResult<'static> {
|
||||
let sp = cx.with_def_site_ctxt(sp);
|
||||
|
||||
match parse_cfg(cx, sp, tts) {
|
||||
ExpandResult::Ready(match parse_cfg(cx, sp, tts) {
|
||||
Ok(cfg) => {
|
||||
let matches_cfg = attr::cfg_matches(
|
||||
&cfg,
|
||||
@ -29,10 +29,10 @@ pub fn expand_cfg(
|
||||
MacEager::expr(cx.expr_bool(sp, matches_cfg))
|
||||
}
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
DummyResult::any(sp)
|
||||
let guar = err.emit();
|
||||
DummyResult::any(sp, guar)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> {
|
||||
|
||||
@ -46,7 +46,7 @@ impl MultiItemModifier for Expander {
|
||||
) -> ExpandResult<Vec<Annotatable>, Annotatable> {
|
||||
let template = AttributeTemplate { list: Some("path"), ..Default::default() };
|
||||
validate_attr::check_builtin_meta_item(
|
||||
&ecx.sess.parse_sess,
|
||||
&ecx.sess.psess,
|
||||
meta_item,
|
||||
ast::AttrStyle::Outer,
|
||||
sym::cfg_accessible,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user