Merge pull request #4277 from rust-lang/rustup-2025-04-17
Automatic Rustup
This commit is contained in:
commit
817e72521f
1042 changed files with 11310 additions and 7175 deletions
|
|
@ -31,3 +31,5 @@ ec2cc761bc7067712ecc7734502f703fe3b024c8
|
|||
c682aa162b0d41e21cc6748f4fecfe01efb69d1f
|
||||
# reformat with updated edition 2024
|
||||
1fcae03369abb4c2cc180cd5a49e1f4440a81300
|
||||
# Breaking up of compiletest runtest.rs
|
||||
60600a6fa403216bfd66e04f948b1822f6450af7
|
||||
|
|
|
|||
7
.github/workflows/ci.yml
vendored
7
.github/workflows/ci.yml
vendored
|
|
@ -53,6 +53,13 @@ jobs:
|
|||
steps:
|
||||
- name: Checkout the source code
|
||||
uses: actions/checkout@v4
|
||||
# Cache citool to make its build faster, as it's in the critical path.
|
||||
# The rust-cache doesn't bleed into the main `job`, so it should not affect any other
|
||||
# Rust compilation.
|
||||
- name: Cache citool
|
||||
uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8
|
||||
with:
|
||||
workspaces: src/ci/citool
|
||||
- name: Calculate the CI job matrix
|
||||
env:
|
||||
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
||||
|
|
|
|||
1
.mailmap
1
.mailmap
|
|
@ -292,6 +292,7 @@ James Hinshelwood <jameshinshelwood1@gmail.com> <james.hinshelwood@bigpayme.com>
|
|||
James Miller <bladeon@gmail.com> <james@aatch.net>
|
||||
James Perry <james.austin.perry@gmail.com>
|
||||
James Sanderson <zofrex@gmail.com>
|
||||
Jamie Hill-Daniel <jamie@hill-daniel.co.uk> <clubby789@gmail.com>
|
||||
Jana Dönszelmann <jana@donsz.nl>
|
||||
Jana Dönszelmann <jana@donsz.nl> <jonathan@donsz.nl>
|
||||
Jana Dönszelmann <jana@donsz.nl> <jonabent@gmail.com>
|
||||
|
|
|
|||
68
Cargo.lock
68
Cargo.lock
|
|
@ -719,6 +719,7 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"anstyle-svg",
|
||||
"build_helper",
|
||||
"camino",
|
||||
"colored",
|
||||
"diff",
|
||||
"getopts",
|
||||
|
|
@ -931,15 +932,6 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
|
||||
dependencies = [
|
||||
"powerfmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive-where"
|
||||
version = "1.2.7"
|
||||
|
|
@ -1221,7 +1213,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide 0.8.7",
|
||||
"miniz_oxide 0.8.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2291,9 +2283,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.7"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430"
|
||||
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
|
|
@ -2425,12 +2417,6 @@ dependencies = [
|
|||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-conv"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.46"
|
||||
|
|
@ -2808,12 +2794,6 @@ dependencies = [
|
|||
"portable-atomic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.21"
|
||||
|
|
@ -3616,6 +3596,7 @@ name = "rustc_driver_impl"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"ctrlc",
|
||||
"jiff",
|
||||
"libc",
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
|
|
@ -3662,7 +3643,6 @@ dependencies = [
|
|||
"rustc_ty_utils",
|
||||
"serde_json",
|
||||
"shlex",
|
||||
"time",
|
||||
"tracing",
|
||||
"windows 0.59.0",
|
||||
]
|
||||
|
|
@ -4692,6 +4672,7 @@ name = "rustdoc-gui-test"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"build_helper",
|
||||
"camino",
|
||||
"compiletest",
|
||||
"getopts",
|
||||
"walkdir",
|
||||
|
|
@ -5356,37 +5337,6 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa",
|
||||
"num-conv",
|
||||
"powerfmt",
|
||||
"serde",
|
||||
"time-core",
|
||||
"time-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49"
|
||||
dependencies = [
|
||||
"num-conv",
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinystr"
|
||||
version = "0.7.6"
|
||||
|
|
@ -6111,11 +6061,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-bindgen"
|
||||
version = "0.59.0"
|
||||
version = "0.61.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b7fb600834d7e868f6e5bb748a86101427330fafbf9485c331b9d5f562d54a5"
|
||||
checksum = "ac1c59c20569610dd9ed784d5f003fb493ec57b4cf39d974eb03a84bb7156c90"
|
||||
dependencies = [
|
||||
"rayon",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -315,7 +315,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
repr: &ReprOptions,
|
||||
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
|
||||
is_enum: bool,
|
||||
is_unsafe_cell: bool,
|
||||
is_special_no_niche: bool,
|
||||
scalar_valid_range: (Bound<u128>, Bound<u128>),
|
||||
discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool),
|
||||
discriminants: impl Iterator<Item = (VariantIdx, i128)>,
|
||||
|
|
@ -348,7 +348,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
repr,
|
||||
variants,
|
||||
is_enum,
|
||||
is_unsafe_cell,
|
||||
is_special_no_niche,
|
||||
scalar_valid_range,
|
||||
always_sized,
|
||||
present_first,
|
||||
|
|
@ -505,7 +505,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
repr: &ReprOptions,
|
||||
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
|
||||
is_enum: bool,
|
||||
is_unsafe_cell: bool,
|
||||
is_special_no_niche: bool,
|
||||
scalar_valid_range: (Bound<u128>, Bound<u128>),
|
||||
always_sized: bool,
|
||||
present_first: VariantIdx,
|
||||
|
|
@ -524,7 +524,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
let mut st = self.univariant(&variants[v], repr, kind)?;
|
||||
st.variants = Variants::Single { index: v };
|
||||
|
||||
if is_unsafe_cell {
|
||||
if is_special_no_niche {
|
||||
let hide_niches = |scalar: &mut _| match scalar {
|
||||
Scalar::Initialized { value, valid_range } => {
|
||||
*valid_range = WrappingRange::full(value.size(dl))
|
||||
|
|
|
|||
|
|
@ -120,6 +120,17 @@ impl Path {
|
|||
Path { segments: thin_vec![PathSegment::from_ident(ident)], span: ident.span, tokens: None }
|
||||
}
|
||||
|
||||
pub fn is_ident(&self, name: Symbol) -> bool {
|
||||
if let [segment] = self.segments.as_ref()
|
||||
&& segment.args.is_none()
|
||||
&& segment.ident.name == name
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_global(&self) -> bool {
|
||||
self.segments.first().is_some_and(|segment| segment.ident.name == kw::PathRoot)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ use std::fmt;
|
|||
use std::marker::PhantomData;
|
||||
|
||||
use crate::ptr::P;
|
||||
use crate::token::Nonterminal;
|
||||
use crate::tokenstream::LazyAttrTokenStream;
|
||||
use crate::{
|
||||
Arm, AssocItem, AttrItem, AttrKind, AttrVec, Attribute, Block, Crate, Expr, ExprField,
|
||||
|
|
@ -206,19 +205,6 @@ impl HasTokens for Attribute {
|
|||
}
|
||||
}
|
||||
|
||||
impl HasTokens for Nonterminal {
|
||||
fn tokens(&self) -> Option<&LazyAttrTokenStream> {
|
||||
match self {
|
||||
Nonterminal::NtBlock(block) => block.tokens(),
|
||||
}
|
||||
}
|
||||
fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
|
||||
match self {
|
||||
Nonterminal::NtBlock(block) => block.tokens_mut(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait for AST nodes having (or not having) attributes.
|
||||
pub trait HasAttrs {
|
||||
/// This is `true` if this `HasAttrs` might support 'custom' (proc-macro) inner
|
||||
|
|
|
|||
|
|
@ -627,7 +627,7 @@ pub fn mk_doc_comment(
|
|||
Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span }
|
||||
}
|
||||
|
||||
pub fn mk_attr(
|
||||
fn mk_attr(
|
||||
g: &AttrIdGenerator,
|
||||
style: AttrStyle,
|
||||
unsafety: Safety,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
|
||||
#![doc(
|
||||
html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
|
||||
test(attr(deny(warnings)))
|
||||
|
|
|
|||
|
|
@ -844,9 +844,9 @@ fn visit_lazy_tts<T: MutVisitor>(vis: &mut T, lazy_tts: &mut Option<LazyAttrToke
|
|||
visit_lazy_tts_opt_mut(vis, lazy_tts.as_mut());
|
||||
}
|
||||
|
||||
/// Applies ident visitor if it's an ident; applies other visits to interpolated nodes.
|
||||
/// In practice the ident part is not actually used by specific visitors right now,
|
||||
/// but there's a test below checking that it works.
|
||||
/// Applies ident visitor if it's an ident. In practice this is not actually
|
||||
/// used by specific visitors right now, but there's a test below checking that
|
||||
/// it works.
|
||||
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
|
||||
pub fn visit_token<T: MutVisitor>(vis: &mut T, t: &mut Token) {
|
||||
let Token { kind, span } = t;
|
||||
|
|
@ -864,45 +864,11 @@ pub fn visit_token<T: MutVisitor>(vis: &mut T, t: &mut Token) {
|
|||
token::NtLifetime(ident, _is_raw) => {
|
||||
vis.visit_ident(ident);
|
||||
}
|
||||
token::Interpolated(nt) => {
|
||||
let nt = Arc::make_mut(nt);
|
||||
visit_nonterminal(vis, nt);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
|
||||
/// Applies the visitor to elements of interpolated nodes.
|
||||
//
|
||||
// N.B., this can occur only when applying a visitor to partially expanded
|
||||
// code, where parsed pieces have gotten implanted ito *other* macro
|
||||
// invocations. This is relevant for macro hygiene, but possibly not elsewhere.
|
||||
//
|
||||
// One problem here occurs because the types for flat_map_item, flat_map_stmt,
|
||||
// etc., allow the visitor to return *multiple* items; this is a problem for the
|
||||
// nodes here, because they insist on having exactly one piece. One solution
|
||||
// would be to mangle the MutVisitor trait to include one-to-many and
|
||||
// one-to-one versions of these entry points, but that would probably confuse a
|
||||
// lot of people and help very few. Instead, I'm just going to put in dynamic
|
||||
// checks. I think the performance impact of this will be pretty much
|
||||
// nonexistent. The danger is that someone will apply a `MutVisitor` to a
|
||||
// partially expanded node, and will be confused by the fact that their
|
||||
// `flat_map_item` or `flat_map_stmt` isn't getting called on `NtItem` or `NtStmt`
|
||||
// nodes. Hopefully they'll wind up reading this comment, and doing something
|
||||
// appropriate.
|
||||
//
|
||||
// BTW, design choice: I considered just changing the type of, e.g., `NtItem` to
|
||||
// contain multiple items, but decided against it when I looked at
|
||||
// `parse_item_or_view_item` and tried to figure out what I would do with
|
||||
// multiple items there....
|
||||
fn visit_nonterminal<T: MutVisitor>(vis: &mut T, nt: &mut token::Nonterminal) {
|
||||
match nt {
|
||||
token::NtBlock(block) => vis.visit_block(block),
|
||||
}
|
||||
}
|
||||
|
||||
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
|
||||
fn visit_defaultness<T: MutVisitor>(vis: &mut T, defaultness: &mut Defaultness) {
|
||||
match defaultness {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,10 @@
|
|||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub use LitKind::*;
|
||||
pub use Nonterminal::*;
|
||||
pub use NtExprKind::*;
|
||||
pub use NtPatKind::*;
|
||||
pub use TokenKind::*;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, kw, sym};
|
||||
|
|
@ -16,7 +13,6 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, kw, sym};
|
|||
use rustc_span::{Ident, Symbol};
|
||||
|
||||
use crate::ast;
|
||||
use crate::ptr::P;
|
||||
use crate::util::case::Case;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
|
|
@ -34,10 +30,6 @@ pub enum InvisibleOrigin {
|
|||
// Converted from `proc_macro::Delimiter` in
|
||||
// `proc_macro::Delimiter::to_internal`, i.e. returned by a proc macro.
|
||||
ProcMacro,
|
||||
|
||||
// Converted from `TokenKind::Interpolated` in
|
||||
// `TokenStream::flatten_token`. Treated similarly to `ProcMacro`.
|
||||
FlattenToken,
|
||||
}
|
||||
|
||||
impl PartialEq for InvisibleOrigin {
|
||||
|
|
@ -134,9 +126,7 @@ impl Delimiter {
|
|||
match self {
|
||||
Delimiter::Parenthesis | Delimiter::Bracket | Delimiter::Brace => false,
|
||||
Delimiter::Invisible(InvisibleOrigin::MetaVar(_)) => false,
|
||||
Delimiter::Invisible(InvisibleOrigin::FlattenToken | InvisibleOrigin::ProcMacro) => {
|
||||
true
|
||||
}
|
||||
Delimiter::Invisible(InvisibleOrigin::ProcMacro) => true,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -337,9 +327,7 @@ impl From<IdentIsRaw> for bool {
|
|||
}
|
||||
}
|
||||
|
||||
// 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)]
|
||||
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub enum TokenKind {
|
||||
/* Expression-operator symbols. */
|
||||
/// `=`
|
||||
|
|
@ -468,21 +456,6 @@ pub enum TokenKind {
|
|||
/// the `lifetime` metavariable in the macro's RHS.
|
||||
NtLifetime(Ident, IdentIsRaw),
|
||||
|
||||
/// An embedded AST node, as produced by a macro. This only exists for
|
||||
/// historical reasons. We'd like to get rid of it, for multiple reasons.
|
||||
/// - It's conceptually very strange. Saying a token can contain an AST
|
||||
/// node is like saying, in natural language, that a word can contain a
|
||||
/// sentence.
|
||||
/// - It requires special handling in a bunch of places in the parser.
|
||||
/// - It prevents `Token` from implementing `Copy`.
|
||||
/// It adds complexity and likely slows things down. Please don't add new
|
||||
/// occurrences of this token kind!
|
||||
///
|
||||
/// The span in the surrounding `Token` is that of the metavariable in the
|
||||
/// macro's RHS. The span within the Nonterminal is that of the fragment
|
||||
/// passed to the macro at the call site.
|
||||
Interpolated(Arc<Nonterminal>),
|
||||
|
||||
/// A doc comment token.
|
||||
/// `Symbol` is the doc comment's data excluding its "quotes" (`///`, `/**`, etc)
|
||||
/// similarly to symbols in string literal tokens.
|
||||
|
|
@ -492,20 +465,7 @@ pub enum TokenKind {
|
|||
Eof,
|
||||
}
|
||||
|
||||
impl Clone for TokenKind {
|
||||
fn clone(&self) -> Self {
|
||||
// `TokenKind` would impl `Copy` if it weren't for `Interpolated`. So
|
||||
// for all other variants, this implementation of `clone` is just like
|
||||
// a copy. This is faster than the `derive(Clone)` version which has a
|
||||
// separate path for every variant.
|
||||
match self {
|
||||
Interpolated(nt) => Interpolated(Arc::clone(nt)),
|
||||
_ => unsafe { std::ptr::read(self) },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub struct Token {
|
||||
pub kind: TokenKind,
|
||||
pub span: Span,
|
||||
|
|
@ -600,7 +560,7 @@ impl Token {
|
|||
| FatArrow | Pound | Dollar | Question | SingleQuote => true,
|
||||
|
||||
OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..)
|
||||
| NtIdent(..) | Lifetime(..) | NtLifetime(..) | Interpolated(..) | Eof => false,
|
||||
| NtIdent(..) | Lifetime(..) | NtLifetime(..) | Eof => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -631,7 +591,6 @@ impl Token {
|
|||
PathSep | // global path
|
||||
Lifetime(..) | // labeled loop
|
||||
Pound => true, // expression attributes
|
||||
Interpolated(ref nt) => matches!(&**nt, NtBlock(..)),
|
||||
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
|
||||
MetaVarKind::Block |
|
||||
MetaVarKind::Expr { .. } |
|
||||
|
|
@ -703,7 +662,6 @@ impl Token {
|
|||
match self.kind {
|
||||
OpenDelim(Delimiter::Brace) | Literal(..) | Minus => true,
|
||||
Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true,
|
||||
Interpolated(ref nt) => matches!(&**nt, NtBlock(..)),
|
||||
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
|
||||
MetaVarKind::Expr { .. } | MetaVarKind::Block | MetaVarKind::Literal,
|
||||
))) => true,
|
||||
|
|
@ -831,31 +789,20 @@ impl Token {
|
|||
/// Is this a pre-parsed expression dropped into the token stream
|
||||
/// (which happens while parsing the result of macro expansion)?
|
||||
pub fn is_metavar_expr(&self) -> bool {
|
||||
#[allow(irrefutable_let_patterns)] // FIXME: temporary
|
||||
if let Interpolated(nt) = &self.kind
|
||||
&& let NtBlock(_) = &**nt
|
||||
{
|
||||
true
|
||||
} else if matches!(
|
||||
matches!(
|
||||
self.is_metavar_seq(),
|
||||
Some(MetaVarKind::Expr { .. } | MetaVarKind::Literal | MetaVarKind::Path)
|
||||
) {
|
||||
true
|
||||
} else {
|
||||
matches!(self.is_metavar_seq(), Some(MetaVarKind::Path))
|
||||
}
|
||||
Some(
|
||||
MetaVarKind::Expr { .. }
|
||||
| MetaVarKind::Literal
|
||||
| MetaVarKind::Path
|
||||
| MetaVarKind::Block
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/// Is the token an interpolated block (`$b:block`)?
|
||||
pub fn is_whole_block(&self) -> bool {
|
||||
#[allow(irrefutable_let_patterns)] // FIXME: temporary
|
||||
if let Interpolated(nt) = &self.kind
|
||||
&& let NtBlock(..) = &**nt
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
/// Are we at a block from a metavar (`$b:block`)?
|
||||
pub fn is_metavar_block(&self) -> bool {
|
||||
matches!(self.is_metavar_seq(), Some(MetaVarKind::Block))
|
||||
}
|
||||
|
||||
/// Returns `true` if the token is either the `mut` or `const` keyword.
|
||||
|
|
@ -1024,7 +971,7 @@ impl Token {
|
|||
| PercentEq | CaretEq | AndEq | OrEq | ShlEq | ShrEq | At | DotDotDot | DotDotEq
|
||||
| Comma | Semi | PathSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question
|
||||
| OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..) | NtIdent(..)
|
||||
| Lifetime(..) | NtLifetime(..) | Interpolated(..) | DocComment(..) | Eof,
|
||||
| Lifetime(..) | NtLifetime(..) | DocComment(..) | Eof,
|
||||
_,
|
||||
) => {
|
||||
return None;
|
||||
|
|
@ -1063,12 +1010,6 @@ pub enum NtExprKind {
|
|||
Expr2021 { inferred: bool },
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable)]
|
||||
/// For interpolation during macro expansion.
|
||||
pub enum Nonterminal {
|
||||
NtBlock(P<ast::Block>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
|
||||
pub enum NonterminalKind {
|
||||
Item,
|
||||
|
|
@ -1152,47 +1093,6 @@ impl fmt::Display for NonterminalKind {
|
|||
}
|
||||
}
|
||||
|
||||
impl Nonterminal {
|
||||
pub fn use_span(&self) -> Span {
|
||||
match self {
|
||||
NtBlock(block) => block.span,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn descr(&self) -> &'static str {
|
||||
match self {
|
||||
NtBlock(..) => "block",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Nonterminal {
|
||||
fn eq(&self, _rhs: &Self) -> bool {
|
||||
// FIXME: Assume that all nonterminals are not equal, we can't compare them
|
||||
// correctly based on data from AST. This will prevent them from matching each other
|
||||
// in macros. The comparison will become possible only when each nonterminal has an
|
||||
// attached token stream from which it was parsed.
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Nonterminal {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
NtBlock(..) => f.pad("NtBlock(..)"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<CTX> HashStable<CTX> for Nonterminal
|
||||
where
|
||||
CTX: crate::HashStableContext,
|
||||
{
|
||||
fn hash_stable(&self, _hcx: &mut CTX, _hasher: &mut StableHasher) {
|
||||
panic!("interpolated tokens should not be present in the HIR")
|
||||
}
|
||||
}
|
||||
|
||||
// Some types are used a lot. Make sure they don't unintentionally get bigger.
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
mod size_asserts {
|
||||
|
|
@ -1202,7 +1102,6 @@ mod size_asserts {
|
|||
// tidy-alphabetical-start
|
||||
static_assert_size!(Lit, 12);
|
||||
static_assert_size!(LitKind, 2);
|
||||
static_assert_size!(Nonterminal, 8);
|
||||
static_assert_size!(Token, 24);
|
||||
static_assert_size!(TokenKind, 16);
|
||||
// tidy-alphabetical-end
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ use rustc_span::{DUMMY_SP, Span, SpanDecoder, SpanEncoder, Symbol, sym};
|
|||
|
||||
use crate::ast::AttrStyle;
|
||||
use crate::ast_traits::{HasAttrs, HasTokens};
|
||||
use crate::token::{self, Delimiter, InvisibleOrigin, Nonterminal, Token, TokenKind};
|
||||
use crate::token::{self, Delimiter, Token, TokenKind};
|
||||
use crate::{AttrVec, Attribute};
|
||||
|
||||
/// Part of a `TokenStream`.
|
||||
|
|
@ -305,11 +305,6 @@ pub struct AttrsTarget {
|
|||
}
|
||||
|
||||
/// A `TokenStream` is an abstract sequence of tokens, organized into [`TokenTree`]s.
|
||||
///
|
||||
/// The goal is for procedural macros to work with `TokenStream`s and `TokenTree`s
|
||||
/// instead of a representation of the abstract syntax tree.
|
||||
/// Today's `TokenTree`s can still contain AST via `token::Interpolated` for
|
||||
/// backwards compatibility.
|
||||
#[derive(Clone, Debug, Default, Encodable, Decodable)]
|
||||
pub struct TokenStream(pub(crate) Arc<Vec<TokenTree>>);
|
||||
|
||||
|
|
@ -476,61 +471,6 @@ impl TokenStream {
|
|||
TokenStream::new(tts)
|
||||
}
|
||||
|
||||
pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream {
|
||||
match nt {
|
||||
Nonterminal::NtBlock(block) => TokenStream::from_ast(block),
|
||||
}
|
||||
}
|
||||
|
||||
fn flatten_token(token: &Token, spacing: Spacing) -> TokenTree {
|
||||
match token.kind {
|
||||
token::NtIdent(ident, is_raw) => {
|
||||
TokenTree::Token(Token::new(token::Ident(ident.name, is_raw), ident.span), spacing)
|
||||
}
|
||||
token::NtLifetime(ident, is_raw) => TokenTree::Delimited(
|
||||
DelimSpan::from_single(token.span),
|
||||
DelimSpacing::new(Spacing::JointHidden, spacing),
|
||||
Delimiter::Invisible(InvisibleOrigin::FlattenToken),
|
||||
TokenStream::token_alone(token::Lifetime(ident.name, is_raw), ident.span),
|
||||
),
|
||||
token::Interpolated(ref nt) => TokenTree::Delimited(
|
||||
DelimSpan::from_single(token.span),
|
||||
DelimSpacing::new(Spacing::JointHidden, spacing),
|
||||
Delimiter::Invisible(InvisibleOrigin::FlattenToken),
|
||||
TokenStream::from_nonterminal_ast(&nt).flattened(),
|
||||
),
|
||||
_ => TokenTree::Token(token.clone(), spacing),
|
||||
}
|
||||
}
|
||||
|
||||
fn flatten_token_tree(tree: &TokenTree) -> TokenTree {
|
||||
match tree {
|
||||
TokenTree::Token(token, spacing) => TokenStream::flatten_token(token, *spacing),
|
||||
TokenTree::Delimited(span, spacing, delim, tts) => {
|
||||
TokenTree::Delimited(*span, *spacing, *delim, tts.flattened())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn flattened(&self) -> TokenStream {
|
||||
fn can_skip(stream: &TokenStream) -> bool {
|
||||
stream.iter().all(|tree| match tree {
|
||||
TokenTree::Token(token, _) => !matches!(
|
||||
token.kind,
|
||||
token::NtIdent(..) | token::NtLifetime(..) | token::Interpolated(..)
|
||||
),
|
||||
TokenTree::Delimited(.., inner) => can_skip(inner),
|
||||
})
|
||||
}
|
||||
|
||||
if can_skip(self) {
|
||||
return self.clone();
|
||||
}
|
||||
|
||||
self.iter().map(|tree| TokenStream::flatten_token_tree(tree)).collect()
|
||||
}
|
||||
|
||||
// If `vec` is not empty, try to glue `tt` onto its last token. The return
|
||||
// value indicates if gluing took place.
|
||||
fn try_glue_to_last(vec: &mut Vec<TokenTree>, tt: &TokenTree) -> bool {
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
.delegation_fn_sigs
|
||||
.get(&local_def_id)
|
||||
.is_some_and(|sig| sig.has_self),
|
||||
None => self.tcx.associated_item(def_id).fn_has_self_parameter,
|
||||
None => self.tcx.associated_item(def_id).is_method(),
|
||||
},
|
||||
_ => span_bug!(span, "unexpected DefKind for delegation item"),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -399,12 +399,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
&mut self,
|
||||
expr: &'hir hir::Expr<'hir>,
|
||||
span: Span,
|
||||
check_ident: Ident,
|
||||
check_hir_id: HirId,
|
||||
cond_ident: Ident,
|
||||
cond_hir_id: HirId,
|
||||
) -> &'hir hir::Expr<'hir> {
|
||||
let checker_fn = self.expr_ident(span, check_ident, check_hir_id);
|
||||
let span = self.mark_span_with_reason(DesugaringKind::Contract, span, None);
|
||||
self.expr_call(span, checker_fn, std::slice::from_ref(expr))
|
||||
let cond_fn = self.expr_ident(span, cond_ident, cond_hir_id);
|
||||
let call_expr = self.expr_call_lang_item_fn_mut(
|
||||
span,
|
||||
hir::LangItem::ContractCheckEnsures,
|
||||
arena_vec![self; *cond_fn, *expr],
|
||||
);
|
||||
self.arena.alloc(call_expr)
|
||||
}
|
||||
|
||||
pub(crate) fn lower_const_block(&mut self, c: &AnonConst) -> hir::ConstBlock {
|
||||
|
|
|
|||
|
|
@ -1206,8 +1206,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let precond = if let Some(req) = &contract.requires {
|
||||
// Lower the precondition check intrinsic.
|
||||
let lowered_req = this.lower_expr_mut(&req);
|
||||
let req_span = this.mark_span_with_reason(
|
||||
DesugaringKind::Contract,
|
||||
lowered_req.span,
|
||||
None,
|
||||
);
|
||||
let precond = this.expr_call_lang_item_fn_mut(
|
||||
req.span,
|
||||
req_span,
|
||||
hir::LangItem::ContractCheckRequires,
|
||||
&*arena_vec![this; lowered_req],
|
||||
);
|
||||
|
|
@ -1217,6 +1222,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
};
|
||||
let (postcond, body) = if let Some(ens) = &contract.ensures {
|
||||
let ens_span = this.lower_span(ens.span);
|
||||
let ens_span =
|
||||
this.mark_span_with_reason(DesugaringKind::Contract, ens_span, None);
|
||||
// Set up the postcondition `let` statement.
|
||||
let check_ident: Ident =
|
||||
Ident::from_str_and_span("__ensures_checker", ens_span);
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@
|
|||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
|
||||
#![doc(rust_logo)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
|
|
@ -917,7 +916,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
|
||||
fn lower_delim_args(&self, args: &DelimArgs) -> DelimArgs {
|
||||
DelimArgs { dspan: args.dspan, delim: args.delim, tokens: args.tokens.flattened() }
|
||||
DelimArgs { dspan: args.dspan, delim: args.delim, tokens: args.tokens.clone() }
|
||||
}
|
||||
|
||||
/// Lower an associated item constraint.
|
||||
|
|
@ -1766,24 +1765,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
ident: Ident,
|
||||
is_anon_in_path: IsAnonInPath,
|
||||
) -> &'hir hir::Lifetime {
|
||||
debug_assert_ne!(ident.name, kw::Empty);
|
||||
let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error);
|
||||
let res = match res {
|
||||
LifetimeRes::Param { param, .. } => hir::LifetimeName::Param(param),
|
||||
LifetimeRes::Param { param, .. } => hir::LifetimeKind::Param(param),
|
||||
LifetimeRes::Fresh { param, .. } => {
|
||||
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
|
||||
let param = self.local_def_id(param);
|
||||
hir::LifetimeName::Param(param)
|
||||
hir::LifetimeKind::Param(param)
|
||||
}
|
||||
LifetimeRes::Infer => {
|
||||
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
|
||||
hir::LifetimeName::Infer
|
||||
hir::LifetimeKind::Infer
|
||||
}
|
||||
LifetimeRes::Static { .. } => {
|
||||
debug_assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime));
|
||||
hir::LifetimeName::Static
|
||||
hir::LifetimeKind::Static
|
||||
}
|
||||
LifetimeRes::Error => hir::LifetimeName::Error,
|
||||
LifetimeRes::Error => hir::LifetimeKind::Error,
|
||||
LifetimeRes::ElidedAnchor { .. } => {
|
||||
panic!("Unexpected `ElidedAnchar` {:?} at {:?}", ident, ident.span);
|
||||
}
|
||||
|
|
@ -2390,7 +2388,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let r = hir::Lifetime::new(
|
||||
self.next_id(),
|
||||
Ident::new(kw::UnderscoreLifetime, self.lower_span(span)),
|
||||
hir::LifetimeName::ImplicitObjectLifetimeDefault,
|
||||
hir::LifetimeKind::ImplicitObjectLifetimeDefault,
|
||||
IsAnonInPath::No,
|
||||
);
|
||||
debug!("elided_dyn_bound: r={:?}", r);
|
||||
|
|
|
|||
|
|
@ -448,8 +448,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
generic_args.args.insert_many(
|
||||
0,
|
||||
(start.as_u32()..end.as_u32()).map(|i| {
|
||||
let id = NodeId::from_u32(i);
|
||||
(start..end).map(|id| {
|
||||
let l = self.lower_lifetime_anon_in_path(id, elided_lifetime_span);
|
||||
GenericArg::Lifetime(l)
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -79,6 +79,10 @@ ast_passes_extern_types_cannot = `type`s inside `extern` blocks cannot have {$de
|
|||
.suggestion = remove the {$remove_descr}
|
||||
.label = `extern` block begins here
|
||||
|
||||
ast_passes_extern_without_abi = `extern` declarations without an explicit ABI are disallowed
|
||||
.suggestion = specify an ABI
|
||||
.help = prior to Rust 2024, a default ABI was inferred
|
||||
|
||||
ast_passes_feature_on_non_nightly = `#![feature]` may not be used on the {$channel} release channel
|
||||
.suggestion = remove the attribute
|
||||
.stable_since = the feature `{$name}` has been stable since `{$since}` and no longer requires an attribute to enable
|
||||
|
|
|
|||
|
|
@ -684,7 +684,7 @@ impl<'a> AstValidator<'a> {
|
|||
self.dcx().emit_err(errors::PatternFnPointer { span });
|
||||
});
|
||||
if let Extern::Implicit(extern_span) = bfty.ext {
|
||||
self.maybe_lint_missing_abi(extern_span, ty.id);
|
||||
self.handle_missing_abi(extern_span, ty.id);
|
||||
}
|
||||
}
|
||||
TyKind::TraitObject(bounds, ..) => {
|
||||
|
|
@ -717,10 +717,12 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) {
|
||||
fn handle_missing_abi(&mut self, span: Span, id: NodeId) {
|
||||
// FIXME(davidtwco): This is a hack to detect macros which produce spans of the
|
||||
// call site which do not have a macro backtrace. See #61963.
|
||||
if self
|
||||
if span.edition().at_least_edition_future() && self.features.explicit_extern_abis() {
|
||||
self.dcx().emit_err(errors::MissingAbi { span });
|
||||
} else if self
|
||||
.sess
|
||||
.source_map()
|
||||
.span_to_snippet(span)
|
||||
|
|
@ -996,7 +998,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}
|
||||
|
||||
if abi.is_none() {
|
||||
self.maybe_lint_missing_abi(*extern_span, item.id);
|
||||
self.handle_missing_abi(*extern_span, item.id);
|
||||
}
|
||||
self.with_in_extern_mod(*safety, |this| {
|
||||
visit::walk_item(this, item);
|
||||
|
|
@ -1370,7 +1372,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
},
|
||||
) = fk
|
||||
{
|
||||
self.maybe_lint_missing_abi(*extern_span, id);
|
||||
self.handle_missing_abi(*extern_span, id);
|
||||
}
|
||||
|
||||
// Functions without bodies cannot have patterns.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use rustc_ast::ParamKindOrd;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{Applicability, Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic};
|
||||
use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_span::{Ident, Span, Symbol};
|
||||
|
||||
|
|
@ -394,11 +394,7 @@ pub(crate) struct EmptyLabelManySpans(pub Vec<Span>);
|
|||
|
||||
// The derive for `Vec<Span>` does multiple calls to `span_label`, adding commas between each
|
||||
impl Subdiagnostic for EmptyLabelManySpans {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_: &F,
|
||||
) {
|
||||
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
|
||||
diag.span_labels(self.0, "");
|
||||
}
|
||||
}
|
||||
|
|
@ -749,11 +745,7 @@ pub(crate) struct StableFeature {
|
|||
}
|
||||
|
||||
impl Subdiagnostic for StableFeature {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_: &F,
|
||||
) {
|
||||
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
|
||||
diag.arg("name", self.name);
|
||||
diag.arg("since", self.since);
|
||||
diag.help(fluent::ast_passes_stable_since);
|
||||
|
|
@ -823,3 +815,12 @@ pub(crate) struct DuplicatePreciseCapturing {
|
|||
#[label]
|
||||
pub bound2: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_extern_without_abi)]
|
||||
#[help]
|
||||
pub(crate) struct MissingAbi {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "extern \"<abi>\"", applicability = "has-placeholders")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,14 +5,10 @@ pub mod state;
|
|||
use std::borrow::Cow;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::token::{Nonterminal, Token, TokenKind};
|
||||
use rustc_ast::token::{Token, TokenKind};
|
||||
use rustc_ast::tokenstream::{TokenStream, TokenTree};
|
||||
pub use state::{AnnNode, Comments, PpAnn, PrintState, State, print_crate};
|
||||
|
||||
pub fn nonterminal_to_string(nt: &Nonterminal) -> String {
|
||||
State::new().nonterminal_to_string(nt)
|
||||
}
|
||||
|
||||
/// Print the token kind precisely, without converting `$crate` into its respective crate name.
|
||||
pub fn token_kind_to_string(tok: &TokenKind) -> Cow<'static, str> {
|
||||
State::new().token_kind_to_string(tok)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use std::sync::Arc;
|
|||
|
||||
use rustc_ast::attr::AttrIdGenerator;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind};
|
||||
use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Token, TokenKind};
|
||||
use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree};
|
||||
use rustc_ast::util::classify;
|
||||
use rustc_ast::util::comments::{Comment, CommentStyle};
|
||||
|
|
@ -876,14 +876,6 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
}
|
||||
}
|
||||
|
||||
fn nonterminal_to_string(&self, nt: &Nonterminal) -> String {
|
||||
// We extract the token stream from the AST fragment and pretty print
|
||||
// it, rather than using AST pretty printing, because `Nonterminal` is
|
||||
// slated for removal in #124141. (This method will also then be
|
||||
// removed.)
|
||||
self.tts_to_string(&TokenStream::from_nonterminal_ast(nt))
|
||||
}
|
||||
|
||||
/// Print the token kind precisely, without converting `$crate` into its respective crate name.
|
||||
fn token_kind_to_string(&self, tok: &TokenKind) -> Cow<'static, str> {
|
||||
self.token_kind_to_string_ext(tok, None)
|
||||
|
|
@ -976,8 +968,6 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
doc_comment_to_string(comment_kind, attr_style, data).into()
|
||||
}
|
||||
token::Eof => "<eof>".into(),
|
||||
|
||||
token::Interpolated(ref nt) => self.nonterminal_to_string(&nt).into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ use rustc_session::config::ExpectedValues;
|
|||
use rustc_session::lint::BuiltinLintDiag;
|
||||
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::symbol::kw;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
|
||||
use crate::session_diagnostics::{self, UnsupportedLiteralReason};
|
||||
|
|
@ -89,20 +88,6 @@ pub fn eval_condition(
|
|||
let cfg = match cfg {
|
||||
MetaItemInner::MetaItem(meta_item) => meta_item,
|
||||
MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => {
|
||||
if let Some(features) = features {
|
||||
// we can't use `try_gate_cfg` as symbols don't differentiate between `r#true`
|
||||
// and `true`, and we want to keep the former working without feature gate
|
||||
gate_cfg(
|
||||
&(
|
||||
if *b { kw::True } else { kw::False },
|
||||
sym::cfg_boolean_literals,
|
||||
|features: &Features| features.cfg_boolean_literals(),
|
||||
),
|
||||
cfg.span(),
|
||||
sess,
|
||||
features,
|
||||
);
|
||||
}
|
||||
return *b;
|
||||
}
|
||||
_ => {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ impl SingleAttributeParser for TransparencyParser {
|
|||
fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
match args.name_value().and_then(|nv| nv.value_as_str()) {
|
||||
Some(sym::transparent) => Some(Transparency::Transparent),
|
||||
Some(sym::semitransparent) => Some(Transparency::SemiTransparent),
|
||||
Some(sym::semiopaque | sym::semitransparent) => Some(Transparency::SemiOpaque),
|
||||
Some(sym::opaque) => Some(Transparency::Opaque),
|
||||
Some(other) => {
|
||||
cx.dcx().span_err(cx.attr_span, format!("unknown macro transparency: `{other}`"));
|
||||
|
|
|
|||
|
|
@ -320,7 +320,7 @@ impl<'sess> AttributeParser<'sess> {
|
|||
ast::AttrArgs::Delimited(args) => AttrArgs::Delimited(DelimArgs {
|
||||
dspan: args.dspan,
|
||||
delim: args.delim,
|
||||
tokens: args.tokens.flattened(),
|
||||
tokens: args.tokens.clone(),
|
||||
}),
|
||||
// This is an inert key-value attribute - it will never be visible to macros
|
||||
// after it gets lowered to HIR. Therefore, we can extract literals to handle
|
||||
|
|
|
|||
|
|
@ -77,7 +77,6 @@
|
|||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
|
||||
#![doc(rust_logo)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(rustdoc_internals)]
|
||||
|
|
|
|||
|
|
@ -485,25 +485,7 @@ impl<'a> MetaItemListParserContext<'a> {
|
|||
}
|
||||
|
||||
// or a path.
|
||||
let path =
|
||||
if let Some(TokenTree::Token(Token { kind: token::Interpolated(_), span, .. }, _)) =
|
||||
self.inside_delimiters.peek()
|
||||
{
|
||||
self.inside_delimiters.next();
|
||||
// We go into this path if an expr ended up in an attribute that
|
||||
// expansion did not turn into a literal. Say, `#[repr(align(macro!()))]`
|
||||
// where the macro didn't expand to a literal. An error is already given
|
||||
// for this at this point, and then we do continue. This makes this path
|
||||
// reachable...
|
||||
let e = self.dcx.span_delayed_bug(
|
||||
*span,
|
||||
"expr in place where literal is expected (builtin attr parsing)",
|
||||
);
|
||||
|
||||
return Some(MetaItemOrLitParser::Err(*span, e));
|
||||
} else {
|
||||
self.next_path()?
|
||||
};
|
||||
let path = self.next_path()?;
|
||||
|
||||
// Paths can be followed by:
|
||||
// - `(more meta items)` (another list)
|
||||
|
|
|
|||
|
|
@ -77,6 +77,9 @@ pub(crate) fn categorize(context: PlaceContext) -> Option<DefUse> {
|
|||
// Debug info is neither def nor use.
|
||||
PlaceContext::NonUse(NonUseContext::VarDebugInfo) => None,
|
||||
|
||||
// Backwards incompatible drop hint is not a use, just a marker for linting.
|
||||
PlaceContext::NonUse(NonUseContext::BackwardIncompatibleDropHint) => None,
|
||||
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Deinit | MutatingUseContext::SetDiscriminant) => {
|
||||
bug!("These statements are not allowed in this MIR phase")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -647,7 +647,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
&& tc.polarity() == ty::PredicatePolarity::Positive
|
||||
&& supertrait_def_ids(tcx, tc.def_id())
|
||||
.flat_map(|trait_did| tcx.associated_items(trait_did).in_definition_order())
|
||||
.any(|item| item.fn_has_self_parameter)
|
||||
.any(|item| item.is_method())
|
||||
})
|
||||
}) {
|
||||
return None;
|
||||
|
|
@ -3376,10 +3376,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
|
||||
let (sugg_span, suggestion) = match tcx.sess.source_map().span_to_snippet(args_span) {
|
||||
Ok(string) => {
|
||||
let coro_prefix = if string.starts_with("async") {
|
||||
// `async` is 5 chars long. Not using `.len()` to avoid the cast from `usize`
|
||||
// to `u32`.
|
||||
Some(5)
|
||||
let coro_prefix = if let Some(sub) = string.strip_prefix("async") {
|
||||
let trimmed_sub = sub.trim_end();
|
||||
if trimmed_sub.ends_with("gen") {
|
||||
// `async` is 5 chars long.
|
||||
Some((trimmed_sub.len() + 5) as _)
|
||||
} else {
|
||||
// `async` is 5 chars long.
|
||||
Some(5)
|
||||
}
|
||||
} else if string.starts_with("gen") {
|
||||
// `gen` is 3 chars long
|
||||
Some(3)
|
||||
|
|
|
|||
|
|
@ -888,7 +888,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
// Skip `async` desugaring `impl Future`.
|
||||
}
|
||||
if let TyKind::TraitObject(_, lt) = alias_ty.kind {
|
||||
if lt.res == hir::LifetimeName::ImplicitObjectLifetimeDefault {
|
||||
if lt.kind == hir::LifetimeKind::ImplicitObjectLifetimeDefault {
|
||||
spans_suggs.push((lt.ident.span.shrink_to_hi(), " + 'a".to_string()));
|
||||
} else {
|
||||
spans_suggs.push((lt.ident.span, "'a".to_string()));
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
|
||||
#![doc(rust_logo)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
|
|
@ -22,6 +21,7 @@ use std::cell::RefCell;
|
|||
use std::marker::PhantomData;
|
||||
use std::ops::{ControlFlow, Deref};
|
||||
|
||||
use borrow_set::LocalsStateAtExit;
|
||||
use root_cx::BorrowCheckRootCtxt;
|
||||
use rustc_abi::FieldIdx;
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
|
|
@ -304,33 +304,13 @@ fn do_mir_borrowck<'tcx>(
|
|||
root_cx.set_tainted_by_errors(e);
|
||||
}
|
||||
|
||||
let mut local_names = IndexVec::from_elem(None, &input_body.local_decls);
|
||||
for var_debug_info in &input_body.var_debug_info {
|
||||
if let VarDebugInfoContents::Place(place) = var_debug_info.value {
|
||||
if let Some(local) = place.as_local() {
|
||||
if let Some(prev_name) = local_names[local]
|
||||
&& var_debug_info.name != prev_name
|
||||
{
|
||||
span_bug!(
|
||||
var_debug_info.source_info.span,
|
||||
"local {:?} has many names (`{}` vs `{}`)",
|
||||
local,
|
||||
prev_name,
|
||||
var_debug_info.name
|
||||
);
|
||||
}
|
||||
local_names[local] = Some(var_debug_info.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Replace all regions with fresh inference variables. This
|
||||
// requires first making our own copy of the MIR. This copy will
|
||||
// be modified (in place) to contain non-lexical lifetimes. It
|
||||
// will have a lifetime tied to the inference context.
|
||||
let mut body_owned = input_body.clone();
|
||||
let mut promoted = input_promoted.to_owned();
|
||||
let free_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted);
|
||||
let universal_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted);
|
||||
let body = &body_owned; // no further changes
|
||||
|
||||
let location_table = PoloniusLocationTable::new(body);
|
||||
|
|
@ -355,7 +335,7 @@ fn do_mir_borrowck<'tcx>(
|
|||
} = nll::compute_regions(
|
||||
root_cx,
|
||||
&infcx,
|
||||
free_regions,
|
||||
universal_regions,
|
||||
body,
|
||||
&promoted,
|
||||
&location_table,
|
||||
|
|
@ -368,24 +348,23 @@ fn do_mir_borrowck<'tcx>(
|
|||
// Dump MIR results into a file, if that is enabled. This lets us
|
||||
// write unit-tests, as well as helping with debugging.
|
||||
nll::dump_nll_mir(&infcx, body, ®ioncx, &opt_closure_req, &borrow_set);
|
||||
polonius::dump_polonius_mir(
|
||||
&infcx,
|
||||
body,
|
||||
®ioncx,
|
||||
&opt_closure_req,
|
||||
&borrow_set,
|
||||
polonius_diagnostics.as_ref(),
|
||||
);
|
||||
|
||||
// We also have a `#[rustc_regions]` annotation that causes us to dump
|
||||
// information.
|
||||
nll::dump_annotation(&infcx, body, ®ioncx, &opt_closure_req);
|
||||
|
||||
let movable_coroutine = body.coroutine.is_some()
|
||||
&& tcx.coroutine_movability(def.to_def_id()) == hir::Movability::Movable;
|
||||
|
||||
let diags_buffer = &mut BorrowckDiagnosticsBuffer::default();
|
||||
nll::dump_annotation(&infcx, body, ®ioncx, &opt_closure_req, diags_buffer);
|
||||
|
||||
let movable_coroutine =
|
||||
// The first argument is the coroutine type passed by value
|
||||
if let Some(local) = body.local_decls.raw.get(1)
|
||||
// Get the interior types and args which typeck computed
|
||||
&& let ty::Coroutine(def_id, _) = *local.ty.kind()
|
||||
&& tcx.coroutine_movability(def_id) == hir::Movability::Movable
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
// While promoteds should mostly be correct by construction, we need to check them for
|
||||
// invalid moves to detect moving out of arrays:`struct S; fn main() { &([S][0]); }`.
|
||||
for promoted_body in &promoted {
|
||||
|
|
@ -403,7 +382,6 @@ fn do_mir_borrowck<'tcx>(
|
|||
location_table: &location_table,
|
||||
movable_coroutine,
|
||||
fn_self_span_reported: Default::default(),
|
||||
locals_are_invalidated_at_exit,
|
||||
access_place_error_reported: Default::default(),
|
||||
reservation_error_reported: Default::default(),
|
||||
uninitialized_error_reported: Default::default(),
|
||||
|
|
@ -435,6 +413,26 @@ fn do_mir_borrowck<'tcx>(
|
|||
promoted_mbcx.report_move_errors();
|
||||
}
|
||||
|
||||
let mut local_names = IndexVec::from_elem(None, &body.local_decls);
|
||||
for var_debug_info in &body.var_debug_info {
|
||||
if let VarDebugInfoContents::Place(place) = var_debug_info.value {
|
||||
if let Some(local) = place.as_local() {
|
||||
if let Some(prev_name) = local_names[local]
|
||||
&& var_debug_info.name != prev_name
|
||||
{
|
||||
span_bug!(
|
||||
var_debug_info.source_info.span,
|
||||
"local {:?} has many names (`{}` vs `{}`)",
|
||||
local,
|
||||
prev_name,
|
||||
var_debug_info.name
|
||||
);
|
||||
}
|
||||
local_names[local] = Some(var_debug_info.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut mbcx = MirBorrowckCtxt {
|
||||
root_cx,
|
||||
infcx: &infcx,
|
||||
|
|
@ -442,7 +440,6 @@ fn do_mir_borrowck<'tcx>(
|
|||
move_data: &move_data,
|
||||
location_table: &location_table,
|
||||
movable_coroutine,
|
||||
locals_are_invalidated_at_exit,
|
||||
fn_self_span_reported: Default::default(),
|
||||
access_place_error_reported: Default::default(),
|
||||
reservation_error_reported: Default::default(),
|
||||
|
|
@ -455,9 +452,9 @@ fn do_mir_borrowck<'tcx>(
|
|||
local_names,
|
||||
region_names: RefCell::default(),
|
||||
next_region_name: RefCell::new(1),
|
||||
polonius_output,
|
||||
move_errors: Vec::new(),
|
||||
diags_buffer,
|
||||
polonius_output: polonius_output.as_deref(),
|
||||
polonius_diagnostics: polonius_diagnostics.as_ref(),
|
||||
};
|
||||
|
||||
|
|
@ -474,16 +471,6 @@ fn do_mir_borrowck<'tcx>(
|
|||
|
||||
mbcx.report_move_errors();
|
||||
|
||||
// If requested, dump polonius MIR.
|
||||
polonius::dump_polonius_mir(
|
||||
&infcx,
|
||||
body,
|
||||
®ioncx,
|
||||
&borrow_set,
|
||||
polonius_diagnostics.as_ref(),
|
||||
&opt_closure_req,
|
||||
);
|
||||
|
||||
// For each non-user used mutable variable, check if it's been assigned from
|
||||
// a user-declared local. If so, then put that local into the used_mut set.
|
||||
// Note that this set is expected to be small - only upvars from closures
|
||||
|
|
@ -514,7 +501,6 @@ fn do_mir_borrowck<'tcx>(
|
|||
};
|
||||
|
||||
let body_with_facts = if consumer_options.is_some() {
|
||||
let output_facts = mbcx.polonius_output;
|
||||
Some(Box::new(BodyWithBorrowckFacts {
|
||||
body: body_owned,
|
||||
promoted,
|
||||
|
|
@ -522,7 +508,7 @@ fn do_mir_borrowck<'tcx>(
|
|||
region_inference_context: regioncx,
|
||||
location_table: polonius_input.as_ref().map(|_| location_table),
|
||||
input_facts: polonius_input,
|
||||
output_facts,
|
||||
output_facts: polonius_output,
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
|
|
@ -655,13 +641,6 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
|
|||
location_table: &'a PoloniusLocationTable,
|
||||
|
||||
movable_coroutine: bool,
|
||||
/// This keeps track of whether local variables are free-ed when the function
|
||||
/// exits even without a `StorageDead`, which appears to be the case for
|
||||
/// constants.
|
||||
///
|
||||
/// I'm not sure this is the right approach - @eddyb could you try and
|
||||
/// figure this out?
|
||||
locals_are_invalidated_at_exit: bool,
|
||||
/// This field keeps track of when borrow errors are reported in the access_place function
|
||||
/// so that there is no duplicate reporting. This field cannot also be used for the conflicting
|
||||
/// borrow errors that is handled by the `reservation_error_reported` field as the inclusion
|
||||
|
|
@ -709,12 +688,11 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
|
|||
/// The counter for generating new region names.
|
||||
next_region_name: RefCell<usize>,
|
||||
|
||||
/// Results of Polonius analysis.
|
||||
polonius_output: Option<Box<PoloniusOutput>>,
|
||||
|
||||
diags_buffer: &'a mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>,
|
||||
move_errors: Vec<MoveError<'tcx>>,
|
||||
|
||||
/// Results of Polonius analysis.
|
||||
polonius_output: Option<&'a PoloniusOutput>,
|
||||
/// When using `-Zpolonius=next`: the data used to compute errors and diagnostics.
|
||||
polonius_diagnostics: Option<&'a PoloniusDiagnosticsContext>,
|
||||
}
|
||||
|
|
@ -938,13 +916,20 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<
|
|||
| TerminatorKind::Return
|
||||
| TerminatorKind::TailCall { .. }
|
||||
| TerminatorKind::CoroutineDrop => {
|
||||
// Returning from the function implicitly kills storage for all locals and statics.
|
||||
// Often, the storage will already have been killed by an explicit
|
||||
// StorageDead, but we don't always emit those (notably on unwind paths),
|
||||
// so this "extra check" serves as a kind of backup.
|
||||
for i in state.borrows.iter() {
|
||||
let borrow = &self.borrow_set[i];
|
||||
self.check_for_invalidation_at_exit(loc, borrow, span);
|
||||
match self.borrow_set.locals_state_at_exit() {
|
||||
LocalsStateAtExit::AllAreInvalidated => {
|
||||
// Returning from the function implicitly kills storage for all locals and statics.
|
||||
// Often, the storage will already have been killed by an explicit
|
||||
// StorageDead, but we don't always emit those (notably on unwind paths),
|
||||
// so this "extra check" serves as a kind of backup.
|
||||
for i in state.borrows.iter() {
|
||||
let borrow = &self.borrow_set[i];
|
||||
self.check_for_invalidation_at_exit(loc, borrow, span);
|
||||
}
|
||||
}
|
||||
// If we do not implicitly invalidate all locals on exit,
|
||||
// we check for conflicts when dropping or moving this local.
|
||||
LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved: _ } => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1301,7 +1286,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
error_reported
|
||||
}
|
||||
|
||||
/// Through #123739, backward incompatible drops (BIDs) are introduced.
|
||||
/// Through #123739, `BackwardIncompatibleDropHint`s (BIDs) are introduced.
|
||||
/// We would like to emit lints whether borrow checking fails at these future drop locations.
|
||||
#[instrument(level = "debug", skip(self, state))]
|
||||
fn check_backward_incompatible_drop(
|
||||
|
|
@ -1716,22 +1701,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
// we'll have a memory leak) and assume that all statics have a destructor.
|
||||
//
|
||||
// FIXME: allow thread-locals to borrow other thread locals?
|
||||
|
||||
let (might_be_alive, will_be_dropped) =
|
||||
if self.body.local_decls[root_place.local].is_ref_to_thread_local() {
|
||||
// Thread-locals might be dropped after the function exits
|
||||
// We have to dereference the outer reference because
|
||||
// borrows don't conflict behind shared references.
|
||||
root_place.projection = TyCtxtConsts::DEREF_PROJECTION;
|
||||
(true, true)
|
||||
} else {
|
||||
(false, self.locals_are_invalidated_at_exit)
|
||||
};
|
||||
|
||||
if !will_be_dropped {
|
||||
debug!("place_is_invalidated_at_exit({:?}) - won't be dropped", place);
|
||||
return;
|
||||
}
|
||||
let might_be_alive = if self.body.local_decls[root_place.local].is_ref_to_thread_local() {
|
||||
// Thread-locals might be dropped after the function exits
|
||||
// We have to dereference the outer reference because
|
||||
// borrows don't conflict behind shared references.
|
||||
root_place.projection = TyCtxtConsts::DEREF_PROJECTION;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let sd = if might_be_alive { Deep } else { Shallow(None) };
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ use tracing::{debug, instrument};
|
|||
|
||||
use crate::borrow_set::BorrowSet;
|
||||
use crate::consumers::ConsumerOptions;
|
||||
use crate::diagnostics::{BorrowckDiagnosticsBuffer, RegionErrors};
|
||||
use crate::diagnostics::RegionErrors;
|
||||
use crate::polonius::PoloniusDiagnosticsContext;
|
||||
use crate::polonius::legacy::{
|
||||
PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
|
||||
|
|
@ -117,11 +117,6 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
Rc::clone(&location_map),
|
||||
);
|
||||
|
||||
// Create the region inference context, taking ownership of the
|
||||
// region inference data that was contained in `infcx`, and the
|
||||
// base constraints generated by the type-check.
|
||||
let var_infos = infcx.get_region_var_infos();
|
||||
|
||||
// If requested, emit legacy polonius facts.
|
||||
polonius::legacy::emit_facts(
|
||||
&mut polonius_facts,
|
||||
|
|
@ -134,13 +129,8 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
&constraints,
|
||||
);
|
||||
|
||||
let mut regioncx = RegionInferenceContext::new(
|
||||
infcx,
|
||||
var_infos,
|
||||
constraints,
|
||||
universal_region_relations,
|
||||
location_map,
|
||||
);
|
||||
let mut regioncx =
|
||||
RegionInferenceContext::new(infcx, constraints, universal_region_relations, location_map);
|
||||
|
||||
// If requested for `-Zpolonius=next`, convert NLL constraints to localized outlives constraints
|
||||
// and use them to compute loan liveness.
|
||||
|
|
@ -297,7 +287,6 @@ pub(super) fn dump_annotation<'tcx, 'infcx>(
|
|||
body: &Body<'tcx>,
|
||||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
|
||||
diagnostics_buffer: &mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>,
|
||||
) {
|
||||
let tcx = infcx.tcx;
|
||||
let base_def_id = tcx.typeck_root_def_id(body.source.def_id());
|
||||
|
|
@ -335,13 +324,11 @@ pub(super) fn dump_annotation<'tcx, 'infcx>(
|
|||
} else {
|
||||
let mut err = infcx.dcx().struct_span_note(def_span, "no external requirements");
|
||||
regioncx.annotate(tcx, &mut err);
|
||||
|
||||
err
|
||||
};
|
||||
|
||||
// FIXME(@lcnr): We currently don't dump the inferred hidden types here.
|
||||
|
||||
diagnostics_buffer.buffer_non_error(err);
|
||||
err.emit();
|
||||
}
|
||||
|
||||
fn for_each_region_constraint<'tcx>(
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@ pub(crate) fn dump_polonius_mir<'tcx>(
|
|||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
polonius_diagnostics: Option<&PoloniusDiagnosticsContext>,
|
||||
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
|
||||
) {
|
||||
let tcx = infcx.tcx;
|
||||
if !tcx.sess.opts.unstable_opts.polonius.is_next_enabled() {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use rustc_errors::Diag;
|
|||
use rustc_hir::def_id::CRATE_DEF_ID;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_infer::infer::outlives::test_type_match;
|
||||
use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq};
|
||||
use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound, VerifyIfEq};
|
||||
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::{
|
||||
|
|
@ -145,7 +145,7 @@ pub struct RegionInferenceContext<'tcx> {
|
|||
/// variables are identified by their index (`RegionVid`). The
|
||||
/// definition contains information about where the region came
|
||||
/// from as well as its final inferred value.
|
||||
pub(crate) definitions: IndexVec<RegionVid, RegionDefinition<'tcx>>,
|
||||
pub(crate) definitions: Frozen<IndexVec<RegionVid, RegionDefinition<'tcx>>>,
|
||||
|
||||
/// The liveness constraints added to each region. For most
|
||||
/// regions, these start out empty and steadily grow, though for
|
||||
|
|
@ -338,8 +338,7 @@ fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: &ConstraintSccs) {
|
|||
let num_components = sccs.num_sccs();
|
||||
let mut components = vec![FxIndexSet::default(); num_components];
|
||||
|
||||
for (reg_var_idx, scc_idx) in sccs.scc_indices().iter().enumerate() {
|
||||
let reg_var = ty::RegionVid::from_usize(reg_var_idx);
|
||||
for (reg_var, scc_idx) in sccs.scc_indices().iter_enumerated() {
|
||||
let origin = var_to_origin.get(®_var).unwrap_or(&RegionCtxt::Unknown);
|
||||
components[scc_idx.as_usize()].insert((reg_var, *origin));
|
||||
}
|
||||
|
|
@ -385,6 +384,26 @@ fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: &ConstraintSccs) {
|
|||
debug!("SCC edges {:#?}", scc_node_to_edges);
|
||||
}
|
||||
|
||||
fn create_definitions<'tcx>(
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
universal_regions: &UniversalRegions<'tcx>,
|
||||
) -> Frozen<IndexVec<RegionVid, RegionDefinition<'tcx>>> {
|
||||
// Create a RegionDefinition for each inference variable.
|
||||
let mut definitions: IndexVec<_, _> = infcx
|
||||
.get_region_var_infos()
|
||||
.iter()
|
||||
.map(|info| RegionDefinition::new(info.universe, info.origin))
|
||||
.collect();
|
||||
|
||||
// Add the external name for all universal regions.
|
||||
for (external_name, variable) in universal_regions.named_universal_regions_iter() {
|
||||
debug!("region {variable:?} has external name {external_name:?}");
|
||||
definitions[variable].external_name = Some(external_name);
|
||||
}
|
||||
|
||||
Frozen::freeze(definitions)
|
||||
}
|
||||
|
||||
impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
/// Creates a new region inference context with a total of
|
||||
/// `num_region_variables` valid inference variables; the first N
|
||||
|
|
@ -395,7 +414,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
/// of constraints produced by the MIR type check.
|
||||
pub(crate) fn new(
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
var_infos: VarInfos,
|
||||
constraints: MirTypeckRegionConstraints<'tcx>,
|
||||
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
|
||||
location_map: Rc<DenseLocationMap>,
|
||||
|
|
@ -426,11 +444,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
infcx.set_tainted_by_errors(guar);
|
||||
}
|
||||
|
||||
// Create a RegionDefinition for each inference variable.
|
||||
let definitions: IndexVec<_, _> = var_infos
|
||||
.iter()
|
||||
.map(|info| RegionDefinition::new(info.universe, info.origin))
|
||||
.collect();
|
||||
let definitions = create_definitions(infcx, &universal_regions);
|
||||
|
||||
let constraint_sccs =
|
||||
outlives_constraints.add_outlives_static(&universal_regions, &definitions);
|
||||
|
|
@ -526,18 +540,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
/// means that the `R1: !1` constraint here will cause
|
||||
/// `R1` to become `'static`.
|
||||
fn init_free_and_bound_regions(&mut self) {
|
||||
// Update the names (if any)
|
||||
// This iterator has unstable order but we collect it all into an IndexVec
|
||||
for (external_name, variable) in
|
||||
self.universal_region_relations.universal_regions.named_universal_regions_iter()
|
||||
{
|
||||
debug!(
|
||||
"init_free_and_bound_regions: region {:?} has external name {:?}",
|
||||
variable, external_name
|
||||
);
|
||||
self.definitions[variable].external_name = Some(external_name);
|
||||
}
|
||||
|
||||
for variable in self.definitions.indices() {
|
||||
let scc = self.constraint_sccs.scc(variable);
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ use crate::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategor
|
|||
|
||||
pub(crate) struct ConstraintConversion<'a, 'tcx> {
|
||||
infcx: &'a InferCtxt<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
universal_regions: &'a UniversalRegions<'tcx>,
|
||||
/// Each RBP `GK: 'a` is assumed to be true. These encode
|
||||
/// relationships like `T: 'a` that are added via implicit bounds
|
||||
|
|
@ -34,7 +33,6 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> {
|
|||
/// logic expecting to see (e.g.) `ReStatic`, and if we supplied
|
||||
/// 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: &'a [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
locations: Locations,
|
||||
|
|
@ -49,7 +47,6 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
infcx: &'a InferCtxt<'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: &'a [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
locations: Locations,
|
||||
|
|
@ -59,10 +56,8 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
) -> Self {
|
||||
Self {
|
||||
infcx,
|
||||
tcx: infcx.tcx,
|
||||
universal_regions,
|
||||
region_bound_pairs,
|
||||
implicit_region_bound,
|
||||
param_env,
|
||||
known_type_outlives_obligations,
|
||||
locations,
|
||||
|
|
@ -96,7 +91,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
// into a vector. These are the regions that we will be
|
||||
// relating to one another.
|
||||
let closure_mapping = &UniversalRegions::closure_mapping(
|
||||
self.tcx,
|
||||
self.infcx.tcx,
|
||||
closure_args,
|
||||
closure_requirements.num_external_vids,
|
||||
closure_def_id,
|
||||
|
|
@ -111,7 +106,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
let subject = match outlives_requirement.subject {
|
||||
ClosureOutlivesSubject::Region(re) => closure_mapping[re].into(),
|
||||
ClosureOutlivesSubject::Ty(subject_ty) => {
|
||||
subject_ty.instantiate(self.tcx, |vid| closure_mapping[vid]).into()
|
||||
subject_ty.instantiate(self.infcx.tcx, |vid| closure_mapping[vid]).into()
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -127,14 +122,14 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
predicate: ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>,
|
||||
constraint_category: ConstraintCategory<'tcx>,
|
||||
) {
|
||||
let tcx = self.infcx.tcx;
|
||||
debug!("generate: constraints at: {:#?}", self.locations);
|
||||
|
||||
// Extract out various useful fields we'll need below.
|
||||
let ConstraintConversion {
|
||||
tcx,
|
||||
infcx,
|
||||
universal_regions,
|
||||
region_bound_pairs,
|
||||
implicit_region_bound,
|
||||
known_type_outlives_obligations,
|
||||
..
|
||||
} = *self;
|
||||
|
|
@ -145,7 +140,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
break;
|
||||
}
|
||||
|
||||
if !self.tcx.recursion_limit().value_within_limit(iteration) {
|
||||
if !tcx.recursion_limit().value_within_limit(iteration) {
|
||||
bug!(
|
||||
"FIXME(-Znext-solver): Overflowed when processing region obligations: {outlives_predicates:#?}"
|
||||
);
|
||||
|
|
@ -170,10 +165,11 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
let implicit_region_bound =
|
||||
ty::Region::new_var(tcx, universal_regions.implicit_region_bound());
|
||||
// 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,
|
||||
|
|
@ -205,7 +201,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
/// are dealt with during trait solving.
|
||||
fn replace_placeholders_with_nll<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, value: T) -> T {
|
||||
if value.has_placeholders() {
|
||||
fold_regions(self.tcx, value, |r, _| match r.kind() {
|
||||
fold_regions(self.infcx.tcx, value, |r, _| match r.kind() {
|
||||
ty::RePlaceholder(placeholder) => {
|
||||
self.constraints.placeholder_region(self.infcx, placeholder)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,14 +49,12 @@ pub(crate) struct CreateResult<'tcx> {
|
|||
pub(crate) fn create<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
universal_regions: UniversalRegions<'tcx>,
|
||||
constraints: &mut MirTypeckRegionConstraints<'tcx>,
|
||||
) -> CreateResult<'tcx> {
|
||||
UniversalRegionRelationsBuilder {
|
||||
infcx,
|
||||
param_env,
|
||||
implicit_region_bound,
|
||||
constraints,
|
||||
universal_regions,
|
||||
region_bound_pairs: Default::default(),
|
||||
|
|
@ -181,7 +179,6 @@ struct UniversalRegionRelationsBuilder<'a, 'tcx> {
|
|||
infcx: &'a InferCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
universal_regions: UniversalRegions<'tcx>,
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
|
||||
|
||||
// outputs:
|
||||
|
|
@ -320,7 +317,6 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
|||
self.infcx,
|
||||
&self.universal_regions,
|
||||
&self.region_bound_pairs,
|
||||
self.implicit_region_bound,
|
||||
param_env,
|
||||
&known_type_outlives_obligations,
|
||||
Locations::All(span),
|
||||
|
|
|
|||
|
|
@ -113,7 +113,6 @@ pub(crate) fn type_check<'a, 'tcx>(
|
|||
move_data: &MoveData<'tcx>,
|
||||
location_map: Rc<DenseLocationMap>,
|
||||
) -> MirTypeckResults<'tcx> {
|
||||
let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body);
|
||||
let mut constraints = MirTypeckRegionConstraints {
|
||||
placeholder_indices: PlaceholderIndices::default(),
|
||||
placeholder_index_to_region: IndexVec::default(),
|
||||
|
|
@ -129,13 +128,7 @@ pub(crate) fn type_check<'a, 'tcx>(
|
|||
region_bound_pairs,
|
||||
normalized_inputs_and_output,
|
||||
known_type_outlives_obligations,
|
||||
} = free_region_relations::create(
|
||||
infcx,
|
||||
infcx.param_env,
|
||||
implicit_region_bound,
|
||||
universal_regions,
|
||||
&mut constraints,
|
||||
);
|
||||
} = free_region_relations::create(infcx, infcx.param_env, universal_regions, &mut constraints);
|
||||
|
||||
let pre_obligations = infcx.take_registered_region_obligations();
|
||||
assert!(
|
||||
|
|
@ -160,7 +153,6 @@ pub(crate) fn type_check<'a, 'tcx>(
|
|||
user_type_annotations: &body.user_type_annotations,
|
||||
region_bound_pairs,
|
||||
known_type_outlives_obligations,
|
||||
implicit_region_bound,
|
||||
reported_errors: Default::default(),
|
||||
universal_regions: &universal_region_relations.universal_regions,
|
||||
location_table,
|
||||
|
|
@ -226,7 +218,6 @@ struct TypeChecker<'a, 'tcx> {
|
|||
user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>,
|
||||
region_bound_pairs: RegionBoundPairs<'tcx>,
|
||||
known_type_outlives_obligations: Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
reported_errors: FxIndexSet<(Ty<'tcx>, Span)>,
|
||||
universal_regions: &'a UniversalRegions<'tcx>,
|
||||
location_table: &'a PoloniusLocationTable,
|
||||
|
|
@ -422,7 +413,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
self.infcx,
|
||||
self.universal_regions,
|
||||
&self.region_bound_pairs,
|
||||
self.implicit_region_bound,
|
||||
self.infcx.param_env,
|
||||
&self.known_type_outlives_obligations,
|
||||
locations,
|
||||
|
|
@ -1567,11 +1557,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
CastKind::Transmute => {
|
||||
span_mirbug!(
|
||||
self,
|
||||
rvalue,
|
||||
"Unexpected CastKind::Transmute, which is not permitted in Analysis MIR",
|
||||
);
|
||||
let ty_from = op.ty(self.body, tcx);
|
||||
match ty_from.kind() {
|
||||
ty::Pat(base, _) if base == ty => {}
|
||||
_ => span_mirbug!(
|
||||
self,
|
||||
rvalue,
|
||||
"Unexpected CastKind::Transmute {ty_from:?} -> {ty:?}, which is not permitted in Analysis MIR",
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2507,7 +2501,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
self.infcx,
|
||||
self.universal_regions,
|
||||
&self.region_bound_pairs,
|
||||
self.implicit_region_bound,
|
||||
self.infcx.param_env,
|
||||
&self.known_type_outlives_obligations,
|
||||
locations,
|
||||
|
|
|
|||
|
|
@ -438,6 +438,10 @@ impl<'tcx> UniversalRegions<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn implicit_region_bound(&self) -> RegionVid {
|
||||
self.fr_fn_body
|
||||
}
|
||||
|
||||
pub(crate) fn tainted_by_errors(&self) -> Option<ErrorGuaranteed> {
|
||||
self.indices.tainted_by_errors.get()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -231,8 +231,6 @@ builtin_macros_format_unused_args = multiple unused formatting arguments
|
|||
|
||||
builtin_macros_format_use_positional = consider using a positional formatting argument instead
|
||||
|
||||
builtin_macros_invalid_crate_attribute = invalid crate attribute
|
||||
|
||||
builtin_macros_multiple_default_attrs = multiple `#[default]` attributes
|
||||
.note = only one `#[default]` attribute is needed
|
||||
.label = `#[default]` used here
|
||||
|
|
|
|||
|
|
@ -92,11 +92,7 @@ impl CfgEval<'_> {
|
|||
// the location of `#[cfg]` and `#[cfg_attr]` in the token stream. The tokenization
|
||||
// process is lossless, so this process is invisible to proc-macros.
|
||||
|
||||
// 'Flatten' all nonterminals (i.e. `TokenKind::Interpolated`)
|
||||
// to `None`-delimited groups containing the corresponding tokens. This
|
||||
// is normally delayed until the proc-macro server actually needs to
|
||||
// provide a `TokenKind::Interpolated` to a proc-macro. We do this earlier,
|
||||
// so that we can handle cases like:
|
||||
// Interesting cases:
|
||||
//
|
||||
// ```rust
|
||||
// #[cfg_eval] #[cfg] $item
|
||||
|
|
@ -104,8 +100,8 @@ impl CfgEval<'_> {
|
|||
//
|
||||
// where `$item` is `#[cfg_attr] struct Foo {}`. We want to make
|
||||
// sure to evaluate *all* `#[cfg]` and `#[cfg_attr]` attributes - the simplest
|
||||
// way to do this is to do a single parse of a stream without any nonterminals.
|
||||
let orig_tokens = annotatable.to_tokens().flattened();
|
||||
// way to do this is to do a single parse of the token stream.
|
||||
let orig_tokens = annotatable.to_tokens();
|
||||
|
||||
// Re-parse the tokens, setting the `capture_cfg` flag to save extra information
|
||||
// to the captured `AttrTokenStream` (specifically, we capture
|
||||
|
|
|
|||
|
|
@ -1,44 +1,37 @@
|
|||
//! Attributes injected into the crate root from command line using `-Z crate-attr`.
|
||||
|
||||
use rustc_ast::attr::mk_attr;
|
||||
use rustc_ast::{self as ast, AttrItem, AttrStyle, token};
|
||||
use rustc_parse::parser::ForceCollect;
|
||||
use rustc_parse::{new_parser_from_source_str, unwrap_or_emit_fatal};
|
||||
use rustc_ast::{self as ast};
|
||||
use rustc_errors::Diag;
|
||||
use rustc_parse::parser::attr::InnerAttrPolicy;
|
||||
use rustc_parse::{parse_in, source_str_to_stream};
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::FileName;
|
||||
|
||||
use crate::errors;
|
||||
|
||||
pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) {
|
||||
for raw_attr in attrs {
|
||||
let mut parser = unwrap_or_emit_fatal(new_parser_from_source_str(
|
||||
psess,
|
||||
FileName::cli_crate_attr_source_code(raw_attr),
|
||||
raw_attr.clone(),
|
||||
));
|
||||
|
||||
let start_span = parser.token.span;
|
||||
let AttrItem { unsafety, path, args, tokens: _ } =
|
||||
match parser.parse_attr_item(ForceCollect::No) {
|
||||
Ok(ai) => ai,
|
||||
Err(err) => {
|
||||
let source = format!("#![{raw_attr}]");
|
||||
let parse = || -> Result<ast::Attribute, Vec<Diag<'_>>> {
|
||||
let tokens = source_str_to_stream(
|
||||
psess,
|
||||
FileName::cli_crate_attr_source_code(raw_attr),
|
||||
source,
|
||||
None,
|
||||
)?;
|
||||
parse_in(psess, tokens, "<crate attribute>", |p| {
|
||||
p.parse_attribute(InnerAttrPolicy::Permitted)
|
||||
})
|
||||
.map_err(|e| vec![e])
|
||||
};
|
||||
let meta = match parse() {
|
||||
Ok(meta) => meta,
|
||||
Err(errs) => {
|
||||
for err in errs {
|
||||
err.emit();
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let end_span = parser.token.span;
|
||||
if parser.token != token::Eof {
|
||||
psess.dcx().emit_err(errors::InvalidCrateAttr { span: start_span.to(end_span) });
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
krate.attrs.push(mk_attr(
|
||||
&psess.attr_id_generator,
|
||||
AttrStyle::Inner,
|
||||
unsafety,
|
||||
path,
|
||||
args,
|
||||
start_span.to(end_span),
|
||||
));
|
||||
krate.attrs.push(meta);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{
|
||||
Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan, SingleLabelManySpans,
|
||||
SubdiagMessageOp, Subdiagnostic,
|
||||
Subdiagnostic,
|
||||
};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_span::{Ident, Span, Symbol};
|
||||
|
|
@ -109,13 +109,6 @@ pub(crate) struct ProcMacro {
|
|||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_invalid_crate_attribute)]
|
||||
pub(crate) struct InvalidCrateAttr {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_non_abi)]
|
||||
pub(crate) struct NonABI {
|
||||
|
|
@ -691,13 +684,9 @@ pub(crate) struct FormatUnusedArg {
|
|||
// Allow the singular form to be a subdiagnostic of the multiple-unused
|
||||
// form of diagnostic.
|
||||
impl Subdiagnostic for FormatUnusedArg {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
f: &F,
|
||||
) {
|
||||
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
|
||||
diag.arg("named", self.named);
|
||||
let msg = f(diag, crate::fluent_generated::builtin_macros_format_unused_arg.into());
|
||||
let msg = diag.eagerly_translate(crate::fluent_generated::builtin_macros_format_unused_arg);
|
||||
diag.span_label(self.span, msg);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
#![allow(internal_features)]
|
||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(assert_matches)]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_middle::ty::{AssocKind, GenericArg};
|
||||
use rustc_middle::ty::{AssocTag, GenericArg};
|
||||
use rustc_session::config::EntryFnType;
|
||||
use rustc_span::{DUMMY_SP, Ident};
|
||||
|
||||
|
|
@ -107,7 +107,7 @@ pub(crate) fn maybe_create_entry_wrapper(
|
|||
.find_by_ident_and_kind(
|
||||
tcx,
|
||||
Ident::from_str("report"),
|
||||
AssocKind::Fn,
|
||||
AssocTag::Fn,
|
||||
termination_trait,
|
||||
)
|
||||
.unwrap();
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ use std::collections::hash_map::Entry;
|
|||
use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext};
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_index::Idx;
|
||||
use rustc_index::bit_set::DenseBitSet;
|
||||
use rustc_middle::mir::{Body, SourceScope};
|
||||
use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv};
|
||||
|
|
@ -43,8 +42,7 @@ pub(crate) fn compute_mir_scopes<'ll, 'tcx>(
|
|||
let mut instantiated = DenseBitSet::new_empty(mir.source_scopes.len());
|
||||
let mut discriminators = FxHashMap::default();
|
||||
// Instantiate all scopes.
|
||||
for idx in 0..mir.source_scopes.len() {
|
||||
let scope = SourceScope::new(idx);
|
||||
for scope in mir.source_scopes.indices() {
|
||||
make_mir_scope(
|
||||
cx,
|
||||
instance,
|
||||
|
|
|
|||
|
|
@ -1315,31 +1315,21 @@ fn build_generic_type_param_di_nodes<'ll, 'tcx>(
|
|||
ty: Ty<'tcx>,
|
||||
) -> SmallVec<Option<&'ll DIType>> {
|
||||
if let ty::Adt(def, args) = *ty.kind() {
|
||||
let generics = cx.tcx.generics_of(def.did());
|
||||
return get_template_parameters(cx, generics, args);
|
||||
}
|
||||
|
||||
return smallvec![];
|
||||
}
|
||||
|
||||
pub(super) fn get_template_parameters<'ll, 'tcx>(
|
||||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
generics: &ty::Generics,
|
||||
args: ty::GenericArgsRef<'tcx>,
|
||||
) -> SmallVec<Option<&'ll DIType>> {
|
||||
if args.types().next().is_some() {
|
||||
let names = get_parameter_names(cx, generics);
|
||||
let template_params: SmallVec<_> = iter::zip(args, names)
|
||||
.filter_map(|(kind, name)| {
|
||||
kind.as_type().map(|ty| {
|
||||
let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
|
||||
let actual_type_di_node = type_di_node(cx, actual_type);
|
||||
Some(cx.create_template_type_parameter(name.as_str(), actual_type_di_node))
|
||||
if args.types().next().is_some() {
|
||||
let generics = cx.tcx.generics_of(def.did());
|
||||
let names = get_parameter_names(cx, generics);
|
||||
let template_params: SmallVec<_> = iter::zip(args, names)
|
||||
.filter_map(|(kind, name)| {
|
||||
kind.as_type().map(|ty| {
|
||||
let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
|
||||
let actual_type_di_node = type_di_node(cx, actual_type);
|
||||
Some(cx.create_template_type_parameter(name.as_str(), actual_type_di_node))
|
||||
})
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
.collect();
|
||||
|
||||
return template_params;
|
||||
return template_params;
|
||||
}
|
||||
}
|
||||
|
||||
return smallvec![];
|
||||
|
|
|
|||
|
|
@ -363,7 +363,6 @@ fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>(
|
|||
|
||||
state_specific_fields.into_iter().chain(common_fields).collect()
|
||||
},
|
||||
// FIXME: this is a no-op. `build_generic_type_param_di_nodes` only works for Adts.
|
||||
|cx| build_generic_type_param_di_nodes(cx, coroutine_type_and_layout.ty),
|
||||
)
|
||||
.di_node
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
use std::cell::{OnceCell, RefCell};
|
||||
use std::ops::Range;
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
use std::{iter, ptr};
|
||||
|
||||
use libc::c_uint;
|
||||
use metadata::create_subroutine_type;
|
||||
|
|
@ -486,10 +486,40 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
generics: &ty::Generics,
|
||||
args: GenericArgsRef<'tcx>,
|
||||
) -> &'ll DIArray {
|
||||
let template_params = metadata::get_template_parameters(cx, generics, args);
|
||||
if args.types().next().is_none() {
|
||||
return create_DIArray(DIB(cx), &[]);
|
||||
}
|
||||
|
||||
// Again, only create type information if full debuginfo is enabled
|
||||
let template_params: Vec<_> = if cx.sess().opts.debuginfo == DebugInfo::Full {
|
||||
let names = get_parameter_names(cx, generics);
|
||||
iter::zip(args, names)
|
||||
.filter_map(|(kind, name)| {
|
||||
kind.as_type().map(|ty| {
|
||||
let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
|
||||
let actual_type_metadata = type_di_node(cx, actual_type);
|
||||
Some(cx.create_template_type_parameter(
|
||||
name.as_str(),
|
||||
actual_type_metadata,
|
||||
))
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
create_DIArray(DIB(cx), &template_params)
|
||||
}
|
||||
|
||||
fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec<Symbol> {
|
||||
let mut names = generics.parent.map_or_else(Vec::new, |def_id| {
|
||||
get_parameter_names(cx, cx.tcx.generics_of(def_id))
|
||||
});
|
||||
names.extend(generics.own_params.iter().map(|param| param.name));
|
||||
names
|
||||
}
|
||||
|
||||
/// Returns a scope, plus `true` if that's a type scope for "class" methods,
|
||||
/// otherwise `false` for plain namespace scopes.
|
||||
fn get_containing_scope<'ll, 'tcx>(
|
||||
|
|
|
|||
|
|
@ -114,7 +114,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
AttributeKind::Repr(reprs) => {
|
||||
codegen_fn_attrs.alignment = reprs
|
||||
.iter()
|
||||
.find_map(|(r, _)| if let ReprAlign(x) = r { Some(*x) } else { None });
|
||||
.filter_map(|(r, _)| if let ReprAlign(x) = r { Some(*x) } else { None })
|
||||
.max();
|
||||
}
|
||||
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
#![allow(internal_features)]
|
||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(assert_matches)]
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use rustc_abi::WrappingRange;
|
|||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{
|
||||
Diag, DiagArgValue, DiagCtxtHandle, DiagMessage, Diagnostic, EmissionGuarantee, Level,
|
||||
MultiSpan, SubdiagMessageOp, Subdiagnostic,
|
||||
MultiSpan, Subdiagnostic,
|
||||
};
|
||||
use rustc_hir::ConstContext;
|
||||
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
||||
|
|
@ -290,11 +290,7 @@ pub struct FrameNote {
|
|||
}
|
||||
|
||||
impl Subdiagnostic for FrameNote {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
f: &F,
|
||||
) {
|
||||
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
|
||||
diag.arg("times", self.times);
|
||||
diag.arg("where_", self.where_);
|
||||
diag.arg("instance", self.instance);
|
||||
|
|
@ -302,7 +298,7 @@ impl Subdiagnostic for FrameNote {
|
|||
if self.has_label && !self.span.is_dummy() {
|
||||
span.push_span_label(self.span, fluent::const_eval_frame_note_last);
|
||||
}
|
||||
let msg = f(diag, fluent::const_eval_frame_note.into());
|
||||
let msg = diag.eagerly_translate(fluent::const_eval_frame_note);
|
||||
diag.span_note(span, msg);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
|
||||
#![doc(rust_logo)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
use std::alloc::Allocator;
|
||||
|
||||
#[rustc_on_unimplemented(message = "`{Self}` doesn't implement `DynSend`. \
|
||||
#[diagnostic::on_unimplemented(message = "`{Self}` doesn't implement `DynSend`. \
|
||||
Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Send`")]
|
||||
// This is an auto trait for types which can be sent across threads if `sync::is_dyn_thread_safe()`
|
||||
// is true. These types can be wrapped in a `FromDyn` to get a `Send` type. Wrapping a
|
||||
// `Send` type in `IntoDynSyncSend` will create a `DynSend` type.
|
||||
pub unsafe auto trait DynSend {}
|
||||
|
||||
#[rustc_on_unimplemented(message = "`{Self}` doesn't implement `DynSync`. \
|
||||
#[diagnostic::on_unimplemented(message = "`{Self}` doesn't implement `DynSync`. \
|
||||
Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Sync`")]
|
||||
// This is an auto trait for types which can be shared across threads if `sync::is_dyn_thread_safe()`
|
||||
// is true. These types can be wrapped in a `FromDyn` to get a `Sync` type. Wrapping a
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
|
||||
#![doc(rust_logo)]
|
||||
#![feature(rustdoc_internals)]
|
||||
// tidy-alphabetical-end
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ version = "0.0.0"
|
|||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
jiff = { version = "0.2.5", default-features = false, features = ["std"] }
|
||||
# tidy-alphabetical-start
|
||||
rustc_abi = { path = "../rustc_abi" }
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
|
|
@ -50,7 +51,6 @@ rustc_trait_selection = { path = "../rustc_trait_selection" }
|
|||
rustc_ty_utils = { path = "../rustc_ty_utils" }
|
||||
serde_json = "1.0.59"
|
||||
shlex = "1.0"
|
||||
time = { version = "0.3.36", default-features = false, features = ["alloc", "formatting", "macros"] }
|
||||
tracing = { version = "0.1.35" }
|
||||
# tidy-alphabetical-end
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(decl_macro)]
|
||||
|
|
@ -30,7 +29,7 @@ use std::path::{Path, PathBuf};
|
|||
use std::process::{self, Command, Stdio};
|
||||
use std::sync::OnceLock;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::time::{Instant, SystemTime};
|
||||
use std::time::Instant;
|
||||
use std::{env, str};
|
||||
|
||||
use rustc_ast as ast;
|
||||
|
|
@ -66,8 +65,6 @@ use rustc_span::FileName;
|
|||
use rustc_span::def_id::LOCAL_CRATE;
|
||||
use rustc_target::json::ToJson;
|
||||
use rustc_target::spec::{Target, TargetTuple};
|
||||
use time::OffsetDateTime;
|
||||
use time::macros::format_description;
|
||||
use tracing::trace;
|
||||
|
||||
#[allow(unused_macros)]
|
||||
|
|
@ -1301,13 +1298,8 @@ fn ice_path_with_config(config: Option<&UnstableOptions>) -> &'static Option<Pat
|
|||
.or_else(|| std::env::current_dir().ok())
|
||||
.unwrap_or_default(),
|
||||
};
|
||||
let now: OffsetDateTime = SystemTime::now().into();
|
||||
let file_now = now
|
||||
.format(
|
||||
// Don't use a standard datetime format because Windows doesn't support `:` in paths
|
||||
&format_description!("[year]-[month]-[day]T[hour]_[minute]_[second]"),
|
||||
)
|
||||
.unwrap_or_default();
|
||||
// Don't use a standard datetime format because Windows doesn't support `:` in paths
|
||||
let file_now = jiff::Zoned::now().strftime("%Y-%m-%dT%H_%M_%S");
|
||||
let pid = std::process::id();
|
||||
path.push(format!("rustc-ice-{file_now}-{pid}.txt"));
|
||||
Some(path)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ Erroneous code example:
|
|||
```compile_fail,E0755
|
||||
#![feature(ffi_pure)]
|
||||
|
||||
#[ffi_pure] // error!
|
||||
#[unsafe(ffi_pure)] // error!
|
||||
pub fn foo() {}
|
||||
# fn main() {}
|
||||
```
|
||||
|
|
@ -17,7 +17,7 @@ side effects or infinite loops:
|
|||
#![feature(ffi_pure)]
|
||||
|
||||
extern "C" {
|
||||
#[ffi_pure] // ok!
|
||||
#[unsafe(ffi_pure)] // ok!
|
||||
pub fn strlen(s: *const i8) -> isize;
|
||||
}
|
||||
# fn main() {}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ Erroneous code example:
|
|||
```compile_fail,E0756
|
||||
#![feature(ffi_const)]
|
||||
|
||||
#[ffi_const] // error!
|
||||
#[unsafe(ffi_const)] // error!
|
||||
pub fn foo() {}
|
||||
# fn main() {}
|
||||
```
|
||||
|
|
@ -18,7 +18,7 @@ which have no side effects except for their return value:
|
|||
#![feature(ffi_const)]
|
||||
|
||||
extern "C" {
|
||||
#[ffi_const] // ok!
|
||||
#[unsafe(ffi_const)] // ok!
|
||||
pub fn strlen(s: *const i8) -> i32;
|
||||
}
|
||||
# fn main() {}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,9 @@ Erroneous code example:
|
|||
#![feature(ffi_const, ffi_pure)]
|
||||
|
||||
extern "C" {
|
||||
#[ffi_const]
|
||||
#[ffi_pure] // error: `#[ffi_const]` function cannot be `#[ffi_pure]`
|
||||
#[unsafe(ffi_const)]
|
||||
#[unsafe(ffi_pure)]
|
||||
//~^ ERROR `#[ffi_const]` function cannot be `#[ffi_pure]`
|
||||
pub fn square(num: i32) -> i32;
|
||||
}
|
||||
```
|
||||
|
|
@ -19,7 +20,7 @@ As `ffi_const` provides stronger guarantees than `ffi_pure`, remove the
|
|||
#![feature(ffi_const)]
|
||||
|
||||
extern "C" {
|
||||
#[ffi_const]
|
||||
#[unsafe(ffi_const)]
|
||||
pub fn square(num: i32) -> i32;
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -181,22 +181,9 @@ where
|
|||
Self: Sized,
|
||||
{
|
||||
/// Add a subdiagnostic to an existing diagnostic.
|
||||
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
|
||||
self.add_to_diag_with(diag, &|_, m| m);
|
||||
}
|
||||
|
||||
/// Add a subdiagnostic to an existing diagnostic where `f` is invoked on every message used
|
||||
/// (to optionally perform eager translation).
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
f: &F,
|
||||
);
|
||||
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>);
|
||||
}
|
||||
|
||||
pub trait SubdiagMessageOp<G: EmissionGuarantee> =
|
||||
Fn(&mut Diag<'_, G>, SubdiagMessage) -> SubdiagMessage;
|
||||
|
||||
/// Trait implemented by lint types. This should not be implemented manually. Instead, use
|
||||
/// `#[derive(LintDiagnostic)]` -- see [rustc_macros::LintDiagnostic].
|
||||
#[rustc_diagnostic_item = "LintDiagnostic"]
|
||||
|
|
@ -1227,15 +1214,21 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
|
|||
/// interpolated variables).
|
||||
#[rustc_lint_diagnostics]
|
||||
pub fn subdiagnostic(&mut self, subdiagnostic: impl Subdiagnostic) -> &mut Self {
|
||||
let dcx = self.dcx;
|
||||
subdiagnostic.add_to_diag_with(self, &|diag, msg| {
|
||||
let args = diag.args.iter();
|
||||
let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
|
||||
dcx.eagerly_translate(msg, args)
|
||||
});
|
||||
subdiagnostic.add_to_diag(self);
|
||||
self
|
||||
}
|
||||
|
||||
/// Fluent variables are not namespaced from each other, so when
|
||||
/// `Diagnostic`s and `Subdiagnostic`s use the same variable name,
|
||||
/// one value will clobber the other. Eagerly translating the
|
||||
/// diagnostic uses the variables defined right then, before the
|
||||
/// clobbering occurs.
|
||||
pub fn eagerly_translate(&self, msg: impl Into<SubdiagMessage>) -> SubdiagMessage {
|
||||
let args = self.args.iter();
|
||||
let msg = self.subdiagnostic_message_to_diagnostic_message(msg.into());
|
||||
self.dcx.eagerly_translate(msg, args)
|
||||
}
|
||||
|
||||
with_fn! { with_span,
|
||||
/// Add a span.
|
||||
#[rustc_lint_diagnostics]
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use {rustc_ast as ast, rustc_hir as hir};
|
|||
use crate::diagnostic::DiagLocation;
|
||||
use crate::{
|
||||
Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, ErrCode, IntoDiagArg, Level,
|
||||
SubdiagMessageOp, Subdiagnostic, fluent_generated as fluent,
|
||||
Subdiagnostic, fluent_generated as fluent,
|
||||
};
|
||||
|
||||
pub struct DiagArgFromDisplay<'a>(pub &'a dyn fmt::Display);
|
||||
|
|
@ -384,11 +384,7 @@ pub struct SingleLabelManySpans {
|
|||
pub label: &'static str,
|
||||
}
|
||||
impl Subdiagnostic for SingleLabelManySpans {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_: &F,
|
||||
) {
|
||||
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
|
||||
diag.span_labels(self.spans, self.label);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ pub use codes::*;
|
|||
pub use diagnostic::{
|
||||
BugAbort, Diag, DiagArg, DiagArgMap, DiagArgName, DiagArgValue, DiagInner, DiagStyledString,
|
||||
Diagnostic, EmissionGuarantee, FatalAbort, IntoDiagArg, LintDiagnostic, StringPart, Subdiag,
|
||||
SubdiagMessageOp, Subdiagnostic,
|
||||
Subdiagnostic,
|
||||
};
|
||||
pub use diagnostic_impls::{
|
||||
DiagArgFromDisplay, DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter,
|
||||
|
|
|
|||
|
|
@ -237,18 +237,6 @@ impl<'a> StripUnconfigured<'a> {
|
|||
inner = self.configure_tokens(&inner);
|
||||
Some(AttrTokenTree::Delimited(sp, spacing, delim, inner))
|
||||
}
|
||||
AttrTokenTree::Token(
|
||||
Token {
|
||||
kind:
|
||||
TokenKind::NtIdent(..)
|
||||
| TokenKind::NtLifetime(..)
|
||||
| TokenKind::Interpolated(..),
|
||||
..
|
||||
},
|
||||
_,
|
||||
) => {
|
||||
panic!("Nonterminal should have been flattened: {:?}", tree);
|
||||
}
|
||||
AttrTokenTree::Token(
|
||||
Token { kind: TokenKind::OpenDelim(_) | TokenKind::CloseDelim(_), .. },
|
||||
_,
|
||||
|
|
|
|||
|
|
@ -66,9 +66,7 @@ pub(super) fn failed_to_match_macro(
|
|||
}
|
||||
|
||||
if let MatcherLoc::Token { token: expected_token } = &remaining_matcher
|
||||
&& (matches!(expected_token.kind, TokenKind::Interpolated(_))
|
||||
|| matches!(token.kind, TokenKind::Interpolated(_))
|
||||
|| matches!(expected_token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_)))
|
||||
&& (matches!(expected_token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_)))
|
||||
|| matches!(token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_))))
|
||||
{
|
||||
err.note("captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens");
|
||||
|
|
@ -162,7 +160,7 @@ impl<'dcx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'dcx, 'match
|
|||
.is_none_or(|failure| failure.is_better_position(*approx_position))
|
||||
{
|
||||
self.best_failure = Some(BestFailure {
|
||||
token: token.clone(),
|
||||
token: *token,
|
||||
position_in_tokenstream: *approx_position,
|
||||
msg,
|
||||
remaining_matcher: self
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ pub(super) fn compute_locs(matcher: &[TokenTree]) -> Vec<MatcherLoc> {
|
|||
for tt in tts {
|
||||
match tt {
|
||||
TokenTree::Token(token) => {
|
||||
locs.push(MatcherLoc::Token { token: token.clone() });
|
||||
locs.push(MatcherLoc::Token { token: *token });
|
||||
}
|
||||
TokenTree::Delimited(span, _, delimited) => {
|
||||
let open_token = Token::new(token::OpenDelim(delimited.delim), span.open);
|
||||
|
|
@ -648,7 +648,7 @@ impl TtParser {
|
|||
// There are no possible next positions AND we aren't waiting for the black-box
|
||||
// parser: syntax error.
|
||||
return Failure(T::build_failure(
|
||||
parser.token.clone(),
|
||||
parser.token,
|
||||
parser.approx_token_stream_pos(),
|
||||
"no rules expected this token in macro call",
|
||||
));
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId};
|
|||
use rustc_ast_pretty::pprust;
|
||||
use rustc_attr_parsing::{AttributeKind, find_attr};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||
use rustc_errors::{Applicability, ErrorGuaranteed};
|
||||
use rustc_errors::{Applicability, Diag, ErrorGuaranteed};
|
||||
use rustc_feature::Features;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint_defs::BuiltinLintDiag;
|
||||
|
|
@ -27,19 +27,18 @@ use rustc_span::hygiene::Transparency;
|
|||
use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, kw, sym};
|
||||
use tracing::{debug, instrument, trace, trace_span};
|
||||
|
||||
use super::diagnostics;
|
||||
use super::macro_parser::{NamedMatches, NamedParseResult};
|
||||
use super::{SequenceRepetition, diagnostics};
|
||||
use crate::base::{
|
||||
DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult, SyntaxExtension,
|
||||
SyntaxExtensionKind, TTMacroExpander,
|
||||
};
|
||||
use crate::expand::{AstFragment, AstFragmentKind, ensure_complete_parse, parse_ast_fragment};
|
||||
use crate::mbe;
|
||||
use crate::mbe::diagnostics::{annotate_doc_comment, parse_failure_msg};
|
||||
use crate::mbe::macro_check;
|
||||
use crate::mbe::macro_parser::NamedMatch::*;
|
||||
use crate::mbe::macro_parser::{Error, ErrorReported, Failure, MatcherLoc, Success, TtParser};
|
||||
use crate::mbe::transcribe::transcribe;
|
||||
use crate::mbe::{self, KleeneOp, macro_check};
|
||||
|
||||
pub(crate) struct ParserAnyMacro<'a> {
|
||||
parser: Parser<'a>,
|
||||
|
|
@ -640,6 +639,37 @@ fn is_empty_token_tree(sess: &Session, seq: &mbe::SequenceRepetition) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
/// Checks if a `vis` nonterminal fragment is unnecessarily wrapped in an optional repetition.
|
||||
///
|
||||
/// When a `vis` fragment (which can already be empty) is wrapped in `$(...)?`,
|
||||
/// this suggests removing the redundant repetition syntax since it provides no additional benefit.
|
||||
fn check_redundant_vis_repetition(
|
||||
err: &mut Diag<'_>,
|
||||
sess: &Session,
|
||||
seq: &SequenceRepetition,
|
||||
span: &DelimSpan,
|
||||
) {
|
||||
let is_zero_or_one: bool = seq.kleene.op == KleeneOp::ZeroOrOne;
|
||||
let is_vis = seq.tts.first().map_or(false, |tt| {
|
||||
matches!(tt, mbe::TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)))
|
||||
});
|
||||
|
||||
if is_vis && is_zero_or_one {
|
||||
err.note("a `vis` fragment can already be empty");
|
||||
err.multipart_suggestion(
|
||||
"remove the `$(` and `)?`",
|
||||
vec![
|
||||
(
|
||||
sess.source_map().span_extend_to_prev_char_before(span.open, '$', true),
|
||||
"".to_string(),
|
||||
),
|
||||
(span.close.with_hi(seq.kleene.span.hi()), "".to_string()),
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks that the lhs contains no repetition which could match an empty token
|
||||
/// tree, because then the matcher would hang indefinitely.
|
||||
fn check_lhs_no_empty_seq(sess: &Session, tts: &[mbe::TokenTree]) -> Result<(), ErrorGuaranteed> {
|
||||
|
|
@ -654,8 +684,10 @@ fn check_lhs_no_empty_seq(sess: &Session, tts: &[mbe::TokenTree]) -> Result<(),
|
|||
TokenTree::Sequence(span, seq) => {
|
||||
if is_empty_token_tree(sess, seq) {
|
||||
let sp = span.entire();
|
||||
let guar = sess.dcx().span_err(sp, "repetition matches empty token tree");
|
||||
return Err(guar);
|
||||
let mut err =
|
||||
sess.dcx().struct_span_err(sp, "repetition matches empty token tree");
|
||||
check_redundant_vis_repetition(&mut err, sess, seq, span);
|
||||
return Err(err.emit());
|
||||
}
|
||||
check_lhs_no_empty_seq(sess, &seq.tts)?
|
||||
}
|
||||
|
|
@ -778,7 +810,7 @@ impl<'tt> FirstSets<'tt> {
|
|||
// token could be the separator token itself.
|
||||
|
||||
if let (Some(sep), true) = (&seq_rep.separator, subfirst.maybe_empty) {
|
||||
first.add_one_maybe(TtHandle::from_token(sep.clone()));
|
||||
first.add_one_maybe(TtHandle::from_token(*sep));
|
||||
}
|
||||
|
||||
// Reverse scan: Sequence comes before `first`.
|
||||
|
|
@ -841,7 +873,7 @@ impl<'tt> FirstSets<'tt> {
|
|||
// If the sequence contents can be empty, then the first
|
||||
// token could be the separator token itself.
|
||||
if let (Some(sep), true) = (&seq_rep.separator, subfirst.maybe_empty) {
|
||||
first.add_one_maybe(TtHandle::from_token(sep.clone()));
|
||||
first.add_one_maybe(TtHandle::from_token(*sep));
|
||||
}
|
||||
|
||||
assert!(first.maybe_empty);
|
||||
|
|
@ -917,7 +949,7 @@ impl<'tt> Clone for TtHandle<'tt> {
|
|||
// This variant *must* contain a `mbe::TokenTree::Token`, and not
|
||||
// any other variant of `mbe::TokenTree`.
|
||||
TtHandle::Token(mbe::TokenTree::Token(tok)) => {
|
||||
TtHandle::Token(mbe::TokenTree::Token(tok.clone()))
|
||||
TtHandle::Token(mbe::TokenTree::Token(*tok))
|
||||
}
|
||||
|
||||
_ => unreachable!(),
|
||||
|
|
@ -1093,7 +1125,7 @@ fn check_matcher_core<'tt>(
|
|||
let mut new;
|
||||
let my_suffix = if let Some(sep) = &seq_rep.separator {
|
||||
new = suffix_first.clone();
|
||||
new.add_one_maybe(TtHandle::from_token(sep.clone()));
|
||||
new.add_one_maybe(TtHandle::from_token(*sep));
|
||||
&new
|
||||
} else {
|
||||
&suffix_first
|
||||
|
|
|
|||
|
|
@ -283,7 +283,7 @@ fn parse_tree<'a>(
|
|||
}
|
||||
|
||||
// `tree` is an arbitrary token. Keep it.
|
||||
tokenstream::TokenTree::Token(token, _) => TokenTree::Token(token.clone()),
|
||||
tokenstream::TokenTree::Token(token, _) => TokenTree::Token(*token),
|
||||
|
||||
// `tree` is the beginning of a delimited set of tokens (e.g., `(` or `{`). We need to
|
||||
// descend into the delimited set and further parse it.
|
||||
|
|
@ -321,7 +321,7 @@ fn parse_kleene_op(
|
|||
match iter.next() {
|
||||
Some(tokenstream::TokenTree::Token(token, _)) => match kleene_op(token) {
|
||||
Some(op) => Ok(Ok((op, token.span))),
|
||||
None => Ok(Err(token.clone())),
|
||||
None => Ok(Err(*token)),
|
||||
},
|
||||
tree => Err(tree.map_or(span, tokenstream::TokenTree::span)),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
use std::mem;
|
||||
use std::sync::Arc;
|
||||
|
||||
use rustc_ast::mut_visit::{self, MutVisitor};
|
||||
use rustc_ast::token::{
|
||||
|
|
@ -165,7 +164,7 @@ pub(super) fn transcribe<'a>(
|
|||
if repeat_idx < repeat_len {
|
||||
frame.idx = 0;
|
||||
if let Some(sep) = sep {
|
||||
result.push(TokenTree::Token(sep.clone(), Spacing::Alone));
|
||||
result.push(TokenTree::Token(*sep, Spacing::Alone));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
|
@ -307,7 +306,9 @@ pub(super) fn transcribe<'a>(
|
|||
let tt = match cur_matched {
|
||||
MatchedSingle(ParseNtResult::Tt(tt)) => {
|
||||
// `tt`s are emitted into the output stream directly as "raw tokens",
|
||||
// without wrapping them into groups.
|
||||
// without wrapping them into groups. Other variables are emitted into
|
||||
// the output stream as groups with `Delimiter::Invisible` to maintain
|
||||
// parsing priorities.
|
||||
maybe_use_metavar_location(psess, &stack, sp, tt, &mut marker)
|
||||
}
|
||||
MatchedSingle(ParseNtResult::Ident(ident, is_raw)) => {
|
||||
|
|
@ -325,6 +326,11 @@ pub(super) fn transcribe<'a>(
|
|||
MatchedSingle(ParseNtResult::Item(item)) => {
|
||||
mk_delimited(item.span, MetaVarKind::Item, TokenStream::from_ast(item))
|
||||
}
|
||||
MatchedSingle(ParseNtResult::Block(block)) => mk_delimited(
|
||||
block.span,
|
||||
MetaVarKind::Block,
|
||||
TokenStream::from_ast(block),
|
||||
),
|
||||
MatchedSingle(ParseNtResult::Stmt(stmt)) => {
|
||||
let stream = if let StmtKind::Empty = stmt.kind {
|
||||
// FIXME: Properly collect tokens for empty statements.
|
||||
|
|
@ -385,15 +391,6 @@ pub(super) fn transcribe<'a>(
|
|||
MatchedSingle(ParseNtResult::Vis(vis)) => {
|
||||
mk_delimited(vis.span, MetaVarKind::Vis, TokenStream::from_ast(vis))
|
||||
}
|
||||
MatchedSingle(ParseNtResult::Nt(nt)) => {
|
||||
// Other variables are emitted into the output stream as groups with
|
||||
// `Delimiter::Invisible` to maintain parsing priorities.
|
||||
// `Interpolated` is currently used for such groups in rustc parser.
|
||||
marker.visit_span(&mut sp);
|
||||
let use_span = nt.use_span();
|
||||
with_metavar_spans(|mspans| mspans.insert(use_span, sp));
|
||||
TokenTree::token_alone(token::Interpolated(Arc::clone(nt)), sp)
|
||||
}
|
||||
MatchedSeq(..) => {
|
||||
// We were unable to descend far enough. This is an error.
|
||||
return Err(dcx.create_err(VarStillRepeating { span: sp, ident }));
|
||||
|
|
@ -441,7 +438,7 @@ pub(super) fn transcribe<'a>(
|
|||
// Nothing much to do here. Just push the token to the result, being careful to
|
||||
// preserve syntax context.
|
||||
mbe::TokenTree::Token(token) => {
|
||||
let mut token = token.clone();
|
||||
let mut token = *token;
|
||||
mut_visit::visit_token(&mut marker, &mut token);
|
||||
let tt = TokenTree::Token(token, Spacing::Alone);
|
||||
result.push(tt);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
use std::ops::{Bound, Range};
|
||||
use std::sync::Arc;
|
||||
|
||||
use ast::token::IdentIsRaw;
|
||||
use pm::bridge::{
|
||||
|
|
@ -18,7 +17,7 @@ use rustc_parse::parser::Parser;
|
|||
use rustc_parse::{exp, new_parser_from_source_str, source_str_to_stream, unwrap_or_emit_fatal};
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::def_id::CrateNum;
|
||||
use rustc_span::{BytePos, FileName, Pos, SourceFile, Span, Symbol, sym};
|
||||
use rustc_span::{BytePos, FileName, Pos, Span, Symbol, sym};
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
|
||||
use crate::base::ExtCtxt;
|
||||
|
|
@ -309,15 +308,6 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
|
|||
}));
|
||||
}
|
||||
|
||||
Interpolated(nt) => {
|
||||
let stream = TokenStream::from_nonterminal_ast(&nt);
|
||||
trees.push(TokenTree::Group(Group {
|
||||
delimiter: pm::Delimiter::None,
|
||||
stream: Some(stream),
|
||||
span: DelimSpan::from_single(span),
|
||||
}))
|
||||
}
|
||||
|
||||
OpenDelim(..) | CloseDelim(..) => unreachable!(),
|
||||
Eof => unreachable!(),
|
||||
}
|
||||
|
|
@ -467,7 +457,6 @@ impl<'a, 'b> Rustc<'a, 'b> {
|
|||
impl server::Types for Rustc<'_, '_> {
|
||||
type FreeFunctions = FreeFunctions;
|
||||
type TokenStream = TokenStream;
|
||||
type SourceFile = Arc<SourceFile>;
|
||||
type Span = Span;
|
||||
type Symbol = Symbol;
|
||||
}
|
||||
|
|
@ -673,28 +662,6 @@ impl server::TokenStream for Rustc<'_, '_> {
|
|||
}
|
||||
}
|
||||
|
||||
impl server::SourceFile for Rustc<'_, '_> {
|
||||
fn eq(&mut self, file1: &Self::SourceFile, file2: &Self::SourceFile) -> bool {
|
||||
Arc::ptr_eq(file1, file2)
|
||||
}
|
||||
|
||||
fn path(&mut self, file: &Self::SourceFile) -> String {
|
||||
match &file.name {
|
||||
FileName::Real(name) => name
|
||||
.local_path()
|
||||
.expect("attempting to get a file path in an imported file in `proc_macro::SourceFile::path`")
|
||||
.to_str()
|
||||
.expect("non-UTF8 file path in `proc_macro::SourceFile::path`")
|
||||
.to_string(),
|
||||
_ => file.name.prefer_local().to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_real(&mut self, file: &Self::SourceFile) -> bool {
|
||||
file.is_real_file()
|
||||
}
|
||||
}
|
||||
|
||||
impl server::Span for Rustc<'_, '_> {
|
||||
fn debug(&mut self, span: Self::Span) -> String {
|
||||
if self.ecx.ecfg.span_debug {
|
||||
|
|
@ -704,8 +671,29 @@ impl server::Span for Rustc<'_, '_> {
|
|||
}
|
||||
}
|
||||
|
||||
fn source_file(&mut self, span: Self::Span) -> Self::SourceFile {
|
||||
self.psess().source_map().lookup_char_pos(span.lo()).file
|
||||
fn file(&mut self, span: Self::Span) -> String {
|
||||
self.psess()
|
||||
.source_map()
|
||||
.lookup_char_pos(span.lo())
|
||||
.file
|
||||
.name
|
||||
.prefer_remapped_unconditionaly()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
fn local_file(&mut self, span: Self::Span) -> Option<String> {
|
||||
self.psess()
|
||||
.source_map()
|
||||
.lookup_char_pos(span.lo())
|
||||
.file
|
||||
.name
|
||||
.clone()
|
||||
.into_local_path()
|
||||
.map(|p| {
|
||||
p.to_str()
|
||||
.expect("non-UTF8 file path in `proc_macro::SourceFile::path`")
|
||||
.to_string()
|
||||
})
|
||||
}
|
||||
|
||||
fn parent(&mut self, span: Self::Span) -> Option<Self::Span> {
|
||||
|
|
|
|||
|
|
@ -95,6 +95,8 @@ declare_features! (
|
|||
(accepted, c_unwind, "1.81.0", Some(74990)),
|
||||
/// Allows `#[cfg_attr(predicate, multiple, attributes, here)]`.
|
||||
(accepted, cfg_attr_multi, "1.33.0", Some(54881)),
|
||||
/// Allows the use of `#[cfg(<true/false>)]`.
|
||||
(accepted, cfg_boolean_literals, "CURRENT_RUSTC_VERSION", Some(131204)),
|
||||
/// Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests.
|
||||
(accepted, cfg_doctest, "1.40.0", Some(62210)),
|
||||
/// Enables `#[cfg(panic = "...")]` config key.
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use AttributeDuplicates::*;
|
|||
use AttributeGate::*;
|
||||
use AttributeType::*;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
||||
use crate::{Features, Stability};
|
||||
|
|
@ -65,9 +66,12 @@ pub enum AttributeSafety {
|
|||
/// Normal attribute that does not need `#[unsafe(...)]`
|
||||
Normal,
|
||||
|
||||
/// Unsafe attribute that requires safety obligations
|
||||
/// to be discharged
|
||||
Unsafe,
|
||||
/// Unsafe attribute that requires safety obligations to be discharged.
|
||||
///
|
||||
/// An error is emitted when `#[unsafe(...)]` is omitted, except when the attribute's edition
|
||||
/// is less than the one stored in `unsafe_since`. This handles attributes that were safe in
|
||||
/// earlier editions, but become unsafe in later ones.
|
||||
Unsafe { unsafe_since: Option<Edition> },
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
|
|
@ -187,12 +191,23 @@ macro_rules! template {
|
|||
}
|
||||
|
||||
macro_rules! ungated {
|
||||
(unsafe($edition:ident) $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => {
|
||||
BuiltinAttribute {
|
||||
name: sym::$attr,
|
||||
encode_cross_crate: $encode_cross_crate,
|
||||
type_: $typ,
|
||||
safety: AttributeSafety::Unsafe { unsafe_since: Some(Edition::$edition) },
|
||||
template: $tpl,
|
||||
gate: Ungated,
|
||||
duplicates: $duplicates,
|
||||
}
|
||||
};
|
||||
(unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => {
|
||||
BuiltinAttribute {
|
||||
name: sym::$attr,
|
||||
encode_cross_crate: $encode_cross_crate,
|
||||
type_: $typ,
|
||||
safety: AttributeSafety::Unsafe,
|
||||
safety: AttributeSafety::Unsafe { unsafe_since: None },
|
||||
template: $tpl,
|
||||
gate: Ungated,
|
||||
duplicates: $duplicates,
|
||||
|
|
@ -217,7 +232,7 @@ macro_rules! gated {
|
|||
name: sym::$attr,
|
||||
encode_cross_crate: $encode_cross_crate,
|
||||
type_: $typ,
|
||||
safety: AttributeSafety::Unsafe,
|
||||
safety: AttributeSafety::Unsafe { unsafe_since: None },
|
||||
template: $tpl,
|
||||
duplicates: $duplicates,
|
||||
gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate),
|
||||
|
|
@ -228,7 +243,7 @@ macro_rules! gated {
|
|||
name: sym::$attr,
|
||||
encode_cross_crate: $encode_cross_crate,
|
||||
type_: $typ,
|
||||
safety: AttributeSafety::Unsafe,
|
||||
safety: AttributeSafety::Unsafe { unsafe_since: None },
|
||||
template: $tpl,
|
||||
duplicates: $duplicates,
|
||||
gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr),
|
||||
|
|
@ -423,9 +438,9 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
),
|
||||
ungated!(no_link, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
|
||||
ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, EncodeCrossCrate::No),
|
||||
ungated!(unsafe export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
|
||||
ungated!(unsafe link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
|
||||
ungated!(unsafe no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
|
||||
ungated!(unsafe(Edition2024) export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
|
||||
ungated!(unsafe(Edition2024) link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
|
||||
ungated!(unsafe(Edition2024) no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
|
||||
ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, EncodeCrossCrate::No),
|
||||
ungated!(link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, EncodeCrossCrate::Yes),
|
||||
|
||||
|
|
@ -752,7 +767,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
),
|
||||
rustc_attr!(
|
||||
rustc_macro_transparency, Normal,
|
||||
template!(NameValueStr: "transparent|semitransparent|opaque"), ErrorFollowing,
|
||||
template!(NameValueStr: "transparent|semiopaque|opaque"), ErrorFollowing,
|
||||
EncodeCrossCrate::Yes, "used internally for testing macro hygiene",
|
||||
),
|
||||
rustc_attr!(
|
||||
|
|
|
|||
|
|
@ -391,8 +391,6 @@ declare_features! (
|
|||
(unstable, async_trait_bounds, "1.85.0", Some(62290)),
|
||||
/// Allows using C-variadics.
|
||||
(unstable, c_variadic, "1.34.0", Some(44930)),
|
||||
/// Allows the use of `#[cfg(<true/false>)]`.
|
||||
(unstable, cfg_boolean_literals, "1.83.0", Some(131204)),
|
||||
/// Allows the use of `#[cfg(contract_checks)` to check if contract checks are enabled.
|
||||
(unstable, cfg_contract_checks, "1.86.0", Some(128044)),
|
||||
/// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour.
|
||||
|
|
@ -477,6 +475,8 @@ declare_features! (
|
|||
(incomplete, ergonomic_clones, "1.87.0", Some(132290)),
|
||||
/// Allows exhaustive pattern matching on types that contain uninhabited types.
|
||||
(unstable, exhaustive_patterns, "1.13.0", Some(51085)),
|
||||
/// Disallows `extern` without an explicit ABI.
|
||||
(unstable, explicit_extern_abis, "CURRENT_RUSTC_VERSION", Some(134986)),
|
||||
/// Allows explicit tail calls via `become` expression.
|
||||
(incomplete, explicit_tail_calls, "1.72.0", Some(112788)),
|
||||
/// Allows using `aapcs`, `efiapi`, `sysv64` and `win64` as calling conventions
|
||||
|
|
@ -565,6 +565,8 @@ declare_features! (
|
|||
(incomplete, mut_ref, "1.79.0", Some(123076)),
|
||||
/// Allows using `#[naked]` on functions.
|
||||
(unstable, naked_functions, "1.9.0", Some(90957)),
|
||||
/// Allows using `#[naked]` on `extern "Rust"` functions.
|
||||
(unstable, naked_functions_rustic_abi, "CURRENT_RUSTC_VERSION", Some(138997)),
|
||||
/// Allows using `#[target_feature(enable = "...")]` on `#[naked]` on functions.
|
||||
(unstable, naked_functions_target_feature, "1.86.0", Some(138568)),
|
||||
/// Allows specifying the as-needed link modifier
|
||||
|
|
|
|||
|
|
@ -25,7 +25,10 @@ fn invocation_relative_path_to_absolute(span: Span, path: &str) -> PathBuf {
|
|||
path.to_path_buf()
|
||||
} else {
|
||||
// `/a/b/c/foo/bar.rs` contains the current macro invocation
|
||||
#[cfg(bootstrap)]
|
||||
let mut source_file_path = span.source_file().path();
|
||||
#[cfg(not(bootstrap))]
|
||||
let mut source_file_path = span.local_file().unwrap();
|
||||
// `/a/b/c/foo/`
|
||||
source_file_path.pop();
|
||||
// `/a/b/c/foo/../locales/en-US/example.ftl`
|
||||
|
|
|
|||
|
|
@ -47,12 +47,9 @@ impl DefPathTable {
|
|||
debug_assert_eq!(self.stable_crate_id, def_path_hash.stable_crate_id());
|
||||
let local_hash = def_path_hash.local_hash();
|
||||
|
||||
let index = {
|
||||
let index = DefIndex::from(self.index_to_key.len());
|
||||
debug!("DefPathTable::insert() - {:?} <-> {:?}", key, index);
|
||||
self.index_to_key.push(key);
|
||||
index
|
||||
};
|
||||
let index = self.index_to_key.push(key);
|
||||
debug!("DefPathTable::insert() - {key:?} <-> {index:?}");
|
||||
|
||||
self.def_path_hashes.push(local_hash);
|
||||
debug_assert!(self.def_path_hashes.len() == self.index_to_key.len());
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ pub enum IsAnonInPath {
|
|||
}
|
||||
|
||||
/// A lifetime. The valid field combinations are non-obvious. The following
|
||||
/// example shows some of them. See also the comments on `LifetimeName`.
|
||||
/// example shows some of them. See also the comments on `LifetimeKind`.
|
||||
/// ```
|
||||
/// #[repr(C)]
|
||||
/// struct S<'a>(&'a u32); // res=Param, name='a, IsAnonInPath::No
|
||||
|
|
@ -84,7 +84,7 @@ pub struct Lifetime {
|
|||
pub ident: Ident,
|
||||
|
||||
/// Semantics of this lifetime.
|
||||
pub res: LifetimeName,
|
||||
pub kind: LifetimeKind,
|
||||
|
||||
/// Is the lifetime anonymous and in a path? Used only for error
|
||||
/// suggestions. See `Lifetime::suggestion` for example use.
|
||||
|
|
@ -130,7 +130,7 @@ impl ParamName {
|
|||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)]
|
||||
pub enum LifetimeName {
|
||||
pub enum LifetimeKind {
|
||||
/// User-given names or fresh (synthetic) names.
|
||||
Param(LocalDefId),
|
||||
|
||||
|
|
@ -160,16 +160,16 @@ pub enum LifetimeName {
|
|||
Static,
|
||||
}
|
||||
|
||||
impl LifetimeName {
|
||||
impl LifetimeKind {
|
||||
fn is_elided(&self) -> bool {
|
||||
match self {
|
||||
LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Infer => true,
|
||||
LifetimeKind::ImplicitObjectLifetimeDefault | LifetimeKind::Infer => true,
|
||||
|
||||
// It might seem surprising that `Fresh` counts as not *elided*
|
||||
// -- but this is because, as far as the code in the compiler is
|
||||
// concerned -- `Fresh` variants act equivalently to "some fresh name".
|
||||
// They correspond to early-bound regions on an impl, in other words.
|
||||
LifetimeName::Error | LifetimeName::Param(..) | LifetimeName::Static => false,
|
||||
LifetimeKind::Error | LifetimeKind::Param(..) | LifetimeKind::Static => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -184,10 +184,10 @@ impl Lifetime {
|
|||
pub fn new(
|
||||
hir_id: HirId,
|
||||
ident: Ident,
|
||||
res: LifetimeName,
|
||||
kind: LifetimeKind,
|
||||
is_anon_in_path: IsAnonInPath,
|
||||
) -> Lifetime {
|
||||
let lifetime = Lifetime { hir_id, ident, res, is_anon_in_path };
|
||||
let lifetime = Lifetime { hir_id, ident, kind, is_anon_in_path };
|
||||
|
||||
// Sanity check: elided lifetimes form a strict subset of anonymous lifetimes.
|
||||
#[cfg(debug_assertions)]
|
||||
|
|
@ -202,7 +202,7 @@ impl Lifetime {
|
|||
}
|
||||
|
||||
pub fn is_elided(&self) -> bool {
|
||||
self.res.is_elided()
|
||||
self.kind.is_elided()
|
||||
}
|
||||
|
||||
pub fn is_anonymous(&self) -> bool {
|
||||
|
|
@ -1014,7 +1014,7 @@ pub struct WhereRegionPredicate<'hir> {
|
|||
impl<'hir> WhereRegionPredicate<'hir> {
|
||||
/// Returns `true` if `param_def_id` matches the `lifetime` of this predicate.
|
||||
fn is_param_bound(&self, param_def_id: LocalDefId) -> bool {
|
||||
self.lifetime.res == LifetimeName::Param(param_def_id)
|
||||
self.lifetime.kind == LifetimeKind::Param(param_def_id)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1756,7 +1756,7 @@ pub enum PatKind<'hir> {
|
|||
Never,
|
||||
|
||||
/// A tuple pattern (e.g., `(a, b)`).
|
||||
/// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
|
||||
/// If the `..` pattern fragment is present, then `DotDotPos` denotes its position.
|
||||
/// `0 <= position <= subpats.len()`
|
||||
Tuple(&'hir [Pat<'hir>], DotDotPos),
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ fn trait_object_roundtrips_impl(syntax: TraitObjectSyntax) {
|
|||
Lifetime {
|
||||
hir_id: HirId::INVALID,
|
||||
ident: Ident::new(sym::name, DUMMY_SP),
|
||||
res: LifetimeName::Static,
|
||||
kind: LifetimeKind::Static,
|
||||
is_anon_in_path: IsAnonInPath::No,
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
//! 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR.
|
||||
//! - Example: find all items with a `#[foo]` attribute on them.
|
||||
//! - How: Use the `hir_crate_items` or `hir_module_items` query to traverse over item-like ids
|
||||
//! (ItemId, TraitItemId, etc.) and use tcx.def_kind and `tcx.hir().item*(id)` to filter and
|
||||
//! (ItemId, TraitItemId, etc.) and use tcx.def_kind and `tcx.hir_item*(id)` to filter and
|
||||
//! access actual item-like thing, respectively.
|
||||
//! - Pro: Efficient; just walks the lists of item ids and gives users control whether to access
|
||||
//! the hir_owners themselves or not.
|
||||
|
|
|
|||
|
|
@ -182,6 +182,7 @@ language_item_table! {
|
|||
DynMetadata, sym::dyn_metadata, dyn_metadata, Target::Struct, GenericRequirement::None;
|
||||
|
||||
Freeze, sym::freeze, freeze_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
UnsafeUnpin, sym::unsafe_unpin, unsafe_unpin_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
|
||||
FnPtrTrait, sym::fn_ptr_trait, fn_ptr_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
FnPtrAddr, sym::fn_ptr_addr, fn_ptr_addr, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
|
||||
|
|
@ -235,6 +236,8 @@ language_item_table! {
|
|||
IndexMut, sym::index_mut, index_mut_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||
|
||||
UnsafeCell, sym::unsafe_cell, unsafe_cell_type, Target::Struct, GenericRequirement::None;
|
||||
UnsafePinned, sym::unsafe_pinned, unsafe_pinned_type, Target::Struct, GenericRequirement::None;
|
||||
|
||||
VaList, sym::va_list, va_list, Target::Struct, GenericRequirement::None;
|
||||
|
||||
Deref, sym::deref, deref_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
|
|
@ -439,6 +442,8 @@ language_item_table! {
|
|||
DefaultTrait3, sym::default_trait3, default_trait3_trait, Target::Trait, GenericRequirement::None;
|
||||
DefaultTrait2, sym::default_trait2, default_trait2_trait, Target::Trait, GenericRequirement::None;
|
||||
DefaultTrait1, sym::default_trait1, default_trait1_trait, Target::Trait, GenericRequirement::None;
|
||||
|
||||
ContractCheckEnsures, sym::contract_check_ensures, contract_check_ensures_fn, Target::Fn, GenericRequirement::None;
|
||||
}
|
||||
|
||||
/// The requirement imposed on the generics of a lang item
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
|
||||
#![feature(associated_type_defaults)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(closure_track_caller)]
|
||||
|
|
|
|||
|
|
@ -443,13 +443,13 @@ fn best_definition_site_of_opaque<'tcx>(
|
|||
let impl_def_id = tcx.local_parent(parent);
|
||||
for assoc in tcx.associated_items(impl_def_id).in_definition_order() {
|
||||
match assoc.kind {
|
||||
ty::AssocKind::Const | ty::AssocKind::Fn => {
|
||||
ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => {
|
||||
if let ControlFlow::Break(span) = locator.check(assoc.def_id.expect_local())
|
||||
{
|
||||
return Some(span);
|
||||
}
|
||||
}
|
||||
ty::AssocKind::Type => {}
|
||||
ty::AssocKind::Type { .. } => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -740,7 +740,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||
|
||||
for &assoc_item in assoc_items.in_definition_order() {
|
||||
match assoc_item.kind {
|
||||
ty::AssocKind::Type if assoc_item.defaultness(tcx).has_value() => {
|
||||
ty::AssocKind::Type { .. } if assoc_item.defaultness(tcx).has_value() => {
|
||||
let trait_args = GenericArgs::identity_for_item(tcx, def_id);
|
||||
let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds(
|
||||
tcx,
|
||||
|
|
@ -942,7 +942,7 @@ fn check_impl_items_against_trait<'tcx>(
|
|||
|
||||
if res.is_ok() {
|
||||
match ty_impl_item.kind {
|
||||
ty::AssocKind::Fn => {
|
||||
ty::AssocKind::Fn { .. } => {
|
||||
compare_impl_item::refine::check_refining_return_position_impl_trait_in_trait(
|
||||
tcx,
|
||||
ty_impl_item,
|
||||
|
|
@ -952,8 +952,8 @@ fn check_impl_items_against_trait<'tcx>(
|
|||
.instantiate_identity(),
|
||||
);
|
||||
}
|
||||
ty::AssocKind::Const => {}
|
||||
ty::AssocKind::Type => {}
|
||||
ty::AssocKind::Const { .. } => {}
|
||||
ty::AssocKind::Type { .. } => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,9 +43,11 @@ pub(super) fn compare_impl_item(
|
|||
debug!(?impl_trait_ref);
|
||||
|
||||
match impl_item.kind {
|
||||
ty::AssocKind::Fn => compare_impl_method(tcx, impl_item, trait_item, impl_trait_ref),
|
||||
ty::AssocKind::Type => compare_impl_ty(tcx, impl_item, trait_item, impl_trait_ref),
|
||||
ty::AssocKind::Const => compare_impl_const(tcx, impl_item, trait_item, impl_trait_ref),
|
||||
ty::AssocKind::Fn { .. } => compare_impl_method(tcx, impl_item, trait_item, impl_trait_ref),
|
||||
ty::AssocKind::Type { .. } => compare_impl_ty(tcx, impl_item, trait_item, impl_trait_ref),
|
||||
ty::AssocKind::Const { .. } => {
|
||||
compare_impl_const(tcx, impl_item, trait_item, impl_trait_ref)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -606,7 +608,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
|
|||
// with placeholders, which imply nothing about outlives bounds, and then
|
||||
// prove below that the hidden types are well formed.
|
||||
let universe = infcx.create_next_universe();
|
||||
let mut idx = 0;
|
||||
let mut idx = ty::BoundVar::ZERO;
|
||||
let mapping: FxIndexMap<_, _> = collector
|
||||
.types
|
||||
.iter()
|
||||
|
|
@ -623,10 +625,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
|
|||
tcx,
|
||||
ty::Placeholder {
|
||||
universe,
|
||||
bound: ty::BoundTy {
|
||||
var: ty::BoundVar::from_usize(idx),
|
||||
kind: ty::BoundTyKind::Anon,
|
||||
},
|
||||
bound: ty::BoundTy { var: idx, kind: ty::BoundTyKind::Anon },
|
||||
},
|
||||
),
|
||||
)
|
||||
|
|
@ -654,7 +653,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
|
|||
cause.span,
|
||||
E0053,
|
||||
"method `{}` has an incompatible return type for trait",
|
||||
trait_m.name
|
||||
trait_m.name()
|
||||
);
|
||||
infcx.err_ctxt().note_type_err(
|
||||
&mut diag,
|
||||
|
|
@ -1032,11 +1031,11 @@ fn report_trait_method_mismatch<'tcx>(
|
|||
impl_err_span,
|
||||
E0053,
|
||||
"method `{}` has an incompatible type for trait",
|
||||
trait_m.name
|
||||
trait_m.name()
|
||||
);
|
||||
match &terr {
|
||||
TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
|
||||
if trait_m.fn_has_self_parameter =>
|
||||
if trait_m.is_method() =>
|
||||
{
|
||||
let ty = trait_sig.inputs()[0];
|
||||
let sugg = get_self_string(ty, |ty| ty == impl_trait_ref.self_ty());
|
||||
|
|
@ -1255,7 +1254,7 @@ fn compare_self_type<'tcx>(
|
|||
get_self_string(self_arg_ty, can_eq_self)
|
||||
};
|
||||
|
||||
match (trait_m.fn_has_self_parameter, impl_m.fn_has_self_parameter) {
|
||||
match (trait_m.is_method(), impl_m.is_method()) {
|
||||
(false, false) | (true, true) => {}
|
||||
|
||||
(false, true) => {
|
||||
|
|
@ -1266,14 +1265,14 @@ fn compare_self_type<'tcx>(
|
|||
impl_m_span,
|
||||
E0185,
|
||||
"method `{}` has a `{}` declaration in the impl, but not in the trait",
|
||||
trait_m.name,
|
||||
trait_m.name(),
|
||||
self_descr
|
||||
);
|
||||
err.span_label(impl_m_span, format!("`{self_descr}` used in impl"));
|
||||
if let Some(span) = tcx.hir_span_if_local(trait_m.def_id) {
|
||||
err.span_label(span, format!("trait method declared without `{self_descr}`"));
|
||||
} else {
|
||||
err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
|
||||
err.note_trait_signature(trait_m.name(), trait_m.signature(tcx));
|
||||
}
|
||||
return Err(err.emit_unless(delay));
|
||||
}
|
||||
|
|
@ -1286,14 +1285,14 @@ fn compare_self_type<'tcx>(
|
|||
impl_m_span,
|
||||
E0186,
|
||||
"method `{}` has a `{}` declaration in the trait, but not in the impl",
|
||||
trait_m.name,
|
||||
trait_m.name(),
|
||||
self_descr
|
||||
);
|
||||
err.span_label(impl_m_span, format!("expected `{self_descr}` in impl"));
|
||||
if let Some(span) = tcx.hir_span_if_local(trait_m.def_id) {
|
||||
err.span_label(span, format!("`{self_descr}` used in trait"));
|
||||
} else {
|
||||
err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
|
||||
err.note_trait_signature(trait_m.name(), trait_m.signature(tcx));
|
||||
}
|
||||
|
||||
return Err(err.emit_unless(delay));
|
||||
|
|
@ -1363,7 +1362,7 @@ fn compare_number_of_generics<'tcx>(
|
|||
let mut err_occurred = None;
|
||||
for (kind, trait_count, impl_count) in matchings {
|
||||
if impl_count != trait_count {
|
||||
let arg_spans = |kind: ty::AssocKind, generics: &hir::Generics<'_>| {
|
||||
let arg_spans = |item: &ty::AssocItem, generics: &hir::Generics<'_>| {
|
||||
let mut spans = generics
|
||||
.params
|
||||
.iter()
|
||||
|
|
@ -1373,7 +1372,7 @@ fn compare_number_of_generics<'tcx>(
|
|||
} => {
|
||||
// A fn can have an arbitrary number of extra elided lifetimes for the
|
||||
// same signature.
|
||||
!matches!(kind, ty::AssocKind::Fn)
|
||||
!item.is_fn()
|
||||
}
|
||||
_ => true,
|
||||
})
|
||||
|
|
@ -1386,7 +1385,7 @@ fn compare_number_of_generics<'tcx>(
|
|||
};
|
||||
let (trait_spans, impl_trait_spans) = if let Some(def_id) = trait_.def_id.as_local() {
|
||||
let trait_item = tcx.hir_expect_trait_item(def_id);
|
||||
let arg_spans: Vec<Span> = arg_spans(trait_.kind, trait_item.generics);
|
||||
let arg_spans: Vec<Span> = arg_spans(&trait_, trait_item.generics);
|
||||
let impl_trait_spans: Vec<Span> = trait_item
|
||||
.generics
|
||||
.params
|
||||
|
|
@ -1412,7 +1411,7 @@ fn compare_number_of_generics<'tcx>(
|
|||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
let spans = arg_spans(impl_.kind, impl_item.generics);
|
||||
let spans = arg_spans(&impl_, impl_item.generics);
|
||||
let span = spans.first().copied();
|
||||
|
||||
let mut err = tcx.dcx().struct_span_err(
|
||||
|
|
@ -1421,7 +1420,7 @@ fn compare_number_of_generics<'tcx>(
|
|||
"{} `{}` has {} {kind} parameter{} but its trait \
|
||||
declaration has {} {kind} parameter{}",
|
||||
item_kind,
|
||||
trait_.name,
|
||||
trait_.name(),
|
||||
impl_count,
|
||||
pluralize!(impl_count),
|
||||
trait_count,
|
||||
|
|
@ -1512,7 +1511,7 @@ fn compare_number_of_method_arguments<'tcx>(
|
|||
impl_span,
|
||||
E0050,
|
||||
"method `{}` has {} but the declaration in trait `{}` has {}",
|
||||
trait_m.name,
|
||||
trait_m.name(),
|
||||
potentially_plural_count(impl_number_args, "parameter"),
|
||||
tcx.def_path_str(trait_m.def_id),
|
||||
trait_number_args
|
||||
|
|
@ -1527,7 +1526,7 @@ fn compare_number_of_method_arguments<'tcx>(
|
|||
),
|
||||
);
|
||||
} else {
|
||||
err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
|
||||
err.note_trait_signature(trait_m.name(), trait_m.signature(tcx));
|
||||
}
|
||||
|
||||
err.span_label(
|
||||
|
|
@ -1581,7 +1580,7 @@ fn compare_synthetic_generics<'tcx>(
|
|||
impl_span,
|
||||
E0643,
|
||||
"method `{}` has incompatible signature for trait",
|
||||
trait_m.name
|
||||
trait_m.name()
|
||||
);
|
||||
err.span_label(trait_span, "declaration in trait here");
|
||||
if impl_synthetic {
|
||||
|
|
@ -1703,7 +1702,7 @@ fn compare_generic_param_kinds<'tcx>(
|
|||
trait_item: ty::AssocItem,
|
||||
delay: bool,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
assert_eq!(impl_item.kind, trait_item.kind);
|
||||
assert_eq!(impl_item.as_tag(), trait_item.as_tag());
|
||||
|
||||
let ty_const_params_of = |def_id| {
|
||||
tcx.generics_of(def_id).own_params.iter().filter(|param| {
|
||||
|
|
@ -1741,7 +1740,7 @@ fn compare_generic_param_kinds<'tcx>(
|
|||
E0053,
|
||||
"{} `{}` has an incompatible generic parameter for trait `{}`",
|
||||
impl_item.descr(),
|
||||
trait_item.name,
|
||||
trait_item.name(),
|
||||
&tcx.def_path_str(tcx.parent(trait_item.def_id))
|
||||
);
|
||||
|
||||
|
|
@ -1877,7 +1876,7 @@ fn compare_const_predicate_entailment<'tcx>(
|
|||
cause.span,
|
||||
E0326,
|
||||
"implemented const `{}` has an incompatible type for trait",
|
||||
trait_ct.name
|
||||
trait_ct.name()
|
||||
);
|
||||
|
||||
let trait_c_span = trait_ct.def_id.as_local().map(|trait_ct_def_id| {
|
||||
|
|
@ -2235,16 +2234,19 @@ fn param_env_with_gat_bounds<'tcx>(
|
|||
// of the RPITITs associated with the same body. This is because checking
|
||||
// the item bounds of RPITITs often involves nested RPITITs having to prove
|
||||
// bounds about themselves.
|
||||
let impl_tys_to_install = match impl_ty.opt_rpitit_info {
|
||||
None => vec![impl_ty],
|
||||
Some(
|
||||
ty::ImplTraitInTraitData::Impl { fn_def_id }
|
||||
| ty::ImplTraitInTraitData::Trait { fn_def_id, .. },
|
||||
) => tcx
|
||||
let impl_tys_to_install = match impl_ty.kind {
|
||||
ty::AssocKind::Type {
|
||||
data:
|
||||
ty::AssocTypeData::Rpitit(
|
||||
ty::ImplTraitInTraitData::Impl { fn_def_id }
|
||||
| ty::ImplTraitInTraitData::Trait { fn_def_id, .. },
|
||||
),
|
||||
} => tcx
|
||||
.associated_types_for_impl_traits_in_associated_fn(fn_def_id)
|
||||
.iter()
|
||||
.map(|def_id| tcx.associated_item(*def_id))
|
||||
.collect(),
|
||||
_ => vec![impl_ty],
|
||||
};
|
||||
|
||||
for impl_ty in impl_tys_to_install {
|
||||
|
|
|
|||
|
|
@ -217,15 +217,11 @@ pub(crate) fn check_intrinsic_type(
|
|||
};
|
||||
(n_tps, 0, 0, inputs, output, hir::Safety::Unsafe)
|
||||
} else if intrinsic_name == sym::contract_check_ensures {
|
||||
// contract_check_ensures::<'a, Ret, C>(&'a Ret, C)
|
||||
// where C: impl Fn(&'a Ret) -> bool,
|
||||
// contract_check_ensures::<Ret, C>(Ret, C) -> Ret
|
||||
// where C: for<'a> Fn(&'a Ret) -> bool,
|
||||
//
|
||||
// so: two type params, one lifetime param, 0 const params, two inputs, no return
|
||||
|
||||
let p = generics.param_at(0, tcx);
|
||||
let r = ty::Region::new_early_param(tcx, p.to_early_bound_region_data());
|
||||
let ref_ret = Ty::new_imm_ref(tcx, r, param(1));
|
||||
(2, 1, 0, vec![ref_ret, param(2)], tcx.types.unit, hir::Safety::Safe)
|
||||
// so: two type params, 0 lifetime param, 0 const params, two inputs, no return
|
||||
(2, 0, 0, vec![param(0), param(1)], param(1), hir::Safety::Safe)
|
||||
} else {
|
||||
let safety = intrinsic_operation_unsafety(tcx, intrinsic_id);
|
||||
let (n_tps, n_cts, inputs, output) = match intrinsic_name {
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ fn missing_items_err(
|
|||
|
||||
let missing_items_msg = missing_items
|
||||
.clone()
|
||||
.map(|trait_item| trait_item.name.to_string())
|
||||
.map(|trait_item| trait_item.name().to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join("`, `");
|
||||
|
||||
|
|
@ -236,7 +236,7 @@ fn missing_items_err(
|
|||
let code = format!("{padding}{snippet}\n{padding}");
|
||||
if let Some(span) = tcx.hir_span_if_local(trait_item.def_id) {
|
||||
missing_trait_item_label
|
||||
.push(errors::MissingTraitItemLabel { span, item: trait_item.name });
|
||||
.push(errors::MissingTraitItemLabel { span, item: trait_item.name() });
|
||||
missing_trait_item.push(errors::MissingTraitItemSuggestion {
|
||||
span: sugg_sp,
|
||||
code,
|
||||
|
|
@ -407,14 +407,14 @@ fn fn_sig_suggestion<'tcx>(
|
|||
.enumerate()
|
||||
.map(|(i, ty)| {
|
||||
Some(match ty.kind() {
|
||||
ty::Param(_) if assoc.fn_has_self_parameter && i == 0 => "self".to_string(),
|
||||
ty::Param(_) if assoc.is_method() && i == 0 => "self".to_string(),
|
||||
ty::Ref(reg, ref_ty, mutability) if i == 0 => {
|
||||
let reg = format!("{reg} ");
|
||||
let reg = match ®[..] {
|
||||
"'_ " | " " => "",
|
||||
reg => reg,
|
||||
};
|
||||
if assoc.fn_has_self_parameter {
|
||||
if assoc.is_method() {
|
||||
match ref_ty.kind() {
|
||||
ty::Param(param) if param.name == kw::SelfUpper => {
|
||||
format!("&{}{}self", reg, mutability.prefix_str())
|
||||
|
|
@ -427,7 +427,7 @@ fn fn_sig_suggestion<'tcx>(
|
|||
}
|
||||
}
|
||||
_ => {
|
||||
if assoc.fn_has_self_parameter && i == 0 {
|
||||
if assoc.is_method() && i == 0 {
|
||||
format!("self: {ty}")
|
||||
} else {
|
||||
format!("_: {ty}")
|
||||
|
|
@ -489,7 +489,7 @@ fn suggestion_signature<'tcx>(
|
|||
);
|
||||
|
||||
match assoc.kind {
|
||||
ty::AssocKind::Fn => fn_sig_suggestion(
|
||||
ty::AssocKind::Fn { .. } => fn_sig_suggestion(
|
||||
tcx,
|
||||
tcx.liberate_late_bound_regions(
|
||||
assoc.def_id,
|
||||
|
|
@ -499,14 +499,14 @@ fn suggestion_signature<'tcx>(
|
|||
tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args),
|
||||
assoc,
|
||||
),
|
||||
ty::AssocKind::Type => {
|
||||
ty::AssocKind::Type { .. } => {
|
||||
let (generics, where_clauses) = bounds_from_generic_predicates(
|
||||
tcx,
|
||||
tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args),
|
||||
);
|
||||
format!("type {}{generics} = /* Type */{where_clauses};", assoc.name)
|
||||
format!("type {}{generics} = /* Type */{where_clauses};", assoc.name())
|
||||
}
|
||||
ty::AssocKind::Const => {
|
||||
ty::AssocKind::Const { name } => {
|
||||
let ty = tcx.type_of(assoc.def_id).instantiate_identity();
|
||||
let val = tcx
|
||||
.infer_ctxt()
|
||||
|
|
@ -514,7 +514,7 @@ fn suggestion_signature<'tcx>(
|
|||
.err_ctxt()
|
||||
.ty_kind_suggestion(tcx.param_env(assoc.def_id), ty)
|
||||
.unwrap_or_else(|| "value".to_string());
|
||||
format!("const {}: {} = {};", assoc.name, ty, val)
|
||||
format!("const {}: {} = {};", name, ty, val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -408,7 +408,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
|
|||
let gat_def_id = gat_item.def_id.expect_local();
|
||||
let gat_item = tcx.associated_item(gat_def_id);
|
||||
// If this item is not an assoc ty, or has no args, then it's not a GAT
|
||||
if gat_item.kind != ty::AssocKind::Type {
|
||||
if !gat_item.is_type() {
|
||||
continue;
|
||||
}
|
||||
let gat_generics = tcx.generics_of(gat_def_id);
|
||||
|
|
@ -432,7 +432,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
|
|||
|
||||
let item_required_bounds = match tcx.associated_item(item_def_id).kind {
|
||||
// In our example, this corresponds to `into_iter` method
|
||||
ty::AssocKind::Fn => {
|
||||
ty::AssocKind::Fn { .. } => {
|
||||
// For methods, we check the function signature's return type for any GATs
|
||||
// to constrain. In the `into_iter` case, we see that the return type
|
||||
// `Self::Iter<'a>` is a GAT we want to gather any potential missing bounds from.
|
||||
|
|
@ -453,7 +453,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
|
|||
)
|
||||
}
|
||||
// In our example, this corresponds to the `Iter` and `Item` associated types
|
||||
ty::AssocKind::Type => {
|
||||
ty::AssocKind::Type { .. } => {
|
||||
// If our associated item is a GAT with missing bounds, add them to
|
||||
// the param-env here. This allows this GAT to propagate missing bounds
|
||||
// to other GATs.
|
||||
|
|
@ -474,7 +474,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
|
|||
gat_generics,
|
||||
)
|
||||
}
|
||||
ty::AssocKind::Const => None,
|
||||
ty::AssocKind::Const { .. } => None,
|
||||
};
|
||||
|
||||
if let Some(item_required_bounds) = item_required_bounds {
|
||||
|
|
@ -1076,7 +1076,7 @@ fn check_associated_item(
|
|||
};
|
||||
|
||||
match item.kind {
|
||||
ty::AssocKind::Const => {
|
||||
ty::AssocKind::Const { .. } => {
|
||||
let ty = tcx.type_of(item.def_id).instantiate_identity();
|
||||
let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
|
||||
wfcx.register_wf_obligation(span, loc, ty.into());
|
||||
|
|
@ -1089,7 +1089,7 @@ fn check_associated_item(
|
|||
);
|
||||
Ok(())
|
||||
}
|
||||
ty::AssocKind::Fn => {
|
||||
ty::AssocKind::Fn { .. } => {
|
||||
let sig = tcx.fn_sig(item.def_id).instantiate_identity();
|
||||
let hir_sig = sig_if_method.expect("bad signature for method");
|
||||
check_fn_or_method(
|
||||
|
|
@ -1101,7 +1101,7 @@ fn check_associated_item(
|
|||
);
|
||||
check_method_receiver(wfcx, hir_sig, item, self_ty)
|
||||
}
|
||||
ty::AssocKind::Type => {
|
||||
ty::AssocKind::Type { .. } => {
|
||||
if let ty::AssocItemContainer::Trait = item.container {
|
||||
check_associated_type_bounds(wfcx, item, span)
|
||||
}
|
||||
|
|
@ -1716,7 +1716,7 @@ fn check_method_receiver<'tcx>(
|
|||
) -> Result<(), ErrorGuaranteed> {
|
||||
let tcx = wfcx.tcx();
|
||||
|
||||
if !method.fn_has_self_parameter {
|
||||
if !method.is_method() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
|
|||
|
||||
for &item1 in impl_items1.in_definition_order() {
|
||||
let collision = impl_items2
|
||||
.filter_by_name_unhygienic(item1.name)
|
||||
.filter_by_name_unhygienic(item1.name())
|
||||
.any(|&item2| self.compare_hygienically(item1, item2));
|
||||
|
||||
if collision {
|
||||
|
|
@ -64,7 +64,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
|
|||
|
||||
fn compare_hygienically(&self, item1: ty::AssocItem, item2: ty::AssocItem) -> bool {
|
||||
// Symbols and namespace match, compare hygienically.
|
||||
item1.kind.namespace() == item2.kind.namespace()
|
||||
item1.namespace() == item2.namespace()
|
||||
&& item1.ident(self.tcx).normalize_to_macros_2_0()
|
||||
== item2.ident(self.tcx).normalize_to_macros_2_0()
|
||||
}
|
||||
|
|
@ -113,7 +113,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
|
|||
let mut res = Ok(());
|
||||
for &item1 in impl_items1.in_definition_order() {
|
||||
let collision = impl_items2
|
||||
.filter_by_name_unhygienic(item1.name)
|
||||
.filter_by_name_unhygienic(item1.name())
|
||||
.find(|&&item2| self.compare_hygienically(item1, item2));
|
||||
|
||||
if let Some(item2) = collision {
|
||||
|
|
@ -230,11 +230,11 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
|
|||
let mut ids = impl_items
|
||||
.in_definition_order()
|
||||
.filter_map(|item| {
|
||||
let entry = connected_region_ids.entry(item.name);
|
||||
let entry = connected_region_ids.entry(item.name());
|
||||
if let IndexEntry::Occupied(e) = &entry {
|
||||
Some(*e.get())
|
||||
} else {
|
||||
idents_to_add.push(item.name);
|
||||
idents_to_add.push(item.name());
|
||||
None
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ use rustc_trait_selection::traits::ObligationCtxt;
|
|||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::errors;
|
||||
use crate::hir_ty_lowering::errors::assoc_kind_str;
|
||||
use crate::hir_ty_lowering::errors::assoc_tag_str;
|
||||
use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason};
|
||||
|
||||
pub(crate) mod dump;
|
||||
|
|
@ -450,7 +450,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
|
|||
item_def_id: DefId,
|
||||
item_segment: &rustc_hir::PathSegment<'tcx>,
|
||||
poly_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
kind: ty::AssocKind,
|
||||
assoc_tag: ty::AssocTag,
|
||||
) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> {
|
||||
if let Some(trait_ref) = poly_trait_ref.no_bound_vars() {
|
||||
let item_args = self.lowerer().lower_generic_args_of_assoc_item(
|
||||
|
|
@ -525,7 +525,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
|
|||
inferred_sugg,
|
||||
bound,
|
||||
mpart_sugg,
|
||||
what: assoc_kind_str(kind),
|
||||
what: assoc_tag_str(assoc_tag),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use rustc_errors::ErrorGuaranteed;
|
|||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt};
|
||||
use rustc_hir::{
|
||||
self as hir, AmbigArg, GenericArg, GenericParam, GenericParamKind, HirId, LifetimeName, Node,
|
||||
self as hir, AmbigArg, GenericArg, GenericParam, GenericParamKind, HirId, LifetimeKind, Node,
|
||||
};
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::hir::nested_filter;
|
||||
|
|
@ -646,14 +646,14 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
arg: &'tcx hir::PreciseCapturingArg<'tcx>,
|
||||
) -> Self::Result {
|
||||
match *arg {
|
||||
hir::PreciseCapturingArg::Lifetime(lt) => match lt.res {
|
||||
LifetimeName::Param(def_id) => {
|
||||
hir::PreciseCapturingArg::Lifetime(lt) => match lt.kind {
|
||||
LifetimeKind::Param(def_id) => {
|
||||
self.resolve_lifetime_ref(def_id, lt);
|
||||
}
|
||||
LifetimeName::Error => {}
|
||||
LifetimeName::ImplicitObjectLifetimeDefault
|
||||
| LifetimeName::Infer
|
||||
| LifetimeName::Static => {
|
||||
LifetimeKind::Error => {}
|
||||
LifetimeKind::ImplicitObjectLifetimeDefault
|
||||
| LifetimeKind::Infer
|
||||
| LifetimeKind::Static => {
|
||||
self.tcx.dcx().emit_err(errors::BadPreciseCapture {
|
||||
span: lt.ident.span,
|
||||
kind: "lifetime",
|
||||
|
|
@ -774,26 +774,26 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
});
|
||||
match lifetime.res {
|
||||
LifetimeName::ImplicitObjectLifetimeDefault => {
|
||||
match lifetime.kind {
|
||||
LifetimeKind::ImplicitObjectLifetimeDefault => {
|
||||
// If the user does not write *anything*, we
|
||||
// use the object lifetime defaulting
|
||||
// rules. So e.g., `Box<dyn Debug>` becomes
|
||||
// `Box<dyn Debug + 'static>`.
|
||||
self.resolve_object_lifetime_default(&*lifetime)
|
||||
}
|
||||
LifetimeName::Infer => {
|
||||
LifetimeKind::Infer => {
|
||||
// If the user writes `'_`, we use the *ordinary* elision
|
||||
// rules. So the `'_` in e.g., `Box<dyn Debug + '_>` will be
|
||||
// resolved the same as the `'_` in `&'_ Foo`.
|
||||
//
|
||||
// cc #48468
|
||||
}
|
||||
LifetimeName::Param(..) | LifetimeName::Static => {
|
||||
LifetimeKind::Param(..) | LifetimeKind::Static => {
|
||||
// If the user wrote an explicit name, use that.
|
||||
self.visit_lifetime(&*lifetime);
|
||||
}
|
||||
LifetimeName::Error => {}
|
||||
LifetimeKind::Error => {}
|
||||
}
|
||||
}
|
||||
hir::TyKind::Ref(lifetime_ref, ref mt) => {
|
||||
|
|
@ -873,17 +873,17 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
|
||||
match lifetime_ref.res {
|
||||
hir::LifetimeName::Static => {
|
||||
match lifetime_ref.kind {
|
||||
hir::LifetimeKind::Static => {
|
||||
self.insert_lifetime(lifetime_ref, ResolvedArg::StaticLifetime)
|
||||
}
|
||||
hir::LifetimeName::Param(param_def_id) => {
|
||||
hir::LifetimeKind::Param(param_def_id) => {
|
||||
self.resolve_lifetime_ref(param_def_id, lifetime_ref)
|
||||
}
|
||||
// If we've already reported an error, just ignore `lifetime_ref`.
|
||||
hir::LifetimeName::Error => {}
|
||||
hir::LifetimeKind::Error => {}
|
||||
// Those will be resolved by typechecking.
|
||||
hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Infer => {}
|
||||
hir::LifetimeKind::ImplicitObjectLifetimeDefault | hir::LifetimeKind::Infer => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1063,15 +1063,15 @@ fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: LocalDefId) -> ObjectL
|
|||
|
||||
for bound in bound.bounds {
|
||||
if let hir::GenericBound::Outlives(lifetime) = bound {
|
||||
set.insert(lifetime.res);
|
||||
set.insert(lifetime.kind);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match set {
|
||||
Set1::Empty => ObjectLifetimeDefault::Empty,
|
||||
Set1::One(hir::LifetimeName::Static) => ObjectLifetimeDefault::Static,
|
||||
Set1::One(hir::LifetimeName::Param(param_def_id)) => {
|
||||
Set1::One(hir::LifetimeKind::Static) => ObjectLifetimeDefault::Static,
|
||||
Set1::One(hir::LifetimeKind::Param(param_def_id)) => {
|
||||
ObjectLifetimeDefault::Param(param_def_id.to_def_id())
|
||||
}
|
||||
_ => ObjectLifetimeDefault::Ambiguous,
|
||||
|
|
@ -1241,7 +1241,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
// Fresh lifetimes in APIT used to be allowed in async fns and forbidden in
|
||||
// regular fns.
|
||||
if let Some(hir::PredicateOrigin::ImplTrait) = where_bound_origin
|
||||
&& let hir::LifetimeName::Param(param_id) = lifetime_ref.res
|
||||
&& let hir::LifetimeKind::Param(param_id) = lifetime_ref.kind
|
||||
&& let Some(generics) =
|
||||
self.tcx.hir_get_generics(self.tcx.local_parent(param_id))
|
||||
&& let Some(param) = generics.params.iter().find(|p| p.def_id == param_id)
|
||||
|
|
@ -1811,7 +1811,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
self.tcx,
|
||||
type_def_id,
|
||||
constraint.ident,
|
||||
ty::AssocKind::Fn,
|
||||
ty::AssocTag::Fn,
|
||||
) {
|
||||
bound_vars.extend(
|
||||
self.tcx
|
||||
|
|
@ -1843,7 +1843,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
self.tcx,
|
||||
type_def_id,
|
||||
constraint.ident,
|
||||
ty::AssocKind::Type,
|
||||
ty::AssocTag::Type,
|
||||
)
|
||||
.map(|(bound_vars, _)| bound_vars);
|
||||
self.with(scope, |this| {
|
||||
|
|
@ -1875,13 +1875,13 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
assoc_ident: Ident,
|
||||
assoc_kind: ty::AssocKind,
|
||||
assoc_tag: ty::AssocTag,
|
||||
) -> Option<(Vec<ty::BoundVariableKind>, &'tcx ty::AssocItem)> {
|
||||
let trait_defines_associated_item_named = |trait_def_id: DefId| {
|
||||
tcx.associated_items(trait_def_id).find_by_ident_and_kind(
|
||||
tcx,
|
||||
assoc_ident,
|
||||
assoc_kind,
|
||||
assoc_tag,
|
||||
trait_def_id,
|
||||
)
|
||||
};
|
||||
|
|
@ -1894,8 +1894,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
let Some((def_id, bound_vars)) = stack.pop() else {
|
||||
break None;
|
||||
};
|
||||
// See issue #83753. If someone writes an associated type on a non-trait, just treat it as
|
||||
// there being no supertrait HRTBs.
|
||||
// See issue #83753. If someone writes an associated type on a non-trait, just treat it
|
||||
// as there being no supertrait HRTBs.
|
||||
match tcx.def_kind(def_id) {
|
||||
DefKind::Trait | DefKind::TraitAlias | DefKind::Impl { .. } => {}
|
||||
_ => break None,
|
||||
|
|
@ -2067,7 +2067,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
self.tcx,
|
||||
trait_def_id,
|
||||
item_segment.ident,
|
||||
ty::AssocKind::Fn,
|
||||
ty::AssocTag::Fn,
|
||||
)
|
||||
});
|
||||
|
||||
|
|
@ -2112,7 +2112,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
self.tcx,
|
||||
trait_def_id,
|
||||
item_segment.ident,
|
||||
ty::AssocKind::Fn,
|
||||
ty::AssocTag::Fn,
|
||||
) else {
|
||||
return;
|
||||
};
|
||||
|
|
@ -2440,7 +2440,7 @@ fn is_late_bound_map(
|
|||
}
|
||||
|
||||
fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
|
||||
if let hir::LifetimeName::Param(def_id) = lifetime_ref.res {
|
||||
if let hir::LifetimeKind::Param(def_id) = lifetime_ref.kind {
|
||||
self.regions.insert(def_id);
|
||||
}
|
||||
}
|
||||
|
|
@ -2453,7 +2453,7 @@ fn is_late_bound_map(
|
|||
|
||||
impl<'tcx> Visitor<'tcx> for AllCollector {
|
||||
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
|
||||
if let hir::LifetimeName::Param(def_id) = lifetime_ref.res {
|
||||
if let hir::LifetimeKind::Param(def_id) = lifetime_ref.kind {
|
||||
self.regions.insert(def_id);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,9 +32,11 @@ pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
|
|||
for &assoc_id in tcx.associated_item_def_ids(impl_def_id) {
|
||||
let assoc = tcx.associated_item(assoc_id);
|
||||
match assoc.kind {
|
||||
ty::AssocKind::Const | ty::AssocKind::Fn => locator.check(assoc_id.expect_local()),
|
||||
ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => {
|
||||
locator.check(assoc_id.expect_local())
|
||||
}
|
||||
// Associated types don't have bodies, so they can't constrain hidden types
|
||||
ty::AssocKind::Type => {}
|
||||
ty::AssocKind::Type { .. } => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use GenericArgsInfo::*;
|
|||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{Applicability, Diag, Diagnostic, EmissionGuarantee, MultiSpan, pluralize};
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt};
|
||||
use rustc_middle::ty::{self as ty, AssocItems, TyCtxt};
|
||||
use rustc_span::def_id::DefId;
|
||||
use tracing::debug;
|
||||
|
||||
|
|
@ -486,13 +486,13 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
|||
let items: &AssocItems = self.tcx.associated_items(self.def_id);
|
||||
items
|
||||
.in_definition_order()
|
||||
.filter(|item| item.kind == AssocKind::Type)
|
||||
.filter(|item| item.is_type())
|
||||
.filter(|item| {
|
||||
!self
|
||||
.gen_args
|
||||
.constraints
|
||||
.iter()
|
||||
.any(|constraint| constraint.ident.name == item.name)
|
||||
.any(|constraint| constraint.ident.name == item.name())
|
||||
})
|
||||
.filter(|item| !item.is_impl_trait_in_trait())
|
||||
.map(|item| self.tcx.item_ident(item.def_id).to_string())
|
||||
|
|
|
|||
|
|
@ -431,16 +431,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
) -> Result<(), ErrorGuaranteed> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
let assoc_kind = if constraint.gen_args.parenthesized
|
||||
let assoc_tag = if constraint.gen_args.parenthesized
|
||||
== hir::GenericArgsParentheses::ReturnTypeNotation
|
||||
{
|
||||
ty::AssocKind::Fn
|
||||
ty::AssocTag::Fn
|
||||
} else if let hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(_) } =
|
||||
constraint.kind
|
||||
{
|
||||
ty::AssocKind::Const
|
||||
ty::AssocTag::Const
|
||||
} else {
|
||||
ty::AssocKind::Type
|
||||
ty::AssocTag::Type
|
||||
};
|
||||
|
||||
// Given something like `U: Trait<T = X>`, we want to produce a predicate like
|
||||
|
|
@ -453,7 +453,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// trait SuperTrait<A> { type T; }
|
||||
let candidate = if self.probe_trait_that_defines_assoc_item(
|
||||
trait_ref.def_id(),
|
||||
assoc_kind,
|
||||
assoc_tag,
|
||||
constraint.ident,
|
||||
) {
|
||||
// Simple case: The assoc item is defined in the current trait.
|
||||
|
|
@ -464,7 +464,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
self.probe_single_bound_for_assoc_item(
|
||||
|| traits::supertraits(tcx, trait_ref),
|
||||
AssocItemQSelf::Trait(trait_ref.def_id()),
|
||||
assoc_kind,
|
||||
assoc_tag,
|
||||
constraint.ident,
|
||||
path_span,
|
||||
Some(constraint),
|
||||
|
|
@ -474,7 +474,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let assoc_item = self
|
||||
.probe_assoc_item(
|
||||
constraint.ident,
|
||||
assoc_kind,
|
||||
assoc_tag,
|
||||
hir_ref_id,
|
||||
constraint.span,
|
||||
candidate.def_id(),
|
||||
|
|
@ -493,7 +493,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
})
|
||||
.or_insert(constraint.span);
|
||||
|
||||
let projection_term = if let ty::AssocKind::Fn = assoc_kind {
|
||||
let projection_term = if let ty::AssocTag::Fn = assoc_tag {
|
||||
let bound_vars = tcx.late_bound_vars(constraint.hir_id);
|
||||
ty::Binder::bind_with_vars(
|
||||
self.lower_return_type_notation_ty(candidate, assoc_item.def_id, path_span)?.into(),
|
||||
|
|
@ -542,7 +542,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
};
|
||||
|
||||
match constraint.kind {
|
||||
hir::AssocItemConstraintKind::Equality { .. } if let ty::AssocKind::Fn = assoc_kind => {
|
||||
hir::AssocItemConstraintKind::Equality { .. } if let ty::AssocTag::Fn = assoc_tag => {
|
||||
return Err(self.dcx().emit_err(crate::errors::ReturnTypeNotationEqualityBound {
|
||||
span: constraint.span,
|
||||
}));
|
||||
|
|
@ -679,7 +679,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
trait_def_id,
|
||||
hir_ty.span,
|
||||
item_segment,
|
||||
ty::AssocKind::Type,
|
||||
ty::AssocTag::Type,
|
||||
);
|
||||
return Ty::new_error(tcx, guar);
|
||||
};
|
||||
|
|
@ -771,7 +771,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
)
|
||||
},
|
||||
AssocItemQSelf::SelfTyAlias,
|
||||
ty::AssocKind::Fn,
|
||||
ty::AssocTag::Fn,
|
||||
assoc_ident,
|
||||
span,
|
||||
None,
|
||||
|
|
@ -783,7 +783,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
) => self.probe_single_ty_param_bound_for_assoc_item(
|
||||
param_did.expect_local(),
|
||||
qself.span,
|
||||
ty::AssocKind::Fn,
|
||||
ty::AssocTag::Fn,
|
||||
assoc_ident,
|
||||
span,
|
||||
)?,
|
||||
|
|
@ -823,7 +823,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
let trait_def_id = bound.def_id();
|
||||
let assoc_ty = self
|
||||
.probe_assoc_item(assoc_ident, ty::AssocKind::Fn, qpath_hir_id, span, trait_def_id)
|
||||
.probe_assoc_item(assoc_ident, ty::AssocTag::Fn, qpath_hir_id, span, trait_def_id)
|
||||
.expect("failed to find associated type");
|
||||
|
||||
Ok((bound, assoc_ty.def_id))
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
tcx.associated_items(pred.trait_ref.def_id)
|
||||
.in_definition_order()
|
||||
// We only care about associated types.
|
||||
.filter(|item| item.kind == ty::AssocKind::Type)
|
||||
.filter(|item| item.is_type())
|
||||
// No RPITITs -- they're not dyn-compatible for now.
|
||||
.filter(|item| !item.is_impl_trait_in_trait())
|
||||
// If the associated type has a `where Self: Sized` bound,
|
||||
|
|
@ -415,7 +415,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
self.lower_lifetime(lifetime, RegionInferReason::ExplicitObjectLifetime)
|
||||
} else {
|
||||
let reason =
|
||||
if let hir::LifetimeName::ImplicitObjectLifetimeDefault = lifetime.res {
|
||||
if let hir::LifetimeKind::ImplicitObjectLifetimeDefault = lifetime.kind {
|
||||
if let hir::Node::Ty(hir::Ty {
|
||||
kind: hir::TyKind::Ref(parent_lifetime, _),
|
||||
..
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
&self,
|
||||
all_candidates: impl Fn() -> I,
|
||||
qself: AssocItemQSelf,
|
||||
assoc_kind: ty::AssocKind,
|
||||
assoc_tag: ty::AssocTag,
|
||||
assoc_ident: Ident,
|
||||
span: Span,
|
||||
constraint: Option<&hir::AssocItemConstraint<'tcx>>,
|
||||
|
|
@ -134,14 +134,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}) {
|
||||
return self.complain_about_assoc_kind_mismatch(
|
||||
assoc_item,
|
||||
assoc_kind,
|
||||
assoc_tag,
|
||||
assoc_ident,
|
||||
span,
|
||||
constraint,
|
||||
);
|
||||
}
|
||||
|
||||
let assoc_kind_str = assoc_kind_str(assoc_kind);
|
||||
let assoc_kind_str = assoc_tag_str(assoc_tag);
|
||||
let qself_str = qself.to_string(tcx);
|
||||
|
||||
// The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a
|
||||
|
|
@ -168,7 +168,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let all_candidate_names: Vec<_> = all_candidates()
|
||||
.flat_map(|r| tcx.associated_items(r.def_id()).in_definition_order())
|
||||
.filter_map(|item| {
|
||||
(!item.is_impl_trait_in_trait() && item.kind == assoc_kind).then_some(item.name)
|
||||
if !item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag {
|
||||
item.opt_name()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
|
@ -200,7 +204,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
.iter()
|
||||
.flat_map(|trait_def_id| tcx.associated_items(*trait_def_id).in_definition_order())
|
||||
.filter_map(|item| {
|
||||
(!item.is_impl_trait_in_trait() && item.kind == assoc_kind).then_some(item.name)
|
||||
(!item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag).then(|| item.name())
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
|
@ -213,7 +217,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
.filter(|trait_def_id| {
|
||||
tcx.associated_items(trait_def_id)
|
||||
.filter_by_name_unhygienic(suggested_name)
|
||||
.any(|item| item.kind == assoc_kind)
|
||||
.any(|item| item.as_tag() == assoc_tag)
|
||||
})
|
||||
.collect::<Vec<_>>()[..]
|
||||
{
|
||||
|
|
@ -330,14 +334,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
fn complain_about_assoc_kind_mismatch(
|
||||
&self,
|
||||
assoc_item: &ty::AssocItem,
|
||||
assoc_kind: ty::AssocKind,
|
||||
assoc_tag: ty::AssocTag,
|
||||
ident: Ident,
|
||||
span: Span,
|
||||
constraint: Option<&hir::AssocItemConstraint<'tcx>>,
|
||||
) -> ErrorGuaranteed {
|
||||
let tcx = self.tcx();
|
||||
|
||||
let bound_on_assoc_const_label = if let ty::AssocKind::Const = assoc_item.kind
|
||||
let bound_on_assoc_const_label = if let ty::AssocKind::Const { .. } = assoc_item.kind
|
||||
&& let Some(constraint) = constraint
|
||||
&& let hir::AssocItemConstraintKind::Bound { .. } = constraint.kind
|
||||
{
|
||||
|
|
@ -375,17 +379,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
hir::Term::Ty(ty) => ty.span,
|
||||
hir::Term::Const(ct) => ct.span(),
|
||||
};
|
||||
(span, Some(ident.span), assoc_item.kind, assoc_kind)
|
||||
(span, Some(ident.span), assoc_item.as_tag(), assoc_tag)
|
||||
} else {
|
||||
(ident.span, None, assoc_kind, assoc_item.kind)
|
||||
(ident.span, None, assoc_tag, assoc_item.as_tag())
|
||||
};
|
||||
|
||||
self.dcx().emit_err(errors::AssocKindMismatch {
|
||||
span,
|
||||
expected: assoc_kind_str(expected),
|
||||
got: assoc_kind_str(got),
|
||||
expected: assoc_tag_str(expected),
|
||||
got: assoc_tag_str(got),
|
||||
expected_because_label,
|
||||
assoc_kind: assoc_kind_str(assoc_item.kind),
|
||||
assoc_kind: assoc_tag_str(assoc_item.as_tag()),
|
||||
def_span: tcx.def_span(assoc_item.def_id),
|
||||
bound_on_assoc_const_label,
|
||||
wrap_in_braces_sugg,
|
||||
|
|
@ -398,9 +402,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
types: &[String],
|
||||
traits: &[String],
|
||||
name: Symbol,
|
||||
kind: ty::AssocKind,
|
||||
assoc_tag: ty::AssocTag,
|
||||
) -> ErrorGuaranteed {
|
||||
let kind_str = assoc_kind_str(kind);
|
||||
let kind_str = assoc_tag_str(assoc_tag);
|
||||
let mut err =
|
||||
struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated {kind_str}");
|
||||
if self
|
||||
|
|
@ -569,7 +573,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
candidates: Vec<(DefId, (DefId, DefId))>,
|
||||
fulfillment_errors: Vec<FulfillmentError<'tcx>>,
|
||||
span: Span,
|
||||
kind: ty::AssocKind,
|
||||
assoc_tag: ty::AssocTag,
|
||||
) -> ErrorGuaranteed {
|
||||
// FIXME(fmease): This was copied in parts from an old version of `rustc_hir_typeck::method::suggest`.
|
||||
// Either
|
||||
|
|
@ -579,14 +583,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
let tcx = self.tcx();
|
||||
|
||||
let kind_str = assoc_kind_str(kind);
|
||||
let assoc_tag_str = assoc_tag_str(assoc_tag);
|
||||
let adt_did = self_ty.ty_adt_def().map(|def| def.did());
|
||||
let add_def_label = |err: &mut Diag<'_>| {
|
||||
if let Some(did) = adt_did {
|
||||
err.span_label(
|
||||
tcx.def_span(did),
|
||||
format!(
|
||||
"associated {kind_str} `{name}` not found for this {}",
|
||||
"associated {assoc_tag_str} `{name}` not found for this {}",
|
||||
tcx.def_descr(did)
|
||||
),
|
||||
);
|
||||
|
|
@ -615,11 +619,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
self.dcx(),
|
||||
name.span,
|
||||
E0220,
|
||||
"associated {kind_str} `{name}` not found for `{self_ty}` in the current scope"
|
||||
"associated {assoc_tag_str} `{name}` not found for `{self_ty}` in the current scope"
|
||||
);
|
||||
err.span_label(name.span, format!("associated item not found in `{self_ty}`"));
|
||||
err.note(format!(
|
||||
"the associated {kind_str} was found for\n{type_candidates}{additional_types}",
|
||||
"the associated {assoc_tag_str} was found for\n{type_candidates}{additional_types}",
|
||||
));
|
||||
add_def_label(&mut err);
|
||||
return err.emit();
|
||||
|
|
@ -700,7 +704,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
let mut err = self.dcx().struct_span_err(
|
||||
name.span,
|
||||
format!("the associated {kind_str} `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied")
|
||||
format!("the associated {assoc_tag_str} `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied")
|
||||
);
|
||||
if !bounds.is_empty() {
|
||||
err.note(format!(
|
||||
|
|
@ -710,7 +714,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
err.span_label(
|
||||
name.span,
|
||||
format!("associated {kind_str} cannot be referenced on `{self_ty}` due to unsatisfied trait bounds")
|
||||
format!("associated {assoc_tag_str} cannot be referenced on `{self_ty}` due to unsatisfied trait bounds")
|
||||
);
|
||||
|
||||
for (span, mut bounds) in bound_spans {
|
||||
|
|
@ -761,7 +765,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// `issue-22560.rs`.
|
||||
let mut dyn_compatibility_violations = Ok(());
|
||||
for (assoc_item, trait_ref) in &missing_assoc_types {
|
||||
names.entry(trait_ref).or_default().push(assoc_item.name);
|
||||
names.entry(trait_ref).or_default().push(assoc_item.name());
|
||||
names_len += 1;
|
||||
|
||||
let violations =
|
||||
|
|
@ -812,7 +816,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let assoc_item = tcx.associated_items(trait_def).find_by_ident_and_kind(
|
||||
tcx,
|
||||
ident,
|
||||
ty::AssocKind::Type,
|
||||
ty::AssocTag::Type,
|
||||
trait_def,
|
||||
);
|
||||
|
||||
|
|
@ -852,16 +856,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let mut names: UnordMap<_, usize> = Default::default();
|
||||
for (item, _) in &missing_assoc_types {
|
||||
types_count += 1;
|
||||
*names.entry(item.name).or_insert(0) += 1;
|
||||
*names.entry(item.name()).or_insert(0) += 1;
|
||||
}
|
||||
let mut dupes = false;
|
||||
let mut shadows = false;
|
||||
for (item, trait_ref) in &missing_assoc_types {
|
||||
let prefix = if names[&item.name] > 1 {
|
||||
let name = item.name();
|
||||
let prefix = if names[&name] > 1 {
|
||||
let trait_def_id = trait_ref.def_id();
|
||||
dupes = true;
|
||||
format!("{}::", tcx.def_path_str(trait_def_id))
|
||||
} else if bound_names.get(&item.name).is_some_and(|x| *x != item) {
|
||||
} else if bound_names.get(&name).is_some_and(|x| *x != item) {
|
||||
let trait_def_id = trait_ref.def_id();
|
||||
shadows = true;
|
||||
format!("{}::", tcx.def_path_str(trait_def_id))
|
||||
|
|
@ -871,7 +876,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
let mut is_shadowed = false;
|
||||
|
||||
if let Some(assoc_item) = bound_names.get(&item.name)
|
||||
if let Some(assoc_item) = bound_names.get(&name)
|
||||
&& *assoc_item != item
|
||||
{
|
||||
is_shadowed = true;
|
||||
|
|
@ -880,17 +885,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
if assoc_item.def_id.is_local() { ", consider renaming it" } else { "" };
|
||||
err.span_label(
|
||||
tcx.def_span(assoc_item.def_id),
|
||||
format!("`{}{}` shadowed here{}", prefix, item.name, rename_message),
|
||||
format!("`{}{}` shadowed here{}", prefix, name, rename_message),
|
||||
);
|
||||
}
|
||||
|
||||
let rename_message = if is_shadowed { ", consider renaming it" } else { "" };
|
||||
|
||||
if let Some(sp) = tcx.hir_span_if_local(item.def_id) {
|
||||
err.span_label(
|
||||
sp,
|
||||
format!("`{}{}` defined here{}", prefix, item.name, rename_message),
|
||||
);
|
||||
err.span_label(sp, format!("`{}{}` defined here{}", prefix, name, rename_message));
|
||||
}
|
||||
}
|
||||
if potential_assoc_types.len() == missing_assoc_types.len() {
|
||||
|
|
@ -903,7 +905,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
{
|
||||
let types: Vec<_> = missing_assoc_types
|
||||
.iter()
|
||||
.map(|(item, _)| format!("{} = Type", item.name))
|
||||
.map(|(item, _)| format!("{} = Type", item.name()))
|
||||
.collect();
|
||||
let code = if let Some(snippet) = snippet.strip_suffix('>') {
|
||||
// The user wrote `Trait<'a>` or similar and we don't have a type we can
|
||||
|
|
@ -938,16 +940,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let mut names: FxIndexMap<_, usize> = FxIndexMap::default();
|
||||
for (item, _) in &missing_assoc_types {
|
||||
types_count += 1;
|
||||
*names.entry(item.name).or_insert(0) += 1;
|
||||
*names.entry(item.name()).or_insert(0) += 1;
|
||||
}
|
||||
let mut label = vec![];
|
||||
for (item, trait_ref) in &missing_assoc_types {
|
||||
let postfix = if names[&item.name] > 1 {
|
||||
let name = item.name();
|
||||
let postfix = if names[&name] > 1 {
|
||||
format!(" (from trait `{}`)", trait_ref.print_trait_sugared())
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
label.push(format!("`{}`{}", item.name, postfix));
|
||||
label.push(format!("`{}`{}", name, postfix));
|
||||
}
|
||||
if !label.is_empty() {
|
||||
err.span_label(
|
||||
|
|
@ -1022,12 +1025,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
.map(|simple_ty| tcx.incoherent_impls(simple_ty))
|
||||
})
|
||||
&& let name = Symbol::intern(&format!("{ident2}_{ident3}"))
|
||||
&& let Some(ty::AssocItem { kind: ty::AssocKind::Fn, .. }) = inherent_impls
|
||||
&& let Some(item) = inherent_impls
|
||||
.iter()
|
||||
.flat_map(|inherent_impl| {
|
||||
tcx.associated_items(inherent_impl).filter_by_name_unhygienic(name)
|
||||
})
|
||||
.next()
|
||||
&& item.is_fn()
|
||||
{
|
||||
Err(struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type")
|
||||
.with_span_suggestion_verbose(
|
||||
|
|
@ -1629,10 +1633,10 @@ fn generics_args_err_extend<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn assoc_kind_str(kind: ty::AssocKind) -> &'static str {
|
||||
match kind {
|
||||
ty::AssocKind::Fn => "function",
|
||||
ty::AssocKind::Const => "constant",
|
||||
ty::AssocKind::Type => "type",
|
||||
pub(crate) fn assoc_tag_str(assoc_tag: ty::AssocTag) -> &'static str {
|
||||
match assoc_tag {
|
||||
ty::AssocTag::Fn => "function",
|
||||
ty::AssocTag::Const => "constant",
|
||||
ty::AssocTag::Type => "type",
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -501,8 +501,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let names: Vec<_> = tcx
|
||||
.associated_items(trait_def_id)
|
||||
.in_definition_order()
|
||||
.filter(|assoc| assoc.kind.namespace() == Namespace::ValueNS)
|
||||
.map(|cand| cand.name)
|
||||
.filter(|assoc| assoc.namespace() == Namespace::ValueNS)
|
||||
.map(|cand| cand.name())
|
||||
.collect();
|
||||
if let Some(typo) = find_best_match_for_name(&names, segment.ident.name, None) {
|
||||
diag.span_suggestion_verbose(
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@ use rustc_middle::middle::stability::AllowUnstable;
|
|||
use rustc_middle::mir::interpret::LitToConstInput;
|
||||
use rustc_middle::ty::print::PrintPolyTraitRefExt as _;
|
||||
use rustc_middle::ty::{
|
||||
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt,
|
||||
TypeVisitableExt, TypingMode, Upcast, fold_regions,
|
||||
self, AssocTag, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty,
|
||||
TyCtxt, TypeVisitableExt, TypingMode, Upcast, fold_regions,
|
||||
};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
|
||||
|
|
@ -51,7 +51,7 @@ use rustc_trait_selection::traits::wf::object_region_bounds;
|
|||
use rustc_trait_selection::traits::{self, ObligationCtxt};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use self::errors::assoc_kind_str;
|
||||
use self::errors::assoc_tag_str;
|
||||
use crate::check::check_abi_fn_ptr;
|
||||
use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, NoVariantNamed};
|
||||
use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint};
|
||||
|
|
@ -168,7 +168,7 @@ pub trait HirTyLowerer<'tcx> {
|
|||
item_def_id: DefId,
|
||||
item_segment: &hir::PathSegment<'tcx>,
|
||||
poly_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
kind: ty::AssocKind,
|
||||
assoc_tag: ty::AssocTag,
|
||||
) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed>;
|
||||
|
||||
fn lower_fn_sig(
|
||||
|
|
@ -251,10 +251,10 @@ enum LowerAssocMode {
|
|||
}
|
||||
|
||||
impl LowerAssocMode {
|
||||
fn kind(self) -> ty::AssocKind {
|
||||
fn assoc_tag(self) -> ty::AssocTag {
|
||||
match self {
|
||||
LowerAssocMode::Type { .. } => ty::AssocKind::Type,
|
||||
LowerAssocMode::Const => ty::AssocKind::Const,
|
||||
LowerAssocMode::Type { .. } => ty::AssocTag::Type,
|
||||
LowerAssocMode::Const => ty::AssocTag::Const,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -268,7 +268,8 @@ impl LowerAssocMode {
|
|||
fn permit_variants(self) -> bool {
|
||||
match self {
|
||||
LowerAssocMode::Type { permit_variants } => permit_variants,
|
||||
// FIXME(mgca): Support paths like `Option::<T>::None` or `Option::<T>::Some` which resolve to const ctors/fn items respectively
|
||||
// FIXME(mgca): Support paths like `Option::<T>::None` or `Option::<T>::Some` which
|
||||
// resolve to const ctors/fn items respectively.
|
||||
LowerAssocMode::Const => false,
|
||||
}
|
||||
}
|
||||
|
|
@ -932,12 +933,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
fn probe_trait_that_defines_assoc_item(
|
||||
&self,
|
||||
trait_def_id: DefId,
|
||||
assoc_kind: ty::AssocKind,
|
||||
assoc_tag: AssocTag,
|
||||
assoc_ident: Ident,
|
||||
) -> bool {
|
||||
self.tcx()
|
||||
.associated_items(trait_def_id)
|
||||
.find_by_ident_and_kind(self.tcx(), assoc_ident, assoc_kind, trait_def_id)
|
||||
.find_by_ident_and_kind(self.tcx(), assoc_ident, assoc_tag, trait_def_id)
|
||||
.is_some()
|
||||
}
|
||||
|
||||
|
|
@ -975,7 +976,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
&self,
|
||||
ty_param_def_id: LocalDefId,
|
||||
ty_param_span: Span,
|
||||
kind: ty::AssocKind,
|
||||
assoc_tag: AssocTag,
|
||||
assoc_ident: Ident,
|
||||
span: Span,
|
||||
) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed> {
|
||||
|
|
@ -993,7 +994,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
traits::transitive_bounds_that_define_assoc_item(tcx, trait_refs, assoc_ident)
|
||||
},
|
||||
AssocItemQSelf::TyParam(ty_param_def_id, ty_param_span),
|
||||
kind,
|
||||
assoc_tag,
|
||||
assoc_ident,
|
||||
span,
|
||||
None,
|
||||
|
|
@ -1010,7 +1011,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
&self,
|
||||
all_candidates: impl Fn() -> I,
|
||||
qself: AssocItemQSelf,
|
||||
assoc_kind: ty::AssocKind,
|
||||
assoc_tag: AssocTag,
|
||||
assoc_ident: Ident,
|
||||
span: Span,
|
||||
constraint: Option<&hir::AssocItemConstraint<'tcx>>,
|
||||
|
|
@ -1021,14 +1022,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let tcx = self.tcx();
|
||||
|
||||
let mut matching_candidates = all_candidates().filter(|r| {
|
||||
self.probe_trait_that_defines_assoc_item(r.def_id(), assoc_kind, assoc_ident)
|
||||
self.probe_trait_that_defines_assoc_item(r.def_id(), assoc_tag, assoc_ident)
|
||||
});
|
||||
|
||||
let Some(bound) = matching_candidates.next() else {
|
||||
let reported = self.complain_about_assoc_item_not_found(
|
||||
all_candidates,
|
||||
qself,
|
||||
assoc_kind,
|
||||
assoc_tag,
|
||||
assoc_ident,
|
||||
span,
|
||||
constraint,
|
||||
|
|
@ -1040,7 +1041,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
if let Some(bound2) = matching_candidates.next() {
|
||||
debug!(?bound2);
|
||||
|
||||
let assoc_kind_str = errors::assoc_kind_str(assoc_kind);
|
||||
let assoc_kind_str = errors::assoc_tag_str(assoc_tag);
|
||||
let qself_str = qself.to_string(tcx);
|
||||
let mut err = self.dcx().create_err(crate::errors::AmbiguousAssocItem {
|
||||
span,
|
||||
|
|
@ -1059,14 +1060,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
},
|
||||
);
|
||||
|
||||
// FIXME(#97583): Print associated item bindings properly (i.e., not as equality predicates!).
|
||||
// FIXME(#97583): Print associated item bindings properly (i.e., not as equality
|
||||
// predicates!).
|
||||
// FIXME: Turn this into a structured, translateable & more actionable suggestion.
|
||||
let mut where_bounds = vec![];
|
||||
for bound in [bound, bound2].into_iter().chain(matching_candidates) {
|
||||
let bound_id = bound.def_id();
|
||||
let bound_span = tcx
|
||||
.associated_items(bound_id)
|
||||
.find_by_ident_and_kind(tcx, assoc_ident, assoc_kind, bound_id)
|
||||
.find_by_ident_and_kind(tcx, assoc_ident, assoc_tag, bound_id)
|
||||
.and_then(|item| tcx.hir_span_if_local(item.def_id));
|
||||
|
||||
if let Some(bound_span) = bound_span {
|
||||
|
|
@ -1265,7 +1267,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
qself_ty,
|
||||
hir_ref_id,
|
||||
span,
|
||||
mode.kind(),
|
||||
mode.assoc_tag(),
|
||||
)? {
|
||||
return Ok(LoweredAssoc::Term(did, args));
|
||||
}
|
||||
|
|
@ -1296,7 +1298,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
)
|
||||
},
|
||||
AssocItemQSelf::SelfTyAlias,
|
||||
mode.kind(),
|
||||
mode.assoc_tag(),
|
||||
assoc_ident,
|
||||
span,
|
||||
None,
|
||||
|
|
@ -1308,12 +1310,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
) => self.probe_single_ty_param_bound_for_assoc_item(
|
||||
param_did.expect_local(),
|
||||
qself.span,
|
||||
mode.kind(),
|
||||
mode.assoc_tag(),
|
||||
assoc_ident,
|
||||
span,
|
||||
)?,
|
||||
_ => {
|
||||
let kind_str = assoc_kind_str(mode.kind());
|
||||
let kind_str = assoc_tag_str(mode.assoc_tag());
|
||||
let reported = if variant_resolution.is_some() {
|
||||
// Variant in type position
|
||||
let msg = format!("expected {kind_str}, found variant `{assoc_ident}`");
|
||||
|
|
@ -1420,7 +1422,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
&[qself_ty.to_string()],
|
||||
&traits,
|
||||
assoc_ident.name,
|
||||
mode.kind(),
|
||||
mode.assoc_tag(),
|
||||
)
|
||||
};
|
||||
return Err(reported);
|
||||
|
|
@ -1429,10 +1431,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
let trait_did = bound.def_id();
|
||||
let assoc_item = self
|
||||
.probe_assoc_item(assoc_ident, mode.kind(), hir_ref_id, span, trait_did)
|
||||
.probe_assoc_item(assoc_ident, mode.assoc_tag(), hir_ref_id, span, trait_did)
|
||||
.expect("failed to find associated item");
|
||||
let (def_id, args) =
|
||||
self.lower_assoc_shared(span, assoc_item.def_id, assoc_segment, bound, mode.kind())?;
|
||||
let (def_id, args) = self.lower_assoc_shared(
|
||||
span,
|
||||
assoc_item.def_id,
|
||||
assoc_segment,
|
||||
bound,
|
||||
mode.assoc_tag(),
|
||||
)?;
|
||||
let result = LoweredAssoc::Term(def_id, args);
|
||||
|
||||
if let Some(variant_def_id) = variant_resolution {
|
||||
|
|
@ -1469,20 +1476,21 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
self_ty: Ty<'tcx>,
|
||||
block: HirId,
|
||||
span: Span,
|
||||
kind: ty::AssocKind,
|
||||
assoc_tag: ty::AssocTag,
|
||||
) -> Result<Option<(DefId, GenericArgsRef<'tcx>)>, ErrorGuaranteed> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
if !tcx.features().inherent_associated_types() {
|
||||
match kind {
|
||||
// Don't attempt to look up inherent associated types when the feature is not enabled.
|
||||
// Theoretically it'd be fine to do so since we feature-gate their definition site.
|
||||
// However, due to current limitations of the implementation (caused by us performing
|
||||
// selection during HIR ty lowering instead of in the trait solver), IATs can lead to cycle
|
||||
// errors (#108491) which mask the feature-gate error, needlessly confusing users
|
||||
// who use IATs by accident (#113265).
|
||||
ty::AssocKind::Type => return Ok(None),
|
||||
ty::AssocKind::Const => {
|
||||
match assoc_tag {
|
||||
// Don't attempt to look up inherent associated types when the feature is not
|
||||
// enabled. Theoretically it'd be fine to do so since we feature-gate their
|
||||
// definition site. However, due to current limitations of the implementation
|
||||
// (caused by us performing selection during HIR ty lowering instead of in the
|
||||
// trait solver), IATs can lead to cycle errors (#108491) which mask the
|
||||
// feature-gate error, needlessly confusing users who use IATs by accident
|
||||
// (#113265).
|
||||
ty::AssocTag::Type => return Ok(None),
|
||||
ty::AssocTag::Const => {
|
||||
// We also gate the mgca codepath for type-level uses of inherent consts
|
||||
// with the inherent_associated_types feature gate since it relies on the
|
||||
// same machinery and has similar rough edges.
|
||||
|
|
@ -1494,7 +1502,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
)
|
||||
.emit());
|
||||
}
|
||||
ty::AssocKind::Fn => unreachable!(),
|
||||
ty::AssocTag::Fn => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1503,7 +1511,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
.inherent_impls(adt_did)
|
||||
.iter()
|
||||
.filter_map(|&impl_| {
|
||||
let (item, scope) = self.probe_assoc_item_unchecked(name, kind, block, impl_)?;
|
||||
let (item, scope) =
|
||||
self.probe_assoc_item_unchecked(name, assoc_tag, block, impl_)?;
|
||||
Some((impl_, (item.def_id, scope)))
|
||||
})
|
||||
.collect();
|
||||
|
|
@ -1542,7 +1551,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
self_ty,
|
||||
|self_ty| {
|
||||
self.select_inherent_assoc_candidates(
|
||||
infcx, name, span, self_ty, param_env, candidates, kind,
|
||||
infcx, name, span, self_ty, param_env, candidates, assoc_tag,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
|
@ -1570,7 +1579,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
self_ty: Ty<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
candidates: Vec<(DefId, (DefId, DefId))>,
|
||||
kind: ty::AssocKind,
|
||||
assoc_tag: ty::AssocTag,
|
||||
) -> Result<(DefId, (DefId, DefId)), ErrorGuaranteed> {
|
||||
let tcx = self.tcx();
|
||||
let mut fulfillment_errors = Vec::new();
|
||||
|
|
@ -1621,7 +1630,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
candidates,
|
||||
fulfillment_errors,
|
||||
span,
|
||||
kind,
|
||||
assoc_tag,
|
||||
)),
|
||||
|
||||
&[applicable_candidate] => Ok(applicable_candidate),
|
||||
|
|
@ -1640,12 +1649,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
fn probe_assoc_item(
|
||||
&self,
|
||||
ident: Ident,
|
||||
kind: ty::AssocKind,
|
||||
assoc_tag: ty::AssocTag,
|
||||
block: HirId,
|
||||
span: Span,
|
||||
scope: DefId,
|
||||
) -> Option<ty::AssocItem> {
|
||||
let (item, scope) = self.probe_assoc_item_unchecked(ident, kind, block, scope)?;
|
||||
let (item, scope) = self.probe_assoc_item_unchecked(ident, assoc_tag, block, scope)?;
|
||||
self.check_assoc_item(item.def_id, ident, scope, block, span);
|
||||
Some(item)
|
||||
}
|
||||
|
|
@ -1657,7 +1666,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
fn probe_assoc_item_unchecked(
|
||||
&self,
|
||||
ident: Ident,
|
||||
kind: ty::AssocKind,
|
||||
assoc_tag: ty::AssocTag,
|
||||
block: HirId,
|
||||
scope: DefId,
|
||||
) -> Option<(ty::AssocItem, /*scope*/ DefId)> {
|
||||
|
|
@ -1670,7 +1679,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let item = tcx
|
||||
.associated_items(scope)
|
||||
.filter_by_name_unhygienic(ident.name)
|
||||
.find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == ident)?;
|
||||
.find(|i| i.as_tag() == assoc_tag && i.ident(tcx).normalize_to_macros_2_0() == ident)?;
|
||||
|
||||
Some((*item, def_scope))
|
||||
}
|
||||
|
|
@ -1722,9 +1731,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
tcx.associated_items(*trait_def_id)
|
||||
.in_definition_order()
|
||||
.any(|i| {
|
||||
i.kind.namespace() == Namespace::TypeNS
|
||||
i.namespace() == Namespace::TypeNS
|
||||
&& i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
|
||||
&& matches!(i.kind, ty::AssocKind::Type)
|
||||
&& i.is_type()
|
||||
})
|
||||
// Consider only accessible traits
|
||||
&& tcx.visibility(*trait_def_id)
|
||||
|
|
@ -1770,7 +1779,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
item_def_id,
|
||||
trait_segment,
|
||||
item_segment,
|
||||
ty::AssocKind::Type,
|
||||
ty::AssocTag::Type,
|
||||
) {
|
||||
Ok((item_def_id, item_args)) => {
|
||||
Ty::new_projection_from_args(self.tcx(), item_def_id, item_args)
|
||||
|
|
@ -1795,7 +1804,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
item_def_id,
|
||||
trait_segment,
|
||||
item_segment,
|
||||
ty::AssocKind::Const,
|
||||
ty::AssocTag::Const,
|
||||
) {
|
||||
Ok((item_def_id, item_args)) => {
|
||||
let uv = ty::UnevaluatedConst::new(item_def_id, item_args);
|
||||
|
|
@ -1813,7 +1822,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
item_def_id: DefId,
|
||||
trait_segment: &hir::PathSegment<'tcx>,
|
||||
item_segment: &hir::PathSegment<'tcx>,
|
||||
kind: ty::AssocKind,
|
||||
assoc_tag: ty::AssocTag,
|
||||
) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
|
|
@ -1821,7 +1830,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
debug!(?trait_def_id);
|
||||
|
||||
let Some(self_ty) = opt_self_ty else {
|
||||
return Err(self.error_missing_qpath_self_ty(trait_def_id, span, item_segment, kind));
|
||||
return Err(self.error_missing_qpath_self_ty(
|
||||
trait_def_id,
|
||||
span,
|
||||
item_segment,
|
||||
assoc_tag,
|
||||
));
|
||||
};
|
||||
debug!(?self_ty);
|
||||
|
||||
|
|
@ -1840,7 +1854,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
trait_def_id: DefId,
|
||||
span: Span,
|
||||
item_segment: &hir::PathSegment<'tcx>,
|
||||
kind: ty::AssocKind,
|
||||
assoc_tag: ty::AssocTag,
|
||||
) -> ErrorGuaranteed {
|
||||
let tcx = self.tcx();
|
||||
let path_str = tcx.def_path_str(trait_def_id);
|
||||
|
|
@ -1877,7 +1891,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that
|
||||
// references the trait. Relevant for the first case in
|
||||
// `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs`
|
||||
self.report_ambiguous_assoc(span, &type_names, &[path_str], item_segment.ident.name, kind)
|
||||
self.report_ambiguous_assoc(
|
||||
span,
|
||||
&type_names,
|
||||
&[path_str],
|
||||
item_segment.ident.name,
|
||||
assoc_tag,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn prohibit_generic_args<'a>(
|
||||
|
|
@ -2862,7 +2882,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let assoc = tcx.associated_items(trait_ref.def_id).find_by_ident_and_kind(
|
||||
tcx,
|
||||
*ident,
|
||||
ty::AssocKind::Fn,
|
||||
ty::AssocTag::Fn,
|
||||
trait_ref.def_id,
|
||||
)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -112,14 +112,14 @@ pub(crate) fn enforce_impl_lifetime_params_are_constrained(
|
|||
.flat_map(|def_id| {
|
||||
let item = tcx.associated_item(def_id);
|
||||
match item.kind {
|
||||
ty::AssocKind::Type => {
|
||||
ty::AssocKind::Type { .. } => {
|
||||
if item.defaultness(tcx).has_value() {
|
||||
cgp::parameters_for(tcx, tcx.type_of(def_id).instantiate_identity(), true)
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
ty::AssocKind::Fn | ty::AssocKind::Const => vec![],
|
||||
ty::AssocKind::Fn { .. } | ty::AssocKind::Const { .. } => vec![],
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
|
|
|||
|
|
@ -59,7 +59,6 @@ This API is completely unstable and subject to change.
|
|||
#![allow(internal_features)]
|
||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(assert_matches)]
|
||||
|
|
|
|||
|
|
@ -1871,10 +1871,11 @@ impl<'a> State<'a> {
|
|||
fn print_pat(&mut self, pat: &hir::Pat<'_>) {
|
||||
self.maybe_print_comment(pat.span.lo());
|
||||
self.ann.pre(self, AnnNode::Pat(pat));
|
||||
// Pat isn't normalized, but the beauty of it
|
||||
// is that it doesn't matter
|
||||
// Pat isn't normalized, but the beauty of it is that it doesn't matter.
|
||||
match pat.kind {
|
||||
PatKind::Missing => unreachable!(),
|
||||
// Printing `_` isn't ideal for a missing pattern, but it's easy and good enough.
|
||||
// E.g. `fn(u32)` gets printed as `fn(_: u32)`.
|
||||
PatKind::Missing => self.word("_"),
|
||||
PatKind::Wild => self.word("_"),
|
||||
PatKind::Never => self.word("!"),
|
||||
PatKind::Binding(BindingMode(by_ref, mutbl), _, ident, sub) => {
|
||||
|
|
@ -2164,7 +2165,9 @@ impl<'a> State<'a> {
|
|||
s.end();
|
||||
});
|
||||
if decl.c_variadic {
|
||||
self.word(", ");
|
||||
if !decl.inputs.is_empty() {
|
||||
self.word(", ");
|
||||
}
|
||||
print_arg(self, None);
|
||||
self.word("...");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1042,30 +1042,31 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||
m_cast: ty::TypeAndMut<'tcx>,
|
||||
) -> Result<CastKind, CastError<'tcx>> {
|
||||
// array-ptr-cast: allow mut-to-mut, mut-to-const, const-to-const
|
||||
if m_expr.mutbl >= m_cast.mutbl {
|
||||
if let ty::Array(ety, _) = m_expr.ty.kind() {
|
||||
// Due to the limitations of LLVM global constants,
|
||||
// region pointers end up pointing at copies of
|
||||
// vector elements instead of the original values.
|
||||
// To allow raw pointers to work correctly, we
|
||||
// need to special-case obtaining a raw pointer
|
||||
// from a region pointer to a vector.
|
||||
if m_expr.mutbl >= m_cast.mutbl
|
||||
&& let ty::Array(ety, _) = m_expr.ty.kind()
|
||||
&& fcx.can_eq(fcx.param_env, *ety, m_cast.ty)
|
||||
{
|
||||
// Due to the limitations of LLVM global constants,
|
||||
// region pointers end up pointing at copies of
|
||||
// vector elements instead of the original values.
|
||||
// To allow raw pointers to work correctly, we
|
||||
// need to special-case obtaining a raw pointer
|
||||
// from a region pointer to a vector.
|
||||
|
||||
// Coerce to a raw pointer so that we generate RawPtr in MIR.
|
||||
let array_ptr_type = Ty::new_ptr(fcx.tcx, m_expr.ty, m_expr.mutbl);
|
||||
fcx.coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None)
|
||||
.unwrap_or_else(|_| {
|
||||
bug!(
|
||||
// Coerce to a raw pointer so that we generate RawPtr in MIR.
|
||||
let array_ptr_type = Ty::new_ptr(fcx.tcx, m_expr.ty, m_expr.mutbl);
|
||||
fcx.coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None)
|
||||
.unwrap_or_else(|_| {
|
||||
bug!(
|
||||
"could not cast from reference to array to pointer to array ({:?} to {:?})",
|
||||
self.expr_ty,
|
||||
array_ptr_type,
|
||||
)
|
||||
});
|
||||
});
|
||||
|
||||
// this will report a type mismatch if needed
|
||||
fcx.demand_eqtype(self.span, *ety, m_cast.ty);
|
||||
return Ok(CastKind::ArrayPtrCast);
|
||||
}
|
||||
// this will report a type mismatch if needed
|
||||
fcx.demand_eqtype(self.span, *ety, m_cast.ty);
|
||||
return Ok(CastKind::ArrayPtrCast);
|
||||
}
|
||||
|
||||
Err(CastError::IllegalCast)
|
||||
|
|
|
|||
|
|
@ -103,15 +103,6 @@ fn coerce_mutbls<'tcx>(
|
|||
if from_mutbl >= to_mutbl { Ok(()) } else { Err(TypeError::Mutability) }
|
||||
}
|
||||
|
||||
/// Do not require any adjustments, i.e. coerce `x -> x`.
|
||||
fn identity(_: Ty<'_>) -> Vec<Adjustment<'_>> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn simple<'tcx>(kind: Adjust) -> impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>> {
|
||||
move |target| vec![Adjustment { kind, target }]
|
||||
}
|
||||
|
||||
/// This always returns `Ok(...)`.
|
||||
fn success<'tcx>(
|
||||
adj: Vec<Adjustment<'tcx>>,
|
||||
|
|
@ -131,7 +122,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
Coerce { fcx, cause, allow_two_phase, use_lub: false, coerce_never }
|
||||
}
|
||||
|
||||
fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
|
||||
fn unify_raw(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
|
||||
debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub);
|
||||
self.commit_if_ok(|_| {
|
||||
let at = self.at(&self.cause, self.fcx.param_env);
|
||||
|
|
@ -161,13 +152,30 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Unify two types (using sub or lub).
|
||||
fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
|
||||
self.unify_raw(a, b)
|
||||
.and_then(|InferOk { value: ty, obligations }| success(vec![], ty, obligations))
|
||||
}
|
||||
|
||||
/// Unify two types (using sub or lub) and produce a specific coercion.
|
||||
fn unify_and<F>(&self, a: Ty<'tcx>, b: Ty<'tcx>, f: F) -> CoerceResult<'tcx>
|
||||
where
|
||||
F: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
|
||||
{
|
||||
self.unify(a, b)
|
||||
.and_then(|InferOk { value: ty, obligations }| success(f(ty), ty, obligations))
|
||||
fn unify_and(
|
||||
&self,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
adjustments: impl IntoIterator<Item = Adjustment<'tcx>>,
|
||||
final_adjustment: Adjust,
|
||||
) -> CoerceResult<'tcx> {
|
||||
self.unify_raw(a, b).and_then(|InferOk { value: ty, obligations }| {
|
||||
success(
|
||||
adjustments
|
||||
.into_iter()
|
||||
.chain(std::iter::once(Adjustment { target: ty, kind: final_adjustment }))
|
||||
.collect(),
|
||||
ty,
|
||||
obligations,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
#[instrument(skip(self))]
|
||||
|
|
@ -180,10 +188,14 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
// Coercing from `!` to any type is allowed:
|
||||
if a.is_never() {
|
||||
if self.coerce_never {
|
||||
return success(simple(Adjust::NeverToAny)(b), b, PredicateObligations::new());
|
||||
return success(
|
||||
vec![Adjustment { kind: Adjust::NeverToAny, target: b }],
|
||||
b,
|
||||
PredicateObligations::new(),
|
||||
);
|
||||
} else {
|
||||
// Otherwise the only coercion we can do is unification.
|
||||
return self.unify_and(a, b, identity);
|
||||
return self.unify(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -191,7 +203,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
// we have no information about the source type. This will always
|
||||
// ultimately fall back to some form of subtyping.
|
||||
if a.is_ty_var() {
|
||||
return self.coerce_from_inference_variable(a, b, identity);
|
||||
return self.coerce_from_inference_variable(a, b);
|
||||
}
|
||||
|
||||
// Consider coercing the subtype to a DST
|
||||
|
|
@ -247,7 +259,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
ty::FnPtr(a_sig_tys, a_hdr) => {
|
||||
// We permit coercion of fn pointers to drop the
|
||||
// unsafe qualifier.
|
||||
self.coerce_from_fn_pointer(a, a_sig_tys.with(a_hdr), b)
|
||||
self.coerce_from_fn_pointer(a_sig_tys.with(a_hdr), b)
|
||||
}
|
||||
ty::Closure(closure_def_id_a, args_a) => {
|
||||
// Non-capturing closures are coercible to
|
||||
|
|
@ -257,7 +269,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
}
|
||||
_ => {
|
||||
// Otherwise, just use unification rules.
|
||||
self.unify_and(a, b, identity)
|
||||
self.unify(a, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -265,12 +277,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
/// Coercing *from* an inference variable. In this case, we have no information
|
||||
/// about the source type, so we can't really do a true coercion and we always
|
||||
/// fall back to subtyping (`unify_and`).
|
||||
fn coerce_from_inference_variable(
|
||||
&self,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
make_adjustments: impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
|
||||
) -> CoerceResult<'tcx> {
|
||||
fn coerce_from_inference_variable(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
|
||||
debug!("coerce_from_inference_variable(a={:?}, b={:?})", a, b);
|
||||
assert!(a.is_ty_var() && self.shallow_resolve(a) == a);
|
||||
assert!(self.shallow_resolve(b) == b);
|
||||
|
|
@ -298,12 +305,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
"coerce_from_inference_variable: two inference variables, target_ty={:?}, obligations={:?}",
|
||||
target_ty, obligations
|
||||
);
|
||||
let adjustments = make_adjustments(target_ty);
|
||||
InferResult::Ok(InferOk { value: (adjustments, target_ty), obligations })
|
||||
success(vec![], target_ty, obligations)
|
||||
} else {
|
||||
// One unresolved type variable: just apply subtyping, we may be able
|
||||
// to do something useful.
|
||||
self.unify_and(a, b, make_adjustments)
|
||||
self.unify(a, b)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -331,7 +337,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
coerce_mutbls(mt_a.mutbl, mutbl_b)?;
|
||||
(r_a, mt_a)
|
||||
}
|
||||
_ => return self.unify_and(a, b, identity),
|
||||
_ => return self.unify(a, b),
|
||||
};
|
||||
|
||||
let span = self.cause.span;
|
||||
|
|
@ -437,7 +443,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
referent_ty,
|
||||
mutbl_b, // [1] above
|
||||
);
|
||||
match self.unify(derefd_ty_a, b) {
|
||||
match self.unify_raw(derefd_ty_a, b) {
|
||||
Ok(ok) => {
|
||||
found = Some(ok);
|
||||
break;
|
||||
|
|
@ -579,13 +585,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
// We only have the latter, so we use an inference variable
|
||||
// for the former and let type inference do the rest.
|
||||
let coerce_target = self.next_ty_var(self.cause.span);
|
||||
let mut coercion = self.unify_and(coerce_target, target, |target| {
|
||||
let unsize = Adjustment { kind: Adjust::Pointer(PointerCoercion::Unsize), target };
|
||||
match reborrow {
|
||||
None => vec![unsize],
|
||||
Some((ref deref, ref autoref)) => vec![deref.clone(), autoref.clone(), unsize],
|
||||
}
|
||||
})?;
|
||||
|
||||
let mut coercion = self.unify_and(
|
||||
coerce_target,
|
||||
target,
|
||||
reborrow.into_iter().flat_map(|(deref, autoref)| [deref, autoref]),
|
||||
Adjust::Pointer(PointerCoercion::Unsize),
|
||||
)?;
|
||||
|
||||
let mut selcx = traits::SelectionContext::new(self);
|
||||
|
||||
|
|
@ -708,7 +714,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
&& let ty::Dynamic(b_data, _, ty::DynStar) = b.kind()
|
||||
&& a_data.principal_def_id() == b_data.principal_def_id()
|
||||
{
|
||||
return self.unify_and(a, b, |_| vec![]);
|
||||
return self.unify(a, b);
|
||||
}
|
||||
|
||||
// Check the obligations of the cast -- for example, when casting
|
||||
|
|
@ -808,23 +814,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
|
||||
// To complete the reborrow, we need to make sure we can unify the inner types, and if so we
|
||||
// add the adjustments.
|
||||
self.unify_and(a, b, |_inner_ty| {
|
||||
vec![Adjustment { kind: Adjust::ReborrowPin(mut_b), target: b }]
|
||||
})
|
||||
self.unify_and(a, b, [], Adjust::ReborrowPin(mut_b))
|
||||
}
|
||||
|
||||
fn coerce_from_safe_fn<F, G>(
|
||||
fn coerce_from_safe_fn(
|
||||
&self,
|
||||
a: Ty<'tcx>,
|
||||
fn_ty_a: ty::PolyFnSig<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
to_unsafe: F,
|
||||
normal: G,
|
||||
) -> CoerceResult<'tcx>
|
||||
where
|
||||
F: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
|
||||
G: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
|
||||
{
|
||||
adjustment: Option<Adjust>,
|
||||
) -> CoerceResult<'tcx> {
|
||||
self.commit_if_ok(|snapshot| {
|
||||
let outer_universe = self.infcx.universe();
|
||||
|
||||
|
|
@ -833,9 +831,19 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
&& hdr_b.safety.is_unsafe()
|
||||
{
|
||||
let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a);
|
||||
self.unify_and(unsafe_a, b, to_unsafe)
|
||||
self.unify_and(
|
||||
unsafe_a,
|
||||
b,
|
||||
adjustment
|
||||
.map(|kind| Adjustment { kind, target: Ty::new_fn_ptr(self.tcx, fn_ty_a) }),
|
||||
Adjust::Pointer(PointerCoercion::UnsafeFnPointer),
|
||||
)
|
||||
} else {
|
||||
self.unify_and(a, b, normal)
|
||||
let a = Ty::new_fn_ptr(self.tcx, fn_ty_a);
|
||||
match adjustment {
|
||||
Some(adjust) => self.unify_and(a, b, [], adjust),
|
||||
None => self.unify(a, b),
|
||||
}
|
||||
};
|
||||
|
||||
// FIXME(#73154): This is a hack. Currently LUB can generate
|
||||
|
|
@ -852,7 +860,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
|
||||
fn coerce_from_fn_pointer(
|
||||
&self,
|
||||
a: Ty<'tcx>,
|
||||
fn_ty_a: ty::PolyFnSig<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
) -> CoerceResult<'tcx> {
|
||||
|
|
@ -861,15 +868,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
//!
|
||||
|
||||
let b = self.shallow_resolve(b);
|
||||
debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b);
|
||||
debug!(?fn_ty_a, ?b, "coerce_from_fn_pointer");
|
||||
|
||||
self.coerce_from_safe_fn(
|
||||
a,
|
||||
fn_ty_a,
|
||||
b,
|
||||
simple(Adjust::Pointer(PointerCoercion::UnsafeFnPointer)),
|
||||
identity,
|
||||
)
|
||||
self.coerce_from_safe_fn(fn_ty_a, b, None)
|
||||
}
|
||||
|
||||
fn coerce_from_fn_item(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
|
||||
|
|
@ -916,30 +917,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
self.at(&self.cause, self.param_env).normalize(a_sig);
|
||||
obligations.extend(o1);
|
||||
|
||||
let a_fn_pointer = Ty::new_fn_ptr(self.tcx, a_sig);
|
||||
let InferOk { value, obligations: o2 } = self.coerce_from_safe_fn(
|
||||
a_fn_pointer,
|
||||
a_sig,
|
||||
b,
|
||||
|unsafe_ty| {
|
||||
vec![
|
||||
Adjustment {
|
||||
kind: Adjust::Pointer(PointerCoercion::ReifyFnPointer),
|
||||
target: a_fn_pointer,
|
||||
},
|
||||
Adjustment {
|
||||
kind: Adjust::Pointer(PointerCoercion::UnsafeFnPointer),
|
||||
target: unsafe_ty,
|
||||
},
|
||||
]
|
||||
},
|
||||
simple(Adjust::Pointer(PointerCoercion::ReifyFnPointer)),
|
||||
Some(Adjust::Pointer(PointerCoercion::ReifyFnPointer)),
|
||||
)?;
|
||||
|
||||
obligations.extend(o2);
|
||||
Ok(InferOk { value, obligations })
|
||||
}
|
||||
_ => self.unify_and(a, b, identity),
|
||||
_ => self.unify(a, b),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -983,10 +970,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
self.unify_and(
|
||||
pointer_ty,
|
||||
b,
|
||||
simple(Adjust::Pointer(PointerCoercion::ClosureFnPointer(safety))),
|
||||
[],
|
||||
Adjust::Pointer(PointerCoercion::ClosureFnPointer(safety)),
|
||||
)
|
||||
}
|
||||
_ => self.unify_and(a, b, identity),
|
||||
_ => self.unify(a, b),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1001,7 +989,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
let (is_ref, mt_a) = match *a.kind() {
|
||||
ty::Ref(_, ty, mutbl) => (true, ty::TypeAndMut { ty, mutbl }),
|
||||
ty::RawPtr(ty, mutbl) => (false, ty::TypeAndMut { ty, mutbl }),
|
||||
_ => return self.unify_and(a, b, identity),
|
||||
_ => return self.unify(a, b),
|
||||
};
|
||||
coerce_mutbls(mt_a.mutbl, mutbl_b)?;
|
||||
|
||||
|
|
@ -1011,16 +999,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
// representation, we still register an Adjust::DerefRef so that
|
||||
// regionck knows that the region for `a` must be valid here.
|
||||
if is_ref {
|
||||
self.unify_and(a_raw, b, |target| {
|
||||
vec![
|
||||
Adjustment { kind: Adjust::Deref(None), target: mt_a.ty },
|
||||
Adjustment { kind: Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)), target },
|
||||
]
|
||||
})
|
||||
self.unify_and(
|
||||
a_raw,
|
||||
b,
|
||||
[Adjustment { kind: Adjust::Deref(None), target: mt_a.ty }],
|
||||
Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)),
|
||||
)
|
||||
} else if mt_a.mutbl != mutbl_b {
|
||||
self.unify_and(a_raw, b, simple(Adjust::Pointer(PointerCoercion::MutToConstPointer)))
|
||||
self.unify_and(a_raw, b, [], Adjust::Pointer(PointerCoercion::MutToConstPointer))
|
||||
} else {
|
||||
self.unify_and(a_raw, b, identity)
|
||||
self.unify(a_raw, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1118,9 +1106,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let cause = self.cause(DUMMY_SP, ObligationCauseCode::ExprAssignable);
|
||||
// We don't ever need two-phase here since we throw out the result of the coercion.
|
||||
let coerce = Coerce::new(self, cause, AllowTwoPhase::No, true);
|
||||
coerce
|
||||
.autoderef(DUMMY_SP, expr_ty)
|
||||
.find_map(|(ty, steps)| self.probe(|_| coerce.unify(ty, target)).ok().map(|_| steps))
|
||||
coerce.autoderef(DUMMY_SP, expr_ty).find_map(|(ty, steps)| {
|
||||
self.probe(|_| coerce.unify_raw(ty, target)).ok().map(|_| steps)
|
||||
})
|
||||
}
|
||||
|
||||
/// Given a type, this function will calculate and return the type given
|
||||
|
|
|
|||
|
|
@ -1089,14 +1089,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
/// This function checks whether the method is not static and does not accept other parameters than `self`.
|
||||
fn has_only_self_parameter(&self, method: &AssocItem) -> bool {
|
||||
match method.kind {
|
||||
ty::AssocKind::Fn => {
|
||||
method.fn_has_self_parameter
|
||||
&& self.tcx.fn_sig(method.def_id).skip_binder().inputs().skip_binder().len()
|
||||
== 1
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
method.is_method()
|
||||
&& self.tcx.fn_sig(method.def_id).skip_binder().inputs().skip_binder().len() == 1
|
||||
}
|
||||
|
||||
/// If the given `HirId` corresponds to a block with a trailing expression, return that expression
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue