Auto merge of #2842 - RalfJung:rustup, r=RalfJung
Rustup Also add a test for https://github.com/rust-lang/rust/issues/110233
This commit is contained in:
commit
cf6b8623bc
68
Cargo.lock
68
Cargo.lock
@ -830,6 +830,7 @@ dependencies = [
|
||||
name = "clippy_lints"
|
||||
version = "0.1.70"
|
||||
dependencies = [
|
||||
"arrayvec 0.7.0",
|
||||
"cargo_metadata 0.15.3",
|
||||
"clippy_utils",
|
||||
"declare_clippy_lint",
|
||||
@ -1685,9 +1686,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.19"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28560757fe2bb34e79f907794bb6b22ae8b0e5c669b638a1132f2592b19035b4"
|
||||
checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
@ -1700,9 +1701,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.19"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b"
|
||||
checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
@ -1710,15 +1711,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.19"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7"
|
||||
checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.19"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29d6d2ff5bb10fb95c85b8ce46538a2e5f5e7fdc755623a7d4529ab8a4ed9d2a"
|
||||
checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
@ -1727,38 +1728,38 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.19"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2"
|
||||
checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.19"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6dbd947adfffb0efc70599b3ddcf7b5597bb5fa9e245eb99f62b3a5f7bb8bd3c"
|
||||
checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.102",
|
||||
"syn 2.0.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.19"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508"
|
||||
checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.19"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72"
|
||||
checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.19"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164"
|
||||
checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
@ -1841,9 +1842,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "git2"
|
||||
version = "0.16.0"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be36bc9e0546df253c0cc41fd0af34f5e92845ad8509462ec76672fac6997f5b"
|
||||
checksum = "89511277159354bea13ae1e53e0c9ab85ba1b20d7e91618fa30e6bc5566857fb"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
@ -1856,9 +1857,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "git2-curl"
|
||||
version = "0.17.0"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7577f4e6341ba7c90d883511130a45b956c274ba5f4d205d9f9da990f654cd33"
|
||||
checksum = "f8f8b7432b72928cff76f69e59ed5327f94a52763731e71274960dee72fe5f8c"
|
||||
dependencies = [
|
||||
"curl",
|
||||
"git2",
|
||||
@ -2768,13 +2769,11 @@ dependencies = [
|
||||
"anyhow",
|
||||
"clap 3.2.20",
|
||||
"flate2",
|
||||
"lazy_static",
|
||||
"num_cpus",
|
||||
"rayon",
|
||||
"remove_dir_all",
|
||||
"tar",
|
||||
"walkdir",
|
||||
"winapi",
|
||||
"xz2",
|
||||
]
|
||||
|
||||
@ -2962,9 +2961,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libgit2-sys"
|
||||
version = "0.14.1+1.5.0"
|
||||
version = "0.15.0+1.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a07fb2692bc3593bda59de45a502bb3071659f2c515e28c71e728306b038e17"
|
||||
checksum = "032e537ae4dd4e50c877f258dc55fcd0657b5021f454094a425bb6bcc9edea4c"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
@ -3002,9 +3001,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libssh2-sys"
|
||||
version = "0.2.23"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b094a36eb4b8b8c8a7b4b8ae43b2944502be3e59cd87687595cf6b0a71b3f4ca"
|
||||
checksum = "2dc8a030b787e2119a731f1951d6a773e2280c660f8ec4b0f5e1505a386e71ee"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
@ -4575,6 +4574,7 @@ dependencies = [
|
||||
"elsa",
|
||||
"ena",
|
||||
"indexmap",
|
||||
"itertools",
|
||||
"jobserver",
|
||||
"libc",
|
||||
"measureme",
|
||||
@ -5723,9 +5723,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.147"
|
||||
version = "1.0.159"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
|
||||
checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
@ -5742,13 +5742,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.147"
|
||||
version = "1.0.159"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
|
||||
checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.102",
|
||||
"syn 2.0.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -167,9 +167,6 @@ pub enum GenericArgs {
|
||||
AngleBracketed(AngleBracketedArgs),
|
||||
/// The `(A, B)` and `C` in `Foo(A, B) -> C`.
|
||||
Parenthesized(ParenthesizedArgs),
|
||||
/// Associated return type bounds, like `T: Trait<method(..): Send>`
|
||||
/// which applies the `Send` bound to the return-type of `method`.
|
||||
ReturnTypeNotation(Span),
|
||||
}
|
||||
|
||||
impl GenericArgs {
|
||||
@ -181,7 +178,6 @@ impl GenericArgs {
|
||||
match self {
|
||||
AngleBracketed(data) => data.span,
|
||||
Parenthesized(data) => data.span,
|
||||
ReturnTypeNotation(span) => *span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ impl FormatArguments {
|
||||
}
|
||||
if !matches!(arg.kind, FormatArgumentKind::Captured(..)) {
|
||||
// This is an explicit argument.
|
||||
// Make sure that all arguments so far are explcit.
|
||||
// Make sure that all arguments so far are explicit.
|
||||
assert_eq!(
|
||||
self.num_explicit_args,
|
||||
self.arguments.len(),
|
||||
|
@ -561,7 +561,6 @@ pub fn noop_visit_generic_args<T: MutVisitor>(generic_args: &mut GenericArgs, vi
|
||||
match generic_args {
|
||||
GenericArgs::AngleBracketed(data) => vis.visit_angle_bracketed_parameter_data(data),
|
||||
GenericArgs::Parenthesized(data) => vis.visit_parenthesized_parameter_data(data),
|
||||
GenericArgs::ReturnTypeNotation(_span) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -482,7 +482,6 @@ where
|
||||
walk_list!(visitor, visit_ty, &data.inputs);
|
||||
walk_fn_ret_ty(visitor, &data.output);
|
||||
}
|
||||
GenericArgs::ReturnTypeNotation(_span) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,7 +137,7 @@ pub struct AsyncNonMoveClosureNotSupported {
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering_functional_record_update_destructuring_assignment)]
|
||||
pub struct FunctionalRecordUpdateDestructuringAssignemnt {
|
||||
pub struct FunctionalRecordUpdateDestructuringAssignment {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "", applicability = "machine-applicable")]
|
||||
pub span: Span,
|
||||
@ -353,13 +353,7 @@ pub enum BadReturnTypeNotation {
|
||||
#[diag(ast_lowering_bad_return_type_notation_inputs)]
|
||||
Inputs {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "(..)", applicability = "maybe-incorrect")]
|
||||
span: Span,
|
||||
},
|
||||
#[diag(ast_lowering_bad_return_type_notation_needs_dots)]
|
||||
NeedsDots {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "(..)", applicability = "maybe-incorrect")]
|
||||
#[suggestion(code = "()", applicability = "maybe-incorrect")]
|
||||
span: Span,
|
||||
},
|
||||
#[diag(ast_lowering_bad_return_type_notation_output)]
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::errors::{
|
||||
AsyncGeneratorsNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks,
|
||||
BaseExpressionDoubleDot, ClosureCannotBeStatic, FunctionalRecordUpdateDestructuringAssignemnt,
|
||||
BaseExpressionDoubleDot, ClosureCannotBeStatic, FunctionalRecordUpdateDestructuringAssignment,
|
||||
GeneratorTooManyParameters, InclusiveRangeWithNoEnd, NotSupportedForLifetimeBinderAsyncClosure,
|
||||
UnderscoreExprLhsAssign,
|
||||
};
|
||||
@ -434,7 +434,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
// `if let pat = val` or `if foo && let pat = val`, as we _do_ want `val` to live beyond the
|
||||
// condition in this case.
|
||||
//
|
||||
// In order to mantain the drop behavior for the non `let` parts of the condition,
|
||||
// In order to maintain the drop behavior for the non `let` parts of the condition,
|
||||
// we still wrap them in terminating scopes, e.g. `if foo && let pat = val` essentially
|
||||
// gets transformed into `if { let _t = foo; _t } && let pat = val`
|
||||
match &cond.kind {
|
||||
@ -1232,7 +1232,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
);
|
||||
let fields_omitted = match &se.rest {
|
||||
StructRest::Base(e) => {
|
||||
self.tcx.sess.emit_err(FunctionalRecordUpdateDestructuringAssignemnt {
|
||||
self.tcx.sess.emit_err(FunctionalRecordUpdateDestructuringAssignment {
|
||||
span: e.span,
|
||||
});
|
||||
true
|
||||
|
@ -987,15 +987,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
GenericArgs::AngleBracketed(data) => {
|
||||
self.lower_angle_bracketed_parameter_data(data, ParamMode::Explicit, itctx).0
|
||||
}
|
||||
&GenericArgs::ReturnTypeNotation(span) => GenericArgsCtor {
|
||||
args: Default::default(),
|
||||
bindings: &[],
|
||||
parenthesized: hir::GenericArgsParentheses::ReturnTypeNotation,
|
||||
span,
|
||||
},
|
||||
GenericArgs::Parenthesized(data) => {
|
||||
if let Some(start_char) = constraint.ident.as_str().chars().next()
|
||||
&& start_char.is_ascii_lowercase()
|
||||
if data.inputs.is_empty() && matches!(data.output, FnRetTy::Default(..)) {
|
||||
let parenthesized = if self.tcx.features().return_type_notation {
|
||||
hir::GenericArgsParentheses::ReturnTypeNotation
|
||||
} else {
|
||||
self.emit_bad_parenthesized_trait_in_assoc_ty(data);
|
||||
hir::GenericArgsParentheses::No
|
||||
};
|
||||
GenericArgsCtor {
|
||||
args: Default::default(),
|
||||
bindings: &[],
|
||||
parenthesized,
|
||||
span: data.inputs_span,
|
||||
}
|
||||
} else if let Some(first_char) = constraint.ident.as_str().chars().next()
|
||||
&& first_char.is_ascii_lowercase()
|
||||
{
|
||||
let mut err = if !data.inputs.is_empty() {
|
||||
self.tcx.sess.create_err(errors::BadReturnTypeNotation::Inputs {
|
||||
@ -1006,9 +1013,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
span: data.inputs_span.shrink_to_hi().to(ty.span),
|
||||
})
|
||||
} else {
|
||||
self.tcx.sess.create_err(errors::BadReturnTypeNotation::NeedsDots {
|
||||
span: data.inputs_span,
|
||||
})
|
||||
unreachable!("inputs are empty and return type is not provided")
|
||||
};
|
||||
if !self.tcx.features().return_type_notation
|
||||
&& self.tcx.sess.is_nightly_build()
|
||||
|
@ -13,7 +13,6 @@ use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::{BytePos, Span, DUMMY_SP};
|
||||
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
@ -219,18 +218,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
)
|
||||
}
|
||||
},
|
||||
&GenericArgs::ReturnTypeNotation(span) => {
|
||||
self.tcx.sess.emit_err(GenericTypeWithParentheses { span, sub: None });
|
||||
(
|
||||
self.lower_angle_bracketed_parameter_data(
|
||||
&AngleBracketedArgs { span, args: ThinVec::default() },
|
||||
param_mode,
|
||||
itctx,
|
||||
)
|
||||
.0,
|
||||
false,
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
(
|
||||
|
@ -17,9 +17,10 @@ ast_passes_keyword_lifetime =
|
||||
ast_passes_invalid_label =
|
||||
invalid label name `{$name}`
|
||||
|
||||
ast_passes_invalid_visibility =
|
||||
unnecessary visibility qualifier
|
||||
.implied = `pub` not permitted here because it's implied
|
||||
ast_passes_visibility_not_permitted =
|
||||
visibility qualifiers are not permitted here
|
||||
.enum_variant = enum variants and their fields always share the visibility of the enum they are in
|
||||
.trait_impl = trait items always share the visibility of their trait
|
||||
.individual_impl_items = place qualifiers on individual impl items instead
|
||||
.individual_foreign_items = place qualifiers on individual foreign items instead
|
||||
|
||||
|
@ -240,16 +240,12 @@ impl<'a> AstValidator<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn invalid_visibility(&self, vis: &Visibility, note: Option<errors::InvalidVisibilityNote>) {
|
||||
fn visibility_not_permitted(&self, vis: &Visibility, note: errors::VisibilityNotPermittedNote) {
|
||||
if let VisibilityKind::Inherited = vis.kind {
|
||||
return;
|
||||
}
|
||||
|
||||
self.session.emit_err(errors::InvalidVisibility {
|
||||
span: vis.span,
|
||||
implied: vis.kind.is_pub().then_some(vis.span),
|
||||
note,
|
||||
});
|
||||
self.session.emit_err(errors::VisibilityNotPermitted { span: vis.span, note });
|
||||
}
|
||||
|
||||
fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
|
||||
@ -819,7 +815,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
items,
|
||||
}) => {
|
||||
self.with_in_trait_impl(true, Some(*constness), |this| {
|
||||
this.invalid_visibility(&item.vis, None);
|
||||
this.visibility_not_permitted(
|
||||
&item.vis,
|
||||
errors::VisibilityNotPermittedNote::TraitImpl,
|
||||
);
|
||||
if let TyKind::Err = self_ty.kind {
|
||||
this.err_handler().emit_err(errors::ObsoleteAuto { span: item.span });
|
||||
}
|
||||
@ -866,9 +865,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
only_trait: only_trait.then_some(()),
|
||||
};
|
||||
|
||||
self.invalid_visibility(
|
||||
self.visibility_not_permitted(
|
||||
&item.vis,
|
||||
Some(errors::InvalidVisibilityNote::IndividualImplItems),
|
||||
errors::VisibilityNotPermittedNote::IndividualImplItems,
|
||||
);
|
||||
if let &Unsafe::Yes(span) = unsafety {
|
||||
self.err_handler().emit_err(errors::InherentImplCannotUnsafe {
|
||||
@ -924,9 +923,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
}
|
||||
ItemKind::ForeignMod(ForeignMod { abi, unsafety, .. }) => {
|
||||
let old_item = mem::replace(&mut self.extern_mod, Some(item));
|
||||
self.invalid_visibility(
|
||||
self.visibility_not_permitted(
|
||||
&item.vis,
|
||||
Some(errors::InvalidVisibilityNote::IndividualForeignItems),
|
||||
errors::VisibilityNotPermittedNote::IndividualForeignItems,
|
||||
);
|
||||
if let &Unsafe::Yes(span) = unsafety {
|
||||
self.err_handler().emit_err(errors::UnsafeItem { span, kind: "extern block" });
|
||||
@ -940,9 +939,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
}
|
||||
ItemKind::Enum(def, _) => {
|
||||
for variant in &def.variants {
|
||||
self.invalid_visibility(&variant.vis, None);
|
||||
self.visibility_not_permitted(
|
||||
&variant.vis,
|
||||
errors::VisibilityNotPermittedNote::EnumVariant,
|
||||
);
|
||||
for field in variant.data.fields() {
|
||||
self.invalid_visibility(&field.vis, None);
|
||||
self.visibility_not_permitted(
|
||||
&field.vis,
|
||||
errors::VisibilityNotPermittedNote::EnumVariant,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1075,7 +1080,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
self.with_impl_trait(None, |this| this.visit_ty(ty));
|
||||
}
|
||||
}
|
||||
GenericArgs::ReturnTypeNotation(_span) => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1301,7 +1305,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
}
|
||||
|
||||
if ctxt == AssocCtxt::Trait || self.in_trait_impl {
|
||||
self.invalid_visibility(&item.vis, None);
|
||||
self.visibility_not_permitted(&item.vis, errors::VisibilityNotPermittedNote::TraitImpl);
|
||||
if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
|
||||
self.check_trait_fn_not_const(sig.header.constness);
|
||||
}
|
||||
@ -1386,7 +1390,6 @@ fn deny_equality_constraints(
|
||||
match &mut assoc_path.segments[len].args {
|
||||
Some(args) => match args.deref_mut() {
|
||||
GenericArgs::Parenthesized(_) => continue,
|
||||
GenericArgs::ReturnTypeNotation(_span) => continue,
|
||||
GenericArgs::AngleBracketed(args) => {
|
||||
args.args.push(arg);
|
||||
}
|
||||
|
@ -42,18 +42,20 @@ pub struct InvalidLabel {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_invalid_visibility, code = "E0449")]
|
||||
pub struct InvalidVisibility {
|
||||
#[diag(ast_passes_visibility_not_permitted, code = "E0449")]
|
||||
pub struct VisibilityNotPermitted {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label(ast_passes_implied)]
|
||||
pub implied: Option<Span>,
|
||||
#[subdiagnostic]
|
||||
pub note: Option<InvalidVisibilityNote>,
|
||||
pub note: VisibilityNotPermittedNote,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum InvalidVisibilityNote {
|
||||
pub enum VisibilityNotPermittedNote {
|
||||
#[note(ast_passes_enum_variant)]
|
||||
EnumVariant,
|
||||
#[note(ast_passes_trait_impl)]
|
||||
TraitImpl,
|
||||
#[note(ast_passes_individual_impl_items)]
|
||||
IndividualImplItems,
|
||||
#[note(ast_passes_individual_foreign_items)]
|
||||
|
@ -121,24 +121,34 @@ impl<'a> PostExpansionVisitor<'a> {
|
||||
}
|
||||
|
||||
/// Feature gate `impl Trait` inside `type Alias = $type_expr;`.
|
||||
fn check_impl_trait(&self, ty: &ast::Ty) {
|
||||
fn check_impl_trait(&self, ty: &ast::Ty, in_associated_ty: bool) {
|
||||
struct ImplTraitVisitor<'a> {
|
||||
vis: &'a PostExpansionVisitor<'a>,
|
||||
in_associated_ty: bool,
|
||||
}
|
||||
impl Visitor<'_> for ImplTraitVisitor<'_> {
|
||||
fn visit_ty(&mut self, ty: &ast::Ty) {
|
||||
if let ast::TyKind::ImplTrait(..) = ty.kind {
|
||||
gate_feature_post!(
|
||||
&self.vis,
|
||||
type_alias_impl_trait,
|
||||
ty.span,
|
||||
"`impl Trait` in type aliases is unstable"
|
||||
);
|
||||
if self.in_associated_ty {
|
||||
gate_feature_post!(
|
||||
&self.vis,
|
||||
impl_trait_in_assoc_type,
|
||||
ty.span,
|
||||
"`impl Trait` in associated types is unstable"
|
||||
);
|
||||
} else {
|
||||
gate_feature_post!(
|
||||
&self.vis,
|
||||
type_alias_impl_trait,
|
||||
ty.span,
|
||||
"`impl Trait` in type aliases is unstable"
|
||||
);
|
||||
}
|
||||
}
|
||||
visit::walk_ty(self, ty);
|
||||
}
|
||||
}
|
||||
ImplTraitVisitor { vis: self }.visit_ty(ty);
|
||||
ImplTraitVisitor { vis: self, in_associated_ty }.visit_ty(ty);
|
||||
}
|
||||
|
||||
fn check_late_bound_lifetime_defs(&self, params: &[ast::GenericParam]) {
|
||||
@ -294,7 +304,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
}
|
||||
|
||||
ast::ItemKind::TyAlias(box ast::TyAlias { ty: Some(ty), .. }) => {
|
||||
self.check_impl_trait(&ty)
|
||||
self.check_impl_trait(&ty, false)
|
||||
}
|
||||
|
||||
_ => {}
|
||||
@ -485,20 +495,23 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
|
||||
fn visit_assoc_constraint(&mut self, constraint: &'a AssocConstraint) {
|
||||
if let AssocConstraintKind::Bound { .. } = constraint.kind {
|
||||
if let Some(args) = constraint.gen_args.as_ref()
|
||||
&& matches!(
|
||||
args,
|
||||
ast::GenericArgs::ReturnTypeNotation(..)
|
||||
)
|
||||
if let Some(ast::GenericArgs::Parenthesized(args)) = constraint.gen_args.as_ref()
|
||||
&& args.inputs.is_empty()
|
||||
&& matches!(args.output, ast::FnRetTy::Default(..))
|
||||
{
|
||||
// RTN is gated below with a `gate_all`.
|
||||
gate_feature_post!(
|
||||
&self,
|
||||
return_type_notation,
|
||||
constraint.span,
|
||||
"return type notation is experimental"
|
||||
);
|
||||
} else {
|
||||
gate_feature_post!(
|
||||
&self,
|
||||
associated_type_bounds,
|
||||
constraint.span,
|
||||
"associated type bounds are unstable"
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
visit::walk_assoc_constraint(self, constraint)
|
||||
@ -517,7 +530,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
);
|
||||
}
|
||||
if let Some(ty) = ty {
|
||||
self.check_impl_trait(ty);
|
||||
self.check_impl_trait(ty, true);
|
||||
}
|
||||
false
|
||||
}
|
||||
@ -589,7 +602,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
|
||||
gate_all!(yeet_expr, "`do yeet` expression is experimental");
|
||||
gate_all!(dyn_star, "`dyn*` trait objects are experimental");
|
||||
gate_all!(const_closures, "const closures are experimental");
|
||||
gate_all!(return_type_notation, "return type notation is experimental");
|
||||
|
||||
// All uses of `gate_all!` below this point were added in #65742,
|
||||
// and subsequently disabled (with the non-early gating readded).
|
||||
@ -605,6 +617,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
|
||||
|
||||
gate_all!(trait_alias, "trait aliases are experimental");
|
||||
gate_all!(associated_type_bounds, "associated type bounds are unstable");
|
||||
gate_all!(return_type_notation, "return type notation is experimental");
|
||||
gate_all!(decl_macro, "`macro` is experimental");
|
||||
gate_all!(box_patterns, "box pattern syntax is experimental");
|
||||
gate_all!(exclusive_range_pattern, "exclusive range pattern syntax is experimental");
|
||||
|
@ -936,10 +936,6 @@ impl<'a> PrintState<'a> for State<'a> {
|
||||
self.word(")");
|
||||
self.print_fn_ret_ty(&data.output);
|
||||
}
|
||||
|
||||
ast::GenericArgs::ReturnTypeNotation(_span) => {
|
||||
self.word("(..)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
use crate::nll::ToRegionVid;
|
||||
use crate::path_utils::allow_two_phase_borrow;
|
||||
use crate::place_ext::PlaceExt;
|
||||
use crate::BorrowIndex;
|
||||
@ -204,7 +203,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> {
|
||||
return;
|
||||
}
|
||||
|
||||
let region = region.to_region_vid();
|
||||
let region = region.as_var();
|
||||
|
||||
let borrow = BorrowData {
|
||||
kind,
|
||||
@ -279,7 +278,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> {
|
||||
let borrow_data = &self.location_map[&location];
|
||||
assert_eq!(borrow_data.reserve_location, location);
|
||||
assert_eq!(borrow_data.kind, kind);
|
||||
assert_eq!(borrow_data.region, region.to_region_vid());
|
||||
assert_eq!(borrow_data.region, region.as_var());
|
||||
assert_eq!(borrow_data.borrowed_place, place);
|
||||
}
|
||||
|
||||
|
@ -12,8 +12,8 @@ use rustc_middle::ty::visit::TypeVisitable;
|
||||
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
|
||||
|
||||
use crate::{
|
||||
borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, nll::ToRegionVid,
|
||||
places_conflict, region_infer::values::LivenessValues,
|
||||
borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, places_conflict,
|
||||
region_infer::values::LivenessValues,
|
||||
};
|
||||
|
||||
pub(super) fn generate_constraints<'tcx>(
|
||||
@ -170,7 +170,7 @@ impl<'cx, 'tcx> ConstraintGeneration<'cx, 'tcx> {
|
||||
debug!("add_regular_live_constraint(live_ty={:?}, location={:?})", live_ty, location);
|
||||
|
||||
self.infcx.tcx.for_each_free_region(&live_ty, |live_region| {
|
||||
let vid = live_region.to_region_vid();
|
||||
let vid = live_region.as_var();
|
||||
self.liveness_constraints.add_element(vid, location);
|
||||
});
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ use crate::{
|
||||
/// The construct graph organizes the constraints by their end-points.
|
||||
/// It can be used to view a `R1: R2` constraint as either an edge `R1
|
||||
/// -> R2` or `R2 -> R1` depending on the direction type `D`.
|
||||
pub(crate) struct ConstraintGraph<D: ConstraintGraphDirecton> {
|
||||
pub(crate) struct ConstraintGraph<D: ConstraintGraphDirection> {
|
||||
_direction: D,
|
||||
first_constraints: IndexVec<RegionVid, Option<OutlivesConstraintIndex>>,
|
||||
next_constraints: IndexVec<OutlivesConstraintIndex, Option<OutlivesConstraintIndex>>,
|
||||
@ -25,7 +25,7 @@ pub(crate) type ReverseConstraintGraph = ConstraintGraph<Reverse>;
|
||||
|
||||
/// Marker trait that controls whether a `R1: R2` constraint
|
||||
/// represents an edge `R1 -> R2` or `R2 -> R1`.
|
||||
pub(crate) trait ConstraintGraphDirecton: Copy + 'static {
|
||||
pub(crate) trait ConstraintGraphDirection: Copy + 'static {
|
||||
fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid;
|
||||
fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid;
|
||||
fn is_normal() -> bool;
|
||||
@ -38,7 +38,7 @@ pub(crate) trait ConstraintGraphDirecton: Copy + 'static {
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub(crate) struct Normal;
|
||||
|
||||
impl ConstraintGraphDirecton for Normal {
|
||||
impl ConstraintGraphDirection for Normal {
|
||||
fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid {
|
||||
c.sup
|
||||
}
|
||||
@ -59,7 +59,7 @@ impl ConstraintGraphDirecton for Normal {
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub(crate) struct Reverse;
|
||||
|
||||
impl ConstraintGraphDirecton for Reverse {
|
||||
impl ConstraintGraphDirection for Reverse {
|
||||
fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid {
|
||||
c.sub
|
||||
}
|
||||
@ -73,7 +73,7 @@ impl ConstraintGraphDirecton for Reverse {
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: ConstraintGraphDirecton> ConstraintGraph<D> {
|
||||
impl<D: ConstraintGraphDirection> ConstraintGraph<D> {
|
||||
/// Creates a "dependency graph" where each region constraint `R1:
|
||||
/// R2` is treated as an edge `R1 -> R2`. We use this graph to
|
||||
/// construct SCCs for region inference but also for error
|
||||
@ -133,7 +133,7 @@ impl<D: ConstraintGraphDirecton> ConstraintGraph<D> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Edges<'s, 'tcx, D: ConstraintGraphDirecton> {
|
||||
pub(crate) struct Edges<'s, 'tcx, D: ConstraintGraphDirection> {
|
||||
graph: &'s ConstraintGraph<D>,
|
||||
constraints: &'s OutlivesConstraintSet<'tcx>,
|
||||
pointer: Option<OutlivesConstraintIndex>,
|
||||
@ -141,7 +141,7 @@ pub(crate) struct Edges<'s, 'tcx, D: ConstraintGraphDirecton> {
|
||||
static_region: RegionVid,
|
||||
}
|
||||
|
||||
impl<'s, 'tcx, D: ConstraintGraphDirecton> Iterator for Edges<'s, 'tcx, D> {
|
||||
impl<'s, 'tcx, D: ConstraintGraphDirection> Iterator for Edges<'s, 'tcx, D> {
|
||||
type Item = OutlivesConstraint<'tcx>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
@ -174,13 +174,13 @@ impl<'s, 'tcx, D: ConstraintGraphDirecton> Iterator for Edges<'s, 'tcx, D> {
|
||||
/// This struct brings together a constraint set and a (normal, not
|
||||
/// reverse) constraint graph. It implements the graph traits and is
|
||||
/// usd for doing the SCC computation.
|
||||
pub(crate) struct RegionGraph<'s, 'tcx, D: ConstraintGraphDirecton> {
|
||||
pub(crate) struct RegionGraph<'s, 'tcx, D: ConstraintGraphDirection> {
|
||||
set: &'s OutlivesConstraintSet<'tcx>,
|
||||
constraint_graph: &'s ConstraintGraph<D>,
|
||||
static_region: RegionVid,
|
||||
}
|
||||
|
||||
impl<'s, 'tcx, D: ConstraintGraphDirecton> RegionGraph<'s, 'tcx, D> {
|
||||
impl<'s, 'tcx, D: ConstraintGraphDirection> RegionGraph<'s, 'tcx, D> {
|
||||
/// Creates a "dependency graph" where each region constraint `R1:
|
||||
/// R2` is treated as an edge `R1 -> R2`. We use this graph to
|
||||
/// construct SCCs for region inference but also for error
|
||||
@ -202,11 +202,11 @@ impl<'s, 'tcx, D: ConstraintGraphDirecton> RegionGraph<'s, 'tcx, D> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Successors<'s, 'tcx, D: ConstraintGraphDirecton> {
|
||||
pub(crate) struct Successors<'s, 'tcx, D: ConstraintGraphDirection> {
|
||||
edges: Edges<'s, 'tcx, D>,
|
||||
}
|
||||
|
||||
impl<'s, 'tcx, D: ConstraintGraphDirecton> Iterator for Successors<'s, 'tcx, D> {
|
||||
impl<'s, 'tcx, D: ConstraintGraphDirection> Iterator for Successors<'s, 'tcx, D> {
|
||||
type Item = RegionVid;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
@ -214,23 +214,25 @@ impl<'s, 'tcx, D: ConstraintGraphDirecton> Iterator for Successors<'s, 'tcx, D>
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::DirectedGraph for RegionGraph<'s, 'tcx, D> {
|
||||
impl<'s, 'tcx, D: ConstraintGraphDirection> graph::DirectedGraph for RegionGraph<'s, 'tcx, D> {
|
||||
type Node = RegionVid;
|
||||
}
|
||||
|
||||
impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::WithNumNodes for RegionGraph<'s, 'tcx, D> {
|
||||
impl<'s, 'tcx, D: ConstraintGraphDirection> graph::WithNumNodes for RegionGraph<'s, 'tcx, D> {
|
||||
fn num_nodes(&self) -> usize {
|
||||
self.constraint_graph.first_constraints.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::WithSuccessors for RegionGraph<'s, 'tcx, D> {
|
||||
impl<'s, 'tcx, D: ConstraintGraphDirection> graph::WithSuccessors for RegionGraph<'s, 'tcx, D> {
|
||||
fn successors(&self, node: Self::Node) -> <Self as graph::GraphSuccessors<'_>>::Iter {
|
||||
self.outgoing_regions(node)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::GraphSuccessors<'_> for RegionGraph<'s, 'tcx, D> {
|
||||
impl<'s, 'tcx, D: ConstraintGraphDirection> graph::GraphSuccessors<'_>
|
||||
for RegionGraph<'s, 'tcx, D>
|
||||
{
|
||||
type Item = RegionVid;
|
||||
type Iter = Successors<'s, 'tcx, D>;
|
||||
}
|
||||
|
@ -11,9 +11,7 @@ use rustc_mir_dataflow::{self, fmt::DebugWithContext, CallReturnPlaces, GenKill}
|
||||
use rustc_mir_dataflow::{Analysis, Direction, Results};
|
||||
use std::fmt;
|
||||
|
||||
use crate::{
|
||||
places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, ToRegionVid,
|
||||
};
|
||||
use crate::{places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext};
|
||||
|
||||
/// A tuple with named fields that can hold either the results or the transient state of the
|
||||
/// dataflow analyses used by the borrow checker.
|
||||
@ -242,7 +240,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
|
||||
) -> Self {
|
||||
let mut prec = OutOfScopePrecomputer::new(body, nonlexical_regioncx);
|
||||
for (borrow_index, borrow_data) in borrow_set.iter_enumerated() {
|
||||
let borrow_region = borrow_data.region.to_region_vid();
|
||||
let borrow_region = borrow_data.region;
|
||||
let location = borrow_data.reserve_location;
|
||||
|
||||
prec.precompute_borrows_out_of_scope(borrow_index, borrow_region, location);
|
||||
|
@ -6,7 +6,6 @@ use std::rc::Rc;
|
||||
|
||||
use crate::{
|
||||
def_use::{self, DefUse},
|
||||
nll::ToRegionVid,
|
||||
region_infer::{Cause, RegionInferenceContext},
|
||||
};
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
@ -117,7 +116,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for DefUseVisitor<'cx, 'tcx> {
|
||||
|
||||
let mut found_it = false;
|
||||
self.tcx.for_each_free_region(&local_ty, |r| {
|
||||
if r.to_region_vid() == self.region_vid {
|
||||
if r.as_var() == self.region_vid {
|
||||
found_it = true;
|
||||
}
|
||||
});
|
||||
|
@ -10,7 +10,7 @@ use rustc_middle::ty::{self, RegionVid, Ty};
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
use crate::{nll::ToRegionVid, universal_regions::DefiningTy, MirBorrowckCtxt};
|
||||
use crate::{universal_regions::DefiningTy, MirBorrowckCtxt};
|
||||
|
||||
/// A name for a particular region used in emitting diagnostics. This name could be a generated
|
||||
/// name like `'1`, a name used by the user like `'a`, or a name like `'static`.
|
||||
@ -497,7 +497,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
// &
|
||||
// - let's call the lifetime of this reference `'1`
|
||||
(ty::Ref(region, referent_ty, _), hir::TyKind::Ref(_lifetime, referent_hir_ty)) => {
|
||||
if region.to_region_vid() == needle_fr {
|
||||
if region.as_var() == needle_fr {
|
||||
// Just grab the first character, the `&`.
|
||||
let source_map = self.infcx.tcx.sess.source_map();
|
||||
let ampersand_span = source_map.start_point(hir_ty.span);
|
||||
@ -598,7 +598,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
for (kind, hir_arg) in iter::zip(substs, args.args) {
|
||||
match (kind.unpack(), hir_arg) {
|
||||
(GenericArgKind::Lifetime(r), hir::GenericArg::Lifetime(lt)) => {
|
||||
if r.to_region_vid() == needle_fr {
|
||||
if r.as_var() == needle_fr {
|
||||
return Some(lt);
|
||||
}
|
||||
}
|
||||
@ -666,7 +666,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
|
||||
let return_ty = self.regioncx.universal_regions().unnormalized_output_ty;
|
||||
debug!("give_name_if_anonymous_region_appears_in_output: return_ty = {:?}", return_ty);
|
||||
if !tcx.any_free_region_meets(&return_ty, |r| r.to_region_vid() == fr) {
|
||||
if !tcx.any_free_region_meets(&return_ty, |r| r.as_var() == fr) {
|
||||
return None;
|
||||
}
|
||||
|
||||
@ -803,7 +803,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
|
||||
let tcx = self.infcx.tcx;
|
||||
|
||||
if !tcx.any_free_region_meets(&yield_ty, |r| r.to_region_vid() == fr) {
|
||||
if !tcx.any_free_region_meets(&yield_ty, |r| r.as_var() == fr) {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
||||
use crate::region_infer::RegionInferenceContext;
|
||||
use crate::Upvar;
|
||||
use crate::{nll::ToRegionVid, region_infer::RegionInferenceContext};
|
||||
use rustc_index::vec::{Idx, IndexSlice};
|
||||
use rustc_middle::mir::{Body, Local};
|
||||
use rustc_middle::ty::{RegionVid, TyCtxt};
|
||||
@ -46,7 +46,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
self.universal_regions().defining_ty.upvar_tys().position(|upvar_ty| {
|
||||
debug!("get_upvar_index_for_region: upvar_ty={upvar_ty:?}");
|
||||
tcx.any_free_region_meets(&upvar_ty, |r| {
|
||||
let r = r.to_region_vid();
|
||||
let r = r.as_var();
|
||||
debug!("get_upvar_index_for_region: r={r:?} fr={fr:?}");
|
||||
r == fr
|
||||
})
|
||||
@ -96,7 +96,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
self.universal_regions().unnormalized_input_tys.iter().skip(implicit_inputs).position(
|
||||
|arg_ty| {
|
||||
debug!("get_argument_index_for_region: arg_ty = {arg_ty:?}");
|
||||
tcx.any_free_region_meets(arg_ty, |r| r.to_region_vid() == fr)
|
||||
tcx.any_free_region_meets(arg_ty, |r| r.as_var() == fr)
|
||||
},
|
||||
)?;
|
||||
|
||||
|
@ -94,7 +94,7 @@ pub mod consumers;
|
||||
|
||||
use borrow_set::{BorrowData, BorrowSet};
|
||||
use dataflow::{BorrowIndex, BorrowckFlowState as Flows, BorrowckResults, Borrows};
|
||||
use nll::{PoloniusOutput, ToRegionVid};
|
||||
use nll::PoloniusOutput;
|
||||
use place_ext::PlaceExt;
|
||||
use places_conflict::{places_conflict, PlaceConflictBias};
|
||||
use region_infer::RegionInferenceContext;
|
||||
@ -507,9 +507,7 @@ impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> {
|
||||
F: Fn() -> RegionCtxt,
|
||||
{
|
||||
let next_region = self.infcx.next_region_var(origin);
|
||||
let vid = next_region
|
||||
.as_var()
|
||||
.unwrap_or_else(|| bug!("expected RegionKind::RegionVar on {:?}", next_region));
|
||||
let vid = next_region.as_var();
|
||||
|
||||
if cfg!(debug_assertions) && !self.inside_canonicalization_ctxt() {
|
||||
debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
|
||||
@ -531,9 +529,7 @@ impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> {
|
||||
F: Fn() -> RegionCtxt,
|
||||
{
|
||||
let next_region = self.infcx.next_nll_region_var(origin.clone());
|
||||
let vid = next_region
|
||||
.as_var()
|
||||
.unwrap_or_else(|| bug!("expected RegionKind::RegionVar on {:?}", next_region));
|
||||
let vid = next_region.as_var();
|
||||
|
||||
if cfg!(debug_assertions) && !self.inside_canonicalization_ctxt() {
|
||||
debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
|
||||
|
@ -10,7 +10,7 @@ use rustc_middle::mir::{
|
||||
BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location,
|
||||
Promoted,
|
||||
};
|
||||
use rustc_middle::ty::{self, OpaqueHiddenType, Region, RegionVid, TyCtxt};
|
||||
use rustc_middle::ty::{self, OpaqueHiddenType, TyCtxt};
|
||||
use rustc_span::symbol::sym;
|
||||
use std::env;
|
||||
use std::io;
|
||||
@ -444,27 +444,6 @@ fn for_each_region_constraint<'tcx>(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Right now, we piggy back on the `ReVar` to store our NLL inference
|
||||
/// regions. These are indexed with `RegionVid`. This method will
|
||||
/// assert that the region is a `ReVar` and extract its internal index.
|
||||
/// This is reasonable because in our MIR we replace all universal regions
|
||||
/// with inference variables.
|
||||
pub trait ToRegionVid {
|
||||
fn to_region_vid(self) -> RegionVid;
|
||||
}
|
||||
|
||||
impl<'tcx> ToRegionVid for Region<'tcx> {
|
||||
fn to_region_vid(self) -> RegionVid {
|
||||
if let ty::ReVar(vid) = *self { vid } else { bug!("region is not an ReVar: {:?}", self) }
|
||||
}
|
||||
}
|
||||
|
||||
impl ToRegionVid for RegionVid {
|
||||
fn to_region_vid(self) -> RegionVid {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait ConstraintDescription {
|
||||
fn description(&self) -> &'static str;
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ use crate::{
|
||||
},
|
||||
diagnostics::{RegionErrorKind, RegionErrors, UniverseInfo},
|
||||
member_constraints::{MemberConstraintSet, NllMemberConstraintIndex},
|
||||
nll::{PoloniusOutput, ToRegionVid},
|
||||
nll::PoloniusOutput,
|
||||
region_infer::reverse_sccs::ReverseSccGraph,
|
||||
region_infer::values::{
|
||||
LivenessValues, PlaceholderIndices, RegionElement, RegionValueElements, RegionValues,
|
||||
@ -593,14 +593,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
/// Returns `true` if the region `r` contains the point `p`.
|
||||
///
|
||||
/// Panics if called before `solve()` executes,
|
||||
pub(crate) fn region_contains(&self, r: impl ToRegionVid, p: impl ToElementIndex) -> bool {
|
||||
let scc = self.constraint_sccs.scc(r.to_region_vid());
|
||||
pub(crate) fn region_contains(&self, r: RegionVid, p: impl ToElementIndex) -> bool {
|
||||
let scc = self.constraint_sccs.scc(r);
|
||||
self.scc_values.contains(scc, p)
|
||||
}
|
||||
|
||||
/// Returns access to the value of `r` for debugging purposes.
|
||||
pub(crate) fn region_value_str(&self, r: RegionVid) -> String {
|
||||
let scc = self.constraint_sccs.scc(r.to_region_vid());
|
||||
let scc = self.constraint_sccs.scc(r);
|
||||
self.scc_values.region_value_str(scc)
|
||||
}
|
||||
|
||||
@ -608,24 +608,21 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
&'a self,
|
||||
r: RegionVid,
|
||||
) -> impl Iterator<Item = ty::PlaceholderRegion> + 'a {
|
||||
let scc = self.constraint_sccs.scc(r.to_region_vid());
|
||||
let scc = self.constraint_sccs.scc(r);
|
||||
self.scc_values.placeholders_contained_in(scc)
|
||||
}
|
||||
|
||||
/// Returns access to the value of `r` for debugging purposes.
|
||||
pub(crate) fn region_universe(&self, r: RegionVid) -> ty::UniverseIndex {
|
||||
let scc = self.constraint_sccs.scc(r.to_region_vid());
|
||||
let scc = self.constraint_sccs.scc(r);
|
||||
self.scc_universes[scc]
|
||||
}
|
||||
|
||||
/// Once region solving has completed, this function will return
|
||||
/// the member constraints that were applied to the value of a given
|
||||
/// region `r`. See `AppliedMemberConstraint`.
|
||||
pub(crate) fn applied_member_constraints(
|
||||
&self,
|
||||
r: impl ToRegionVid,
|
||||
) -> &[AppliedMemberConstraint] {
|
||||
let scc = self.constraint_sccs.scc(r.to_region_vid());
|
||||
pub(crate) fn applied_member_constraints(&self, r: RegionVid) -> &[AppliedMemberConstraint] {
|
||||
let scc = self.constraint_sccs.scc(r);
|
||||
binary_search_util::binary_search_slice(
|
||||
&self.member_constraints_applied,
|
||||
|applied| applied.member_region_scc,
|
||||
@ -1133,7 +1130,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
let r_vid = self.to_region_vid(r);
|
||||
let r_scc = self.constraint_sccs.scc(r_vid);
|
||||
|
||||
// The challenge if this. We have some region variable `r`
|
||||
// The challenge is this. We have some region variable `r`
|
||||
// whose value is a set of CFG points and universal
|
||||
// regions. We want to find if that set is *equivalent* to
|
||||
// any of the named regions found in the closure.
|
||||
@ -2234,7 +2231,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
r: RegionVid,
|
||||
body: &Body<'_>,
|
||||
) -> Option<Location> {
|
||||
let scc = self.constraint_sccs.scc(r.to_region_vid());
|
||||
let scc = self.constraint_sccs.scc(r);
|
||||
let locations = self.scc_values.locations_outlived_by(scc);
|
||||
for location in locations {
|
||||
let bb = &body[location.block];
|
||||
|
@ -20,31 +20,13 @@ pub fn renumber_mir<'tcx>(
|
||||
) {
|
||||
debug!(?body.arg_count);
|
||||
|
||||
let mut visitor = NllVisitor { infcx };
|
||||
let mut renumberer = RegionRenumberer { infcx };
|
||||
|
||||
for body in promoted.iter_mut() {
|
||||
visitor.visit_body(body);
|
||||
renumberer.visit_body(body);
|
||||
}
|
||||
|
||||
visitor.visit_body(body);
|
||||
}
|
||||
|
||||
/// Replaces all regions appearing in `value` with fresh inference
|
||||
/// variables.
|
||||
#[instrument(skip(infcx, get_ctxt_fn), level = "debug")]
|
||||
pub(crate) fn renumber_regions<'tcx, T, F>(
|
||||
infcx: &BorrowckInferCtxt<'_, 'tcx>,
|
||||
value: T,
|
||||
get_ctxt_fn: F,
|
||||
) -> T
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
F: Fn() -> RegionCtxt,
|
||||
{
|
||||
infcx.tcx.fold_regions(value, |_region, _depth| {
|
||||
let origin = NllRegionVariableOrigin::Existential { from_forall: false };
|
||||
infcx.next_nll_region_var(origin, || get_ctxt_fn())
|
||||
})
|
||||
renumberer.visit_body(body);
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
@ -69,12 +51,10 @@ impl RegionCtxt {
|
||||
/// Used to determine the representative of a component in the strongly connected
|
||||
/// constraint graph
|
||||
pub(crate) fn preference_value(self) -> usize {
|
||||
let _anon = Symbol::intern("anon");
|
||||
|
||||
match self {
|
||||
RegionCtxt::Unknown => 1,
|
||||
RegionCtxt::Existential(None) => 2,
|
||||
RegionCtxt::Existential(Some(_anon)) | RegionCtxt::Free(_anon) => 2,
|
||||
RegionCtxt::Existential(Some(_)) | RegionCtxt::Free(_) => 2,
|
||||
RegionCtxt::Location(_) => 3,
|
||||
RegionCtxt::TyContext(_) => 4,
|
||||
_ => 5,
|
||||
@ -82,21 +62,26 @@ impl RegionCtxt {
|
||||
}
|
||||
}
|
||||
|
||||
struct NllVisitor<'a, 'tcx> {
|
||||
struct RegionRenumberer<'a, 'tcx> {
|
||||
infcx: &'a BorrowckInferCtxt<'a, 'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> NllVisitor<'a, 'tcx> {
|
||||
impl<'a, 'tcx> RegionRenumberer<'a, 'tcx> {
|
||||
/// Replaces all regions appearing in `value` with fresh inference
|
||||
/// variables.
|
||||
fn renumber_regions<T, F>(&mut self, value: T, region_ctxt_fn: F) -> T
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
F: Fn() -> RegionCtxt,
|
||||
{
|
||||
renumber_regions(self.infcx, value, region_ctxt_fn)
|
||||
let origin = NllRegionVariableOrigin::Existential { from_forall: false };
|
||||
self.infcx.tcx.fold_regions(value, |_region, _depth| {
|
||||
self.infcx.next_nll_region_var(origin, || region_ctxt_fn())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> {
|
||||
impl<'a, 'tcx> MutVisitor<'tcx> for RegionRenumberer<'a, 'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
@ -124,9 +109,9 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> {
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn visit_constant(&mut self, constant: &mut Constant<'tcx>, _location: Location) {
|
||||
fn visit_constant(&mut self, constant: &mut Constant<'tcx>, location: Location) {
|
||||
let literal = constant.literal;
|
||||
constant.literal = self.renumber_regions(literal, || RegionCtxt::Location(_location));
|
||||
constant.literal = self.renumber_regions(literal, || RegionCtxt::Location(location));
|
||||
debug!("constant: {:#?}", constant);
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,6 @@ use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
use crate::{
|
||||
constraints::OutlivesConstraint,
|
||||
nll::ToRegionVid,
|
||||
region_infer::TypeTest,
|
||||
type_check::{Locations, MirTypeckRegionConstraints},
|
||||
universal_regions::UniversalRegions,
|
||||
@ -198,7 +197,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||
|
||||
fn to_region_vid(&mut self, r: ty::Region<'tcx>) -> ty::RegionVid {
|
||||
if let ty::RePlaceholder(placeholder) = *r {
|
||||
self.constraints.placeholder_region(self.infcx, placeholder).to_region_vid()
|
||||
self.constraints.placeholder_region(self.infcx, placeholder).as_var()
|
||||
} else {
|
||||
self.universal_regions.to_region_vid(r)
|
||||
}
|
||||
|
@ -11,7 +11,6 @@ use crate::{
|
||||
constraints::OutlivesConstraintSet,
|
||||
facts::{AllFacts, AllFactsExt},
|
||||
location::LocationTable,
|
||||
nll::ToRegionVid,
|
||||
region_infer::values::RegionValueElements,
|
||||
universal_regions::UniversalRegions,
|
||||
};
|
||||
@ -80,9 +79,7 @@ fn compute_relevant_live_locals<'tcx>(
|
||||
) -> (Vec<Local>, Vec<Local>) {
|
||||
let (boring_locals, relevant_live_locals): (Vec<_>, Vec<_>) =
|
||||
body.local_decls.iter_enumerated().partition_map(|(local, local_decl)| {
|
||||
if tcx.all_free_regions_meet(&local_decl.ty, |r| {
|
||||
free_regions.contains(&r.to_region_vid())
|
||||
}) {
|
||||
if tcx.all_free_regions_meet(&local_decl.ty, |r| free_regions.contains(&r.as_var())) {
|
||||
Either::Left(local)
|
||||
} else {
|
||||
Either::Right(local)
|
||||
|
@ -35,6 +35,7 @@ use rustc_middle::ty::{
|
||||
OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, UserType, UserTypeAnnotationIndex,
|
||||
};
|
||||
use rustc_span::def_id::CRATE_DEF_ID;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
|
||||
use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints;
|
||||
@ -55,7 +56,6 @@ use crate::{
|
||||
facts::AllFacts,
|
||||
location::LocationTable,
|
||||
member_constraints::MemberConstraintSet,
|
||||
nll::ToRegionVid,
|
||||
path_utils,
|
||||
region_infer::values::{
|
||||
LivenessValues, PlaceholderIndex, PlaceholderIndices, RegionValueElements,
|
||||
@ -1338,18 +1338,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
};
|
||||
let (sig, map) = tcx.replace_late_bound_regions(sig, |br| {
|
||||
use crate::renumber::{BoundRegionInfo, RegionCtxt};
|
||||
use rustc_span::Symbol;
|
||||
|
||||
let region_ctxt_fn = || {
|
||||
let reg_info = match br.kind {
|
||||
ty::BoundRegionKind::BrAnon(Some(span)) => BoundRegionInfo::Span(span),
|
||||
ty::BoundRegionKind::BrAnon(..) => {
|
||||
BoundRegionInfo::Name(Symbol::intern("anon"))
|
||||
}
|
||||
ty::BoundRegionKind::BrAnon(..) => BoundRegionInfo::Name(sym::anon),
|
||||
ty::BoundRegionKind::BrNamed(_, name) => BoundRegionInfo::Name(name),
|
||||
ty::BoundRegionKind::BrEnv => {
|
||||
BoundRegionInfo::Name(Symbol::intern("env"))
|
||||
}
|
||||
ty::BoundRegionKind::BrEnv => BoundRegionInfo::Name(sym::env),
|
||||
};
|
||||
|
||||
RegionCtxt::LateBound(reg_info)
|
||||
@ -2423,7 +2418,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
if let Some(all_facts) = all_facts {
|
||||
let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation");
|
||||
if let Some(borrow_index) = borrow_set.get_index_of(&location) {
|
||||
let region_vid = borrow_region.to_region_vid();
|
||||
let region_vid = borrow_region.as_var();
|
||||
all_facts.loan_issued_at.push((
|
||||
region_vid,
|
||||
borrow_index,
|
||||
@ -2469,8 +2464,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
match base_ty.kind() {
|
||||
ty::Ref(ref_region, _, mutbl) => {
|
||||
constraints.outlives_constraints.push(OutlivesConstraint {
|
||||
sup: ref_region.to_region_vid(),
|
||||
sub: borrow_region.to_region_vid(),
|
||||
sup: ref_region.as_var(),
|
||||
sub: borrow_region.as_var(),
|
||||
locations: location.to_locations(),
|
||||
span: location.to_locations().span(body),
|
||||
category,
|
||||
@ -2600,7 +2595,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
self.implicit_region_bound,
|
||||
self.param_env,
|
||||
location.to_locations(),
|
||||
DUMMY_SP, // irrelevant; will be overrided.
|
||||
DUMMY_SP, // irrelevant; will be overridden.
|
||||
ConstraintCategory::Boring, // same as above.
|
||||
&mut self.borrowck_context.constraints,
|
||||
)
|
||||
|
@ -4,6 +4,7 @@ use rustc_infer::traits::PredicateObligations;
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::ty::relate::TypeRelation;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{Span, Symbol};
|
||||
use rustc_trait_selection::traits::query::Fallible;
|
||||
|
||||
@ -125,18 +126,14 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
|
||||
|
||||
let reg_info = match placeholder.bound.kind {
|
||||
ty::BoundRegionKind::BrAnon(Some(span)) => BoundRegionInfo::Span(span),
|
||||
ty::BoundRegionKind::BrAnon(..) => BoundRegionInfo::Name(Symbol::intern("anon")),
|
||||
ty::BoundRegionKind::BrAnon(..) => BoundRegionInfo::Name(sym::anon),
|
||||
ty::BoundRegionKind::BrNamed(_, name) => BoundRegionInfo::Name(name),
|
||||
ty::BoundRegionKind::BrEnv => BoundRegionInfo::Name(Symbol::intern("env")),
|
||||
ty::BoundRegionKind::BrEnv => BoundRegionInfo::Name(sym::env),
|
||||
};
|
||||
|
||||
let reg_var =
|
||||
reg.as_var().unwrap_or_else(|| bug!("expected region {:?} to be of kind ReVar", reg));
|
||||
|
||||
if cfg!(debug_assertions) && !self.type_checker.infcx.inside_canonicalization_ctxt() {
|
||||
let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut();
|
||||
debug!(?reg_var);
|
||||
var_to_origin.insert(reg_var, RegionCtxt::Placeholder(reg_info));
|
||||
var_to_origin.insert(reg.as_var(), RegionCtxt::Placeholder(reg_info));
|
||||
}
|
||||
|
||||
reg
|
||||
@ -149,12 +146,9 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
|
||||
universe,
|
||||
);
|
||||
|
||||
let reg_var =
|
||||
reg.as_var().unwrap_or_else(|| bug!("expected region {:?} to be of kind ReVar", reg));
|
||||
|
||||
if cfg!(debug_assertions) && !self.type_checker.infcx.inside_canonicalization_ctxt() {
|
||||
let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut();
|
||||
var_to_origin.insert(reg_var, RegionCtxt::Existential(None));
|
||||
var_to_origin.insert(reg.as_var(), RegionCtxt::Existential(None));
|
||||
}
|
||||
|
||||
reg
|
||||
|
@ -24,10 +24,10 @@ use rustc_infer::infer::NllRegionVariableOrigin;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::{self, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{InternalSubsts, SubstsRef};
|
||||
use rustc_span::symbol::{kw, sym};
|
||||
use rustc_span::Symbol;
|
||||
use std::iter;
|
||||
|
||||
use crate::nll::ToRegionVid;
|
||||
use crate::renumber::{BoundRegionInfo, RegionCtxt};
|
||||
use crate::BorrowckInferCtxt;
|
||||
|
||||
@ -404,10 +404,8 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
assert_eq!(FIRST_GLOBAL_INDEX, self.infcx.num_region_vars());
|
||||
|
||||
// Create the "global" region that is always free in all contexts: 'static.
|
||||
let fr_static = self
|
||||
.infcx
|
||||
.next_nll_region_var(FR, || RegionCtxt::Free(Symbol::intern("static")))
|
||||
.to_region_vid();
|
||||
let fr_static =
|
||||
self.infcx.next_nll_region_var(FR, || RegionCtxt::Free(kw::Static)).as_var();
|
||||
|
||||
// We've now added all the global regions. The next ones we
|
||||
// add will be external.
|
||||
@ -440,18 +438,14 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
debug!(?r);
|
||||
if !indices.indices.contains_key(&r) {
|
||||
let region_vid = {
|
||||
let name = match r.get_name() {
|
||||
Some(name) => name,
|
||||
_ => Symbol::intern("anon"),
|
||||
};
|
||||
|
||||
let name = r.get_name_or_anon();
|
||||
self.infcx.next_nll_region_var(FR, || {
|
||||
RegionCtxt::LateBound(BoundRegionInfo::Name(name))
|
||||
})
|
||||
};
|
||||
|
||||
debug!(?region_vid);
|
||||
indices.insert_late_bound_region(r, region_vid.to_region_vid());
|
||||
indices.insert_late_bound_region(r, region_vid.as_var());
|
||||
}
|
||||
},
|
||||
);
|
||||
@ -478,18 +472,14 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
debug!(?r);
|
||||
if !indices.indices.contains_key(&r) {
|
||||
let region_vid = {
|
||||
let name = match r.get_name() {
|
||||
Some(name) => name,
|
||||
_ => Symbol::intern("anon"),
|
||||
};
|
||||
|
||||
let name = r.get_name_or_anon();
|
||||
self.infcx.next_nll_region_var(FR, || {
|
||||
RegionCtxt::LateBound(BoundRegionInfo::Name(name))
|
||||
})
|
||||
};
|
||||
|
||||
debug!(?region_vid);
|
||||
indices.insert_late_bound_region(r, region_vid.to_region_vid());
|
||||
indices.insert_late_bound_region(r, region_vid.as_var());
|
||||
}
|
||||
});
|
||||
|
||||
@ -508,7 +498,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
let reg_vid = self
|
||||
.infcx
|
||||
.next_nll_region_var(FR, || RegionCtxt::Free(Symbol::intern("c-variadic")))
|
||||
.to_region_vid();
|
||||
.as_var();
|
||||
|
||||
let region = self.infcx.tcx.mk_re_var(reg_vid);
|
||||
let va_list_ty =
|
||||
@ -523,7 +513,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
let fr_fn_body = self
|
||||
.infcx
|
||||
.next_nll_region_var(FR, || RegionCtxt::Free(Symbol::intern("fn_body")))
|
||||
.to_region_vid();
|
||||
.as_var();
|
||||
|
||||
let num_universals = self.infcx.num_region_vars();
|
||||
|
||||
@ -644,7 +634,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
|
||||
let global_mapping = iter::once((tcx.lifetimes.re_static, fr_static));
|
||||
let subst_mapping =
|
||||
iter::zip(identity_substs.regions(), fr_substs.regions().map(|r| r.to_region_vid()));
|
||||
iter::zip(identity_substs.regions(), fr_substs.regions().map(|r| r.as_var()));
|
||||
|
||||
UniversalRegionIndices { indices: global_mapping.chain(subst_mapping).collect(), fr_static }
|
||||
}
|
||||
@ -768,15 +758,10 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> {
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
self.infcx.tcx.fold_regions(value, |region, _depth| {
|
||||
let name = match region.get_name() {
|
||||
Some(name) => name,
|
||||
_ => Symbol::intern("anon"),
|
||||
};
|
||||
let name = region.get_name_or_anon();
|
||||
debug!(?region, ?name);
|
||||
|
||||
let reg_var = self.next_nll_region_var(origin, || RegionCtxt::Free(name));
|
||||
|
||||
reg_var
|
||||
self.next_nll_region_var(origin, || RegionCtxt::Free(name))
|
||||
})
|
||||
}
|
||||
|
||||
@ -797,13 +782,13 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> {
|
||||
let region_vid = {
|
||||
let name = match br.kind.get_name() {
|
||||
Some(name) => name,
|
||||
_ => Symbol::intern("anon"),
|
||||
_ => sym::anon,
|
||||
};
|
||||
|
||||
self.next_nll_region_var(origin, || RegionCtxt::Bound(BoundRegionInfo::Name(name)))
|
||||
};
|
||||
|
||||
indices.insert_late_bound_region(liberated_region, region_vid.to_region_vid());
|
||||
indices.insert_late_bound_region(liberated_region, region_vid.as_var());
|
||||
debug!(?liberated_region, ?region_vid);
|
||||
region_vid
|
||||
});
|
||||
@ -829,18 +814,14 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> {
|
||||
debug!(?r);
|
||||
if !indices.indices.contains_key(&r) {
|
||||
let region_vid = {
|
||||
let name = match r.get_name() {
|
||||
Some(name) => name,
|
||||
_ => Symbol::intern("anon"),
|
||||
};
|
||||
|
||||
let name = r.get_name_or_anon();
|
||||
self.next_nll_region_var(FR, || {
|
||||
RegionCtxt::LateBound(BoundRegionInfo::Name(name))
|
||||
})
|
||||
};
|
||||
|
||||
debug!(?region_vid);
|
||||
indices.insert_late_bound_region(r, region_vid.to_region_vid());
|
||||
indices.insert_late_bound_region(r, region_vid.as_var());
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -855,17 +836,13 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> {
|
||||
debug!(?r);
|
||||
if !indices.indices.contains_key(&r) {
|
||||
let region_vid = {
|
||||
let name = match r.get_name() {
|
||||
Some(name) => name,
|
||||
_ => Symbol::intern("anon"),
|
||||
};
|
||||
|
||||
let name = r.get_name_or_anon();
|
||||
self.next_nll_region_var(FR, || {
|
||||
RegionCtxt::LateBound(BoundRegionInfo::Name(name))
|
||||
})
|
||||
};
|
||||
|
||||
indices.insert_late_bound_region(r, region_vid.to_region_vid());
|
||||
indices.insert_late_bound_region(r, region_vid.as_var());
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -883,7 +860,7 @@ impl<'tcx> UniversalRegionIndices<'tcx> {
|
||||
}
|
||||
|
||||
/// Converts `r` into a local inference variable: `r` can either
|
||||
/// by a `ReVar` (i.e., already a reference to an inference
|
||||
/// be a `ReVar` (i.e., already a reference to an inference
|
||||
/// variable) or it can be `'static` or some early-bound
|
||||
/// region. This is useful when taking the results from
|
||||
/// type-checking and trait-matching, which may sometimes
|
||||
@ -892,7 +869,7 @@ impl<'tcx> UniversalRegionIndices<'tcx> {
|
||||
/// fully initialized.
|
||||
pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
|
||||
if let ty::ReVar(..) = *r {
|
||||
r.to_region_vid()
|
||||
r.as_var()
|
||||
} else if r.is_error() {
|
||||
// We use the `'static` `RegionVid` because `ReError` doesn't actually exist in the
|
||||
// `UniversalRegionIndices`. This is fine because 1) it is a fallback only used if
|
||||
|
@ -3,3 +3,149 @@ builtin_macros_requires_cfg_pattern =
|
||||
.label = cfg-pattern required
|
||||
|
||||
builtin_macros_expected_one_cfg_pattern = expected 1 cfg-pattern
|
||||
|
||||
builtin_macros_alloc_error_must_be_fn = alloc_error_handler must be a function
|
||||
|
||||
builtin_macros_assert_requires_boolean = macro requires a boolean expression as an argument
|
||||
.label = boolean expression required
|
||||
|
||||
builtin_macros_assert_requires_expression = macro requires an expression as an argument
|
||||
.suggestion = try removing semicolon
|
||||
|
||||
builtin_macros_assert_missing_comma = unexpected string literal
|
||||
.suggestion = try adding a comma
|
||||
|
||||
builtin_macros_cfg_accessible_unspecified_path = `cfg_accessible` path is not specified
|
||||
builtin_macros_cfg_accessible_multiple_paths = multiple `cfg_accessible` paths are specified
|
||||
builtin_macros_cfg_accessible_literal_path = `cfg_accessible` path cannot be a literal
|
||||
builtin_macros_cfg_accessible_has_args = `cfg_accessible` path cannot accept arguments
|
||||
|
||||
builtin_macros_cfg_accessible_indeterminate = cannot determine whether the path is accessible or not
|
||||
|
||||
builtin_macros_concat_bytestr = cannot concatenate a byte string literal
|
||||
|
||||
builtin_macros_concat_missing_literal = expected a literal
|
||||
.note = only literals (like `"foo"`, `-42` and `3.14`) can be passed to `concat!()`
|
||||
|
||||
builtin_macros_concat_bytes_missing_literal = expected a byte literal
|
||||
.note = only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()`
|
||||
|
||||
builtin_macros_concat_bytes_invalid = cannot concatenate {$lit_kind} literals
|
||||
.byte_char = try using a byte character
|
||||
.byte_str = try using a byte string
|
||||
.number_array = try wrapping the number in an array
|
||||
|
||||
builtin_macros_concat_bytes_oob = numeric literal is out of bounds
|
||||
|
||||
builtin_macros_concat_bytes_non_u8 = numeric literal is not a `u8`
|
||||
|
||||
builtin_macros_concat_bytes_array = cannot concatenate doubly nested array
|
||||
.note = byte strings are treated as arrays of bytes
|
||||
.help = try flattening the array
|
||||
|
||||
builtin_macros_concat_bytes_bad_repeat = repeat count is not a positive number
|
||||
|
||||
builtin_macros_concat_idents_missing_args = `concat_idents!()` takes 1 or more arguments
|
||||
builtin_macros_concat_idents_missing_comma = `concat_idents!()` expecting comma
|
||||
builtin_macros_concat_idents_ident_args = `concat_idents!()` requires ident args
|
||||
|
||||
builtin_macros_bad_derive_target = `derive` may only be applied to `struct`s, `enum`s and `union`s
|
||||
.label = not applicable here
|
||||
.label2 = not a `struct`, `enum` or `union`
|
||||
|
||||
builtin_macros_unexpected_lit = expected path to a trait, found literal
|
||||
.label = not a trait
|
||||
.str_lit = try using `#[derive({$sym})]`
|
||||
.other = for example, write `#[derive(Debug)]` for `Debug`
|
||||
|
||||
builtin_macros_derive_path_args_list = traits in `#[derive(...)]` don't accept arguments
|
||||
.suggestion = remove the arguments
|
||||
|
||||
builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept values
|
||||
.suggestion = remove the value
|
||||
|
||||
builtin_macros_derive_macro_call = `derive` cannot be used on items with type macros
|
||||
|
||||
builtin_macros_cannot_derive_union = this trait cannot be derived for unions
|
||||
|
||||
builtin_macros_no_default_variant = no default declared
|
||||
.help = make a unit variant default by placing `#[default]` above it
|
||||
.suggestion = make `{$ident}` default
|
||||
|
||||
builtin_macros_multiple_defaults = multiple declared defaults
|
||||
.label = first default
|
||||
.additional = additional default
|
||||
.note = only one variant can be default
|
||||
.suggestion = make `{$ident}` default
|
||||
|
||||
builtin_macros_non_unit_default = the `#[default]` attribute may only be used on unit enum variants
|
||||
.help = consider a manual implementation of `Default`
|
||||
|
||||
builtin_macros_non_exhaustive_default = default variant must be exhaustive
|
||||
.label = declared `#[non_exhaustive]` here
|
||||
.help = consider a manual implementation of `Default`
|
||||
|
||||
builtin_macros_multiple_default_attrs = multiple `#[default]` attributes
|
||||
.note = only one `#[default]` attribute is needed
|
||||
.label = `#[default]` used here
|
||||
.label_again = `#[default]` used again here
|
||||
.help = try removing {$only_one ->
|
||||
[true] this
|
||||
*[false] these
|
||||
}
|
||||
|
||||
builtin_macros_default_arg = `#[default]` attribute does not accept a value
|
||||
.suggestion = try using `#[default]`
|
||||
|
||||
builtin_macros_env_takes_args = `env!()` takes 1 or 2 arguments
|
||||
|
||||
builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time
|
||||
.cargo = Cargo sets build script variables at run time. Use `std::env::var("{$var}")` instead
|
||||
.other = use `std::env::var("{$var}")` to read the variable at run time
|
||||
|
||||
builtin_macros_format_requires_string = requires at least a format string argument
|
||||
|
||||
builtin_macros_format_duplicate_arg = duplicate argument named `{$ident}`
|
||||
.label1 = previously here
|
||||
.label2 = duplicate argument
|
||||
|
||||
builtin_macros_format_positional_after_named = positional arguments cannot follow named arguments
|
||||
.label = positional arguments must be before named arguments
|
||||
.named_args = named argument
|
||||
|
||||
builtin_macros_format_string_invalid = invalid format string: {$desc}
|
||||
.label = {$label1} in format string
|
||||
.note = {$note}
|
||||
.second_label = {$label}
|
||||
|
||||
builtin_macros_sugg = consider using a positional formatting argument instead
|
||||
|
||||
builtin_macros_format_no_arg_named = there is no argument named `{$name}`
|
||||
.note = did you intend to capture a variable `{$name}` from the surrounding scope?
|
||||
.note2 = to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro
|
||||
|
||||
builtin_macros_format_unknown_trait = unknown format trait `{$ty}`
|
||||
.note = the only appropriate formatting traits are:
|
||||
- ``, which uses the `Display` trait
|
||||
- `?`, which uses the `Debug` trait
|
||||
- `e`, which uses the `LowerExp` trait
|
||||
- `E`, which uses the `UpperExp` trait
|
||||
- `o`, which uses the `Octal` trait
|
||||
- `p`, which uses the `Pointer` trait
|
||||
- `b`, which uses the `Binary` trait
|
||||
- `x`, which uses the `LowerHex` trait
|
||||
- `X`, which uses the `UpperHex` trait
|
||||
.suggestion = use the `{$trait_name}` trait
|
||||
|
||||
builtin_macros_format_unused_arg = {$named ->
|
||||
[true] named argument
|
||||
*[false] argument
|
||||
} never used
|
||||
|
||||
builtin_macros_format_unused_args = multiple unused formatting arguments
|
||||
.label = multiple missing formatting specifiers
|
||||
|
||||
builtin_macros_format_pos_mismatch = {$n} positional {$n ->
|
||||
[one] argument
|
||||
*[more] arguments
|
||||
} in format string, but {$desc}
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::errors;
|
||||
use crate::util::check_builtin_macro_attribute;
|
||||
|
||||
use rustc_ast::ptr::P;
|
||||
@ -31,7 +32,7 @@ pub fn expand(
|
||||
{
|
||||
(item, true, ecx.with_def_site_ctxt(fn_kind.sig.span))
|
||||
} else {
|
||||
ecx.sess.parse_sess.span_diagnostic.span_err(item.span(), "alloc_error_handler must be a function");
|
||||
ecx.sess.parse_sess.span_diagnostic.emit_err(errors::AllocErrorMustBeFn {span: item.span() });
|
||||
return vec![orig_item];
|
||||
};
|
||||
|
||||
|
@ -1,12 +1,13 @@
|
||||
mod context;
|
||||
|
||||
use crate::edition_panic::use_panic_2021;
|
||||
use crate::errors;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token;
|
||||
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
|
||||
use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, MacDelimiter, Path, PathSegment, UnOp};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::{Applicability, PResult};
|
||||
use rustc_errors::PResult;
|
||||
use rustc_expand::base::{DummyResult, ExtCtxt, MacEager, MacResult};
|
||||
use rustc_parse::parser::Parser;
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
@ -114,9 +115,7 @@ fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PRes
|
||||
let mut parser = cx.new_parser_from_tts(stream);
|
||||
|
||||
if parser.token == token::Eof {
|
||||
let mut err = cx.struct_span_err(sp, "macro requires a boolean expression as an argument");
|
||||
err.span_label(sp, "boolean expression required");
|
||||
return Err(err);
|
||||
return Err(cx.create_err(errors::AssertRequiresBoolean { span: sp }));
|
||||
}
|
||||
|
||||
let cond_expr = parser.parse_expr()?;
|
||||
@ -129,15 +128,7 @@ fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PRes
|
||||
//
|
||||
// Emit an error about semicolon and suggest removing it.
|
||||
if parser.token == token::Semi {
|
||||
let mut err = cx.struct_span_err(sp, "macro requires an expression as an argument");
|
||||
err.span_suggestion(
|
||||
parser.token.span,
|
||||
"try removing semicolon",
|
||||
"",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
err.emit();
|
||||
|
||||
cx.emit_err(errors::AssertRequiresExpression { span: sp, token: parser.token.span });
|
||||
parser.bump();
|
||||
}
|
||||
|
||||
@ -149,15 +140,8 @@ fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PRes
|
||||
// Emit an error and suggest inserting a comma.
|
||||
let custom_message =
|
||||
if let token::Literal(token::Lit { kind: token::Str, .. }) = parser.token.kind {
|
||||
let mut err = cx.struct_span_err(parser.token.span, "unexpected string literal");
|
||||
let comma_span = parser.prev_token.span.shrink_to_hi();
|
||||
err.span_suggestion_short(
|
||||
comma_span,
|
||||
"try adding a comma",
|
||||
", ",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
err.emit();
|
||||
let comma = parser.prev_token.span.shrink_to_hi();
|
||||
cx.emit_err(errors::AssertMissingComma { span: parser.token.span, comma });
|
||||
|
||||
parse_custom_message(&mut parser)
|
||||
} else if parser.eat(&token::Comma) {
|
||||
|
@ -2,13 +2,13 @@
|
||||
//! a literal `true` or `false` based on whether the given cfg matches the
|
||||
//! current compilation environment.
|
||||
|
||||
use crate::errors;
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::token;
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_attr as attr;
|
||||
use rustc_errors::PResult;
|
||||
use rustc_expand::base::{self, *};
|
||||
use rustc_macros::Diagnostic;
|
||||
use rustc_span::Span;
|
||||
|
||||
pub fn expand_cfg(
|
||||
@ -35,26 +35,11 @@ pub fn expand_cfg(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_requires_cfg_pattern)]
|
||||
struct RequiresCfgPattern {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_expected_one_cfg_pattern)]
|
||||
struct OneCfgPattern {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
}
|
||||
|
||||
fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> {
|
||||
let mut p = cx.new_parser_from_tts(tts);
|
||||
|
||||
if p.token == token::Eof {
|
||||
return Err(cx.create_err(RequiresCfgPattern { span }));
|
||||
return Err(cx.create_err(errors::RequiresCfgPattern { span }));
|
||||
}
|
||||
|
||||
let cfg = p.parse_meta_item()?;
|
||||
@ -62,7 +47,7 @@ fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<
|
||||
let _ = p.eat(&token::Comma);
|
||||
|
||||
if !p.eat(&token::Eof) {
|
||||
return Err(cx.create_err(OneCfgPattern { span }));
|
||||
return Err(cx.create_err(errors::OneCfgPattern { span }));
|
||||
}
|
||||
|
||||
Ok(cfg)
|
||||
|
@ -1,5 +1,6 @@
|
||||
//! Implementation of the `#[cfg_accessible(path)]` attribute macro.
|
||||
|
||||
use crate::errors;
|
||||
use rustc_ast as ast;
|
||||
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier};
|
||||
use rustc_feature::AttributeTemplate;
|
||||
@ -10,15 +11,22 @@ use rustc_span::Span;
|
||||
pub(crate) struct Expander;
|
||||
|
||||
fn validate_input<'a>(ecx: &mut ExtCtxt<'_>, mi: &'a ast::MetaItem) -> Option<&'a ast::Path> {
|
||||
use errors::CfgAccessibleInvalid::*;
|
||||
match mi.meta_item_list() {
|
||||
None => {}
|
||||
Some([]) => ecx.span_err(mi.span, "`cfg_accessible` path is not specified"),
|
||||
Some([_, .., l]) => ecx.span_err(l.span(), "multiple `cfg_accessible` paths are specified"),
|
||||
Some([]) => {
|
||||
ecx.emit_err(UnspecifiedPath(mi.span));
|
||||
}
|
||||
Some([_, .., l]) => {
|
||||
ecx.emit_err(MultiplePaths(l.span()));
|
||||
}
|
||||
Some([nmi]) => match nmi.meta_item() {
|
||||
None => ecx.span_err(nmi.span(), "`cfg_accessible` path cannot be a literal"),
|
||||
None => {
|
||||
ecx.emit_err(LiteralPath(nmi.span()));
|
||||
}
|
||||
Some(mi) => {
|
||||
if !mi.is_word() {
|
||||
ecx.span_err(mi.span, "`cfg_accessible` path cannot accept arguments");
|
||||
ecx.emit_err(HasArguments(mi.span));
|
||||
}
|
||||
return Some(&mi.path);
|
||||
}
|
||||
@ -53,7 +61,7 @@ impl MultiItemModifier for Expander {
|
||||
Ok(true) => ExpandResult::Ready(vec![item]),
|
||||
Ok(false) => ExpandResult::Ready(Vec::new()),
|
||||
Err(Indeterminate) if ecx.force_mode => {
|
||||
ecx.span_err(span, "cannot determine whether the path is accessible or not");
|
||||
ecx.emit_err(errors::CfgAccessibleIndeterminate { span });
|
||||
ExpandResult::Ready(vec![item])
|
||||
}
|
||||
Err(Indeterminate) => ExpandResult::Retry(item),
|
||||
|
@ -13,6 +13,11 @@ pub fn expand_compile_error<'cx>(
|
||||
return DummyResult::any(sp);
|
||||
};
|
||||
|
||||
#[expect(
|
||||
rustc::diagnostic_outside_of_impl,
|
||||
reason = "diagnostic message is specified by user"
|
||||
)]
|
||||
#[expect(rustc::untranslatable_diagnostic, reason = "diagnostic message is specified by user")]
|
||||
cx.span_err(sp, var.as_str());
|
||||
|
||||
DummyResult::any(sp)
|
||||
|
@ -4,6 +4,8 @@ use rustc_expand::base::{self, DummyResult};
|
||||
use rustc_session::errors::report_lit_error;
|
||||
use rustc_span::symbol::Symbol;
|
||||
|
||||
use crate::errors;
|
||||
|
||||
pub fn expand_concat(
|
||||
cx: &mut base::ExtCtxt<'_>,
|
||||
sp: rustc_span::Span,
|
||||
@ -31,7 +33,7 @@ pub fn expand_concat(
|
||||
accumulator.push_str(&b.to_string());
|
||||
}
|
||||
Ok(ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..)) => {
|
||||
cx.span_err(e.span, "cannot concatenate a byte string literal");
|
||||
cx.emit_err(errors::ConcatBytestr { span: e.span });
|
||||
has_errors = true;
|
||||
}
|
||||
Ok(ast::LitKind::Err) => {
|
||||
@ -55,7 +57,7 @@ pub fn expand_concat(
|
||||
}
|
||||
}
|
||||
ast::ExprKind::IncludedBytes(..) => {
|
||||
cx.span_err(e.span, "cannot concatenate a byte string literal")
|
||||
cx.emit_err(errors::ConcatBytestr { span: e.span });
|
||||
}
|
||||
ast::ExprKind::Err => {
|
||||
has_errors = true;
|
||||
@ -67,9 +69,7 @@ pub fn expand_concat(
|
||||
}
|
||||
|
||||
if !missing_literal.is_empty() {
|
||||
let mut err = cx.struct_span_err(missing_literal, "expected a literal");
|
||||
err.note("only literals (like `\"foo\"`, `-42` and `3.14`) can be passed to `concat!()`");
|
||||
err.emit();
|
||||
cx.emit_err(errors::ConcatMissingLiteral { spans: missing_literal });
|
||||
return DummyResult::any(sp);
|
||||
} else if has_errors {
|
||||
return DummyResult::any(sp);
|
||||
|
@ -1,10 +1,11 @@
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::{ptr::P, tokenstream::TokenStream};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_expand::base::{self, DummyResult};
|
||||
use rustc_session::errors::report_lit_error;
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::errors;
|
||||
|
||||
/// Emits errors for literal expressions that are invalid inside and outside of an array.
|
||||
fn invalid_type_err(
|
||||
cx: &mut base::ExtCtxt<'_>,
|
||||
@ -12,62 +13,46 @@ fn invalid_type_err(
|
||||
span: Span,
|
||||
is_nested: bool,
|
||||
) {
|
||||
use errors::{
|
||||
ConcatBytesInvalid, ConcatBytesInvalidSuggestion, ConcatBytesNonU8, ConcatBytesOob,
|
||||
};
|
||||
let snippet = cx.sess.source_map().span_to_snippet(span).ok();
|
||||
match ast::LitKind::from_token_lit(token_lit) {
|
||||
Ok(ast::LitKind::Char(_)) => {
|
||||
let mut err = cx.struct_span_err(span, "cannot concatenate character literals");
|
||||
if let Ok(snippet) = cx.sess.source_map().span_to_snippet(span) {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"try using a byte character",
|
||||
format!("b{}", snippet),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
let sugg =
|
||||
snippet.map(|snippet| ConcatBytesInvalidSuggestion::CharLit { span, snippet });
|
||||
cx.sess.emit_err(ConcatBytesInvalid { span, lit_kind: "character", sugg });
|
||||
}
|
||||
Ok(ast::LitKind::Str(_, _)) => {
|
||||
let mut err = cx.struct_span_err(span, "cannot concatenate string literals");
|
||||
// suggestion would be invalid if we are nested
|
||||
if !is_nested {
|
||||
if let Ok(snippet) = cx.sess.source_map().span_to_snippet(span) {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"try using a byte string",
|
||||
format!("b{}", snippet),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
let sugg = if !is_nested {
|
||||
snippet.map(|snippet| ConcatBytesInvalidSuggestion::StrLit { span, snippet })
|
||||
} else {
|
||||
None
|
||||
};
|
||||
cx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg });
|
||||
}
|
||||
Ok(ast::LitKind::Float(_, _)) => {
|
||||
cx.span_err(span, "cannot concatenate float literals");
|
||||
cx.emit_err(ConcatBytesInvalid { span, lit_kind: "float", sugg: None });
|
||||
}
|
||||
Ok(ast::LitKind::Bool(_)) => {
|
||||
cx.span_err(span, "cannot concatenate boolean literals");
|
||||
cx.emit_err(ConcatBytesInvalid { span, lit_kind: "boolean", sugg: None });
|
||||
}
|
||||
Ok(ast::LitKind::Err) => {}
|
||||
Ok(ast::LitKind::Int(_, _)) if !is_nested => {
|
||||
let mut err = cx.struct_span_err(span, "cannot concatenate numeric literals");
|
||||
if let Ok(snippet) = cx.sess.source_map().span_to_snippet(span) {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"try wrapping the number in an array",
|
||||
format!("[{}]", snippet),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
err.emit();
|
||||
let sugg =
|
||||
snippet.map(|snippet| ConcatBytesInvalidSuggestion::IntLit { span: span, snippet });
|
||||
cx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg });
|
||||
}
|
||||
Ok(ast::LitKind::Int(
|
||||
val,
|
||||
ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8),
|
||||
)) => {
|
||||
assert!(val > u8::MAX.into()); // must be an error
|
||||
cx.span_err(span, "numeric literal is out of bounds");
|
||||
cx.emit_err(ConcatBytesOob { span });
|
||||
}
|
||||
Ok(ast::LitKind::Int(_, _)) => {
|
||||
cx.span_err(span, "numeric literal is not a `u8`");
|
||||
cx.emit_err(ConcatBytesNonU8 { span });
|
||||
}
|
||||
Ok(ast::LitKind::ByteStr(..) | ast::LitKind::Byte(_)) => unreachable!(),
|
||||
Err(err) => {
|
||||
@ -85,7 +70,7 @@ fn handle_array_element(
|
||||
match expr.kind {
|
||||
ast::ExprKind::Array(_) | ast::ExprKind::Repeat(_, _) => {
|
||||
if !*has_errors {
|
||||
cx.span_err(expr.span, "cannot concatenate doubly nested array");
|
||||
cx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false });
|
||||
}
|
||||
*has_errors = true;
|
||||
None
|
||||
@ -99,10 +84,7 @@ fn handle_array_element(
|
||||
Ok(ast::LitKind::Byte(val)) => Some(val),
|
||||
Ok(ast::LitKind::ByteStr(..)) => {
|
||||
if !*has_errors {
|
||||
cx.struct_span_err(expr.span, "cannot concatenate doubly nested array")
|
||||
.note("byte strings are treated as arrays of bytes")
|
||||
.help("try flattening the array")
|
||||
.emit();
|
||||
cx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: true });
|
||||
}
|
||||
*has_errors = true;
|
||||
None
|
||||
@ -117,10 +99,7 @@ fn handle_array_element(
|
||||
},
|
||||
ast::ExprKind::IncludedBytes(..) => {
|
||||
if !*has_errors {
|
||||
cx.struct_span_err(expr.span, "cannot concatenate doubly nested array")
|
||||
.note("byte strings are treated as arrays of bytes")
|
||||
.help("try flattening the array")
|
||||
.emit();
|
||||
cx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false });
|
||||
}
|
||||
*has_errors = true;
|
||||
None
|
||||
@ -167,7 +146,7 @@ pub fn expand_concat_bytes(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cx.span_err(count.value.span, "repeat count is not a positive number");
|
||||
cx.emit_err(errors::ConcatBytesBadRepeat {span: count.value.span });
|
||||
}
|
||||
}
|
||||
&ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
|
||||
@ -196,9 +175,7 @@ pub fn expand_concat_bytes(
|
||||
}
|
||||
}
|
||||
if !missing_literals.is_empty() {
|
||||
let mut err = cx.struct_span_err(missing_literals, "expected a byte literal");
|
||||
err.note("only byte literals (like `b\"foo\"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()`");
|
||||
err.emit();
|
||||
cx.emit_err(errors::ConcatBytesMissingLiteral { spans: missing_literals });
|
||||
return base::MacEager::expr(DummyResult::raw_expr(sp, true));
|
||||
} else if has_errors {
|
||||
return base::MacEager::expr(DummyResult::raw_expr(sp, true));
|
||||
|
@ -6,13 +6,15 @@ use rustc_expand::base::{self, *};
|
||||
use rustc_span::symbol::{Ident, Symbol};
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::errors;
|
||||
|
||||
pub fn expand_concat_idents<'cx>(
|
||||
cx: &'cx mut ExtCtxt<'_>,
|
||||
sp: Span,
|
||||
tts: TokenStream,
|
||||
) -> Box<dyn base::MacResult + 'cx> {
|
||||
if tts.is_empty() {
|
||||
cx.span_err(sp, "concat_idents! takes 1 or more arguments");
|
||||
cx.emit_err(errors::ConcatIdentsMissingArgs { span: sp });
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
|
||||
@ -22,7 +24,7 @@ pub fn expand_concat_idents<'cx>(
|
||||
match e {
|
||||
TokenTree::Token(Token { kind: token::Comma, .. }, _) => {}
|
||||
_ => {
|
||||
cx.span_err(sp, "concat_idents! expecting comma");
|
||||
cx.emit_err(errors::ConcatIdentsMissingComma { span: sp });
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
}
|
||||
@ -34,7 +36,7 @@ pub fn expand_concat_idents<'cx>(
|
||||
}
|
||||
}
|
||||
|
||||
cx.span_err(sp, "concat_idents! requires ident args");
|
||||
cx.emit_err(errors::ConcatIdentsIdentArgs { span: sp });
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::cfg_eval::cfg_eval;
|
||||
use crate::errors;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
|
||||
use rustc_errors::{struct_span_err, Applicability};
|
||||
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier};
|
||||
use rustc_feature::AttributeTemplate;
|
||||
use rustc_parse::validate_attr;
|
||||
@ -116,49 +116,33 @@ fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool {
|
||||
let bad_target =
|
||||
!matches!(item_kind, Some(ItemKind::Struct(..) | ItemKind::Enum(..) | ItemKind::Union(..)));
|
||||
if bad_target {
|
||||
struct_span_err!(
|
||||
sess,
|
||||
span,
|
||||
E0774,
|
||||
"`derive` may only be applied to `struct`s, `enum`s and `union`s",
|
||||
)
|
||||
.span_label(span, "not applicable here")
|
||||
.span_label(item.span(), "not a `struct`, `enum` or `union`")
|
||||
.emit();
|
||||
sess.emit_err(errors::BadDeriveTarget { span, item: item.span() });
|
||||
}
|
||||
bad_target
|
||||
}
|
||||
|
||||
fn report_unexpected_meta_item_lit(sess: &Session, lit: &ast::MetaItemLit) {
|
||||
let help_msg = match lit.kind {
|
||||
let help = match lit.kind {
|
||||
ast::LitKind::Str(_, ast::StrStyle::Cooked)
|
||||
if rustc_lexer::is_ident(lit.symbol.as_str()) =>
|
||||
{
|
||||
format!("try using `#[derive({})]`", lit.symbol)
|
||||
errors::BadDeriveLitHelp::StrLit { sym: lit.symbol }
|
||||
}
|
||||
_ => "for example, write `#[derive(Debug)]` for `Debug`".to_string(),
|
||||
_ => errors::BadDeriveLitHelp::Other,
|
||||
};
|
||||
struct_span_err!(sess, lit.span, E0777, "expected path to a trait, found literal",)
|
||||
.span_label(lit.span, "not a trait")
|
||||
.help(&help_msg)
|
||||
.emit();
|
||||
sess.emit_err(errors::BadDeriveLit { span: lit.span, help });
|
||||
}
|
||||
|
||||
fn report_path_args(sess: &Session, meta: &ast::MetaItem) {
|
||||
let report_error = |title, action| {
|
||||
let span = meta.span.with_lo(meta.path.span.hi());
|
||||
sess.struct_span_err(span, title)
|
||||
.span_suggestion(span, action, "", Applicability::MachineApplicable)
|
||||
.emit();
|
||||
};
|
||||
let span = meta.span.with_lo(meta.path.span.hi());
|
||||
|
||||
match meta.kind {
|
||||
MetaItemKind::Word => {}
|
||||
MetaItemKind::List(..) => report_error(
|
||||
"traits in `#[derive(...)]` don't accept arguments",
|
||||
"remove the arguments",
|
||||
),
|
||||
MetaItemKind::List(..) => {
|
||||
sess.emit_err(errors::DerivePathArgsList { span });
|
||||
}
|
||||
MetaItemKind::NameValue(..) => {
|
||||
report_error("traits in `#[derive(...)]` don't accept values", "remove the value")
|
||||
sess.emit_err(errors::DerivePathArgsValue { span });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::deriving::generic::ty::*;
|
||||
use crate::deriving::generic::*;
|
||||
use crate::errors;
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::{attr, walk_list, EnumDef, VariantData};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::symbol::{kw, sym};
|
||||
@ -118,67 +118,50 @@ fn extract_default_variant<'a>(
|
||||
.filter(|variant| matches!(variant.data, VariantData::Unit(..)))
|
||||
.filter(|variant| !attr::contains_name(&variant.attrs, sym::non_exhaustive));
|
||||
|
||||
let mut diag = cx.struct_span_err(trait_span, "no default declared");
|
||||
diag.help("make a unit variant default by placing `#[default]` above it");
|
||||
for variant in possible_defaults {
|
||||
// Suggest making each unit variant default.
|
||||
diag.tool_only_span_suggestion(
|
||||
variant.span,
|
||||
&format!("make `{}` default", variant.ident),
|
||||
format!("#[default] {}", variant.ident),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
diag.emit();
|
||||
let suggs = possible_defaults
|
||||
.map(|v| errors::NoDefaultVariantSugg { span: v.span, ident: v.ident })
|
||||
.collect();
|
||||
cx.emit_err(errors::NoDefaultVariant { span: trait_span, suggs });
|
||||
|
||||
return Err(());
|
||||
}
|
||||
[first, rest @ ..] => {
|
||||
let mut diag = cx.struct_span_err(trait_span, "multiple declared defaults");
|
||||
diag.span_label(first.span, "first default");
|
||||
diag.span_labels(rest.iter().map(|variant| variant.span), "additional default");
|
||||
diag.note("only one variant can be default");
|
||||
for variant in &default_variants {
|
||||
// Suggest making each variant already tagged default.
|
||||
let suggestion = default_variants
|
||||
.iter()
|
||||
.filter_map(|v| {
|
||||
if v.span == variant.span {
|
||||
None
|
||||
} else {
|
||||
Some((attr::find_by_name(&v.attrs, kw::Default)?.span, String::new()))
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
diag.tool_only_multipart_suggestion(
|
||||
&format!("make `{}` default", variant.ident),
|
||||
suggestion,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
diag.emit();
|
||||
|
||||
let suggs = default_variants
|
||||
.iter()
|
||||
.map(|variant| {
|
||||
let spans = default_variants
|
||||
.iter()
|
||||
.filter_map(|v| {
|
||||
if v.span == variant.span {
|
||||
None
|
||||
} else {
|
||||
Some(attr::find_by_name(&v.attrs, kw::Default)?.span)
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
errors::MultipleDefaultsSugg { spans, ident: variant.ident }
|
||||
})
|
||||
.collect();
|
||||
cx.emit_err(errors::MultipleDefaults {
|
||||
span: trait_span,
|
||||
first: first.span,
|
||||
additional: rest.iter().map(|v| v.span).collect(),
|
||||
suggs,
|
||||
});
|
||||
return Err(());
|
||||
}
|
||||
};
|
||||
|
||||
if !matches!(variant.data, VariantData::Unit(..)) {
|
||||
cx.struct_span_err(
|
||||
variant.ident.span,
|
||||
"the `#[default]` attribute may only be used on unit enum variants",
|
||||
)
|
||||
.help("consider a manual implementation of `Default`")
|
||||
.emit();
|
||||
|
||||
cx.emit_err(errors::NonUnitDefault { span: variant.ident.span });
|
||||
return Err(());
|
||||
}
|
||||
|
||||
if let Some(non_exhaustive_attr) = attr::find_by_name(&variant.attrs, sym::non_exhaustive) {
|
||||
cx.struct_span_err(variant.ident.span, "default variant must be exhaustive")
|
||||
.span_label(non_exhaustive_attr.span, "declared `#[non_exhaustive]` here")
|
||||
.help("consider a manual implementation of `Default`")
|
||||
.emit();
|
||||
cx.emit_err(errors::NonExhaustiveDefault {
|
||||
span: variant.ident.span,
|
||||
non_exhaustive: non_exhaustive_attr.span,
|
||||
});
|
||||
|
||||
return Err(());
|
||||
}
|
||||
@ -199,35 +182,23 @@ fn validate_default_attribute(
|
||||
"this method must only be called with a variant that has a `#[default]` attribute",
|
||||
),
|
||||
[first, rest @ ..] => {
|
||||
let suggestion_text =
|
||||
if rest.len() == 1 { "try removing this" } else { "try removing these" };
|
||||
|
||||
cx.struct_span_err(default_variant.ident.span, "multiple `#[default]` attributes")
|
||||
.note("only one `#[default]` attribute is needed")
|
||||
.span_label(first.span, "`#[default]` used here")
|
||||
.span_label(rest[0].span, "`#[default]` used again here")
|
||||
.span_help(rest.iter().map(|attr| attr.span).collect::<Vec<_>>(), suggestion_text)
|
||||
// This would otherwise display the empty replacement, hence the otherwise
|
||||
// repetitive `.span_help` call above.
|
||||
.tool_only_multipart_suggestion(
|
||||
suggestion_text,
|
||||
rest.iter().map(|attr| (attr.span, String::new())).collect(),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
let sugg = errors::MultipleDefaultAttrsSugg {
|
||||
spans: rest.iter().map(|attr| attr.span).collect(),
|
||||
};
|
||||
cx.emit_err(errors::MultipleDefaultAttrs {
|
||||
span: default_variant.ident.span,
|
||||
first: first.span,
|
||||
first_rest: rest[0].span,
|
||||
rest: rest.iter().map(|attr| attr.span).collect::<Vec<_>>().into(),
|
||||
only_one: rest.len() == 1,
|
||||
sugg,
|
||||
});
|
||||
|
||||
return Err(());
|
||||
}
|
||||
};
|
||||
if !attr.is_word() {
|
||||
cx.struct_span_err(attr.span, "`#[default]` attribute does not accept a value")
|
||||
.span_suggestion_hidden(
|
||||
attr.span,
|
||||
"try using `#[default]`",
|
||||
"#[default]",
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit();
|
||||
cx.emit_err(errors::DefaultHasArg { span: attr.span });
|
||||
|
||||
return Err(());
|
||||
}
|
||||
@ -241,12 +212,7 @@ struct DetectNonVariantDefaultAttr<'a, 'b> {
|
||||
impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, 'b> {
|
||||
fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) {
|
||||
if attr.has_name(kw::Default) {
|
||||
self.cx
|
||||
.struct_span_err(
|
||||
attr.span,
|
||||
"the `#[default]` attribute may only be used on unit enum variants",
|
||||
)
|
||||
.emit();
|
||||
self.cx.emit_err(errors::NonUnitDefault { span: attr.span });
|
||||
}
|
||||
|
||||
rustc_ast::visit::walk_attribute(self, attr);
|
||||
|
@ -162,7 +162,7 @@
|
||||
pub use StaticFields::*;
|
||||
pub use SubstructureFields::*;
|
||||
|
||||
use crate::deriving;
|
||||
use crate::{deriving, errors};
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::{
|
||||
self as ast, BindingAnnotation, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, Generics,
|
||||
@ -415,7 +415,7 @@ fn find_type_parameters(
|
||||
}
|
||||
|
||||
fn visit_mac_call(&mut self, mac: &ast::MacCall) {
|
||||
self.cx.span_err(mac.span(), "`derive` cannot be used on items with type macros");
|
||||
self.cx.emit_err(errors::DeriveMacroCall { span: mac.span() });
|
||||
}
|
||||
}
|
||||
|
||||
@ -488,7 +488,7 @@ impl<'a> TraitDef<'a> {
|
||||
is_packed,
|
||||
)
|
||||
} else {
|
||||
cx.span_err(mitem.span, "this trait cannot be derived for unions");
|
||||
cx.emit_err(errors::DeriveUnion { span: mitem.span });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,8 @@ use rustc_span::Span;
|
||||
use std::env;
|
||||
use thin_vec::thin_vec;
|
||||
|
||||
use crate::errors;
|
||||
|
||||
pub fn expand_option_env<'cx>(
|
||||
cx: &'cx mut ExtCtxt<'_>,
|
||||
sp: Span,
|
||||
@ -54,7 +56,7 @@ pub fn expand_env<'cx>(
|
||||
) -> Box<dyn base::MacResult + 'cx> {
|
||||
let mut exprs = match get_exprs_from_tts(cx, tts) {
|
||||
Some(exprs) if exprs.is_empty() || exprs.len() > 2 => {
|
||||
cx.span_err(sp, "env! takes 1 or 2 arguments");
|
||||
cx.emit_err(errors::EnvTakesArgs { span: sp });
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
None => return DummyResult::any(sp),
|
||||
@ -78,18 +80,12 @@ pub fn expand_env<'cx>(
|
||||
cx.sess.parse_sess.env_depinfo.borrow_mut().insert((var, value));
|
||||
let e = match value {
|
||||
None => {
|
||||
let (msg, help) = match custom_msg {
|
||||
None => (
|
||||
format!("environment variable `{var}` not defined at compile time"),
|
||||
Some(help_for_missing_env_var(var.as_str())),
|
||||
),
|
||||
Some(s) => (s.to_string(), None),
|
||||
};
|
||||
let mut diag = cx.struct_span_err(sp, &msg);
|
||||
if let Some(help) = help {
|
||||
diag.help(help);
|
||||
}
|
||||
diag.emit();
|
||||
cx.emit_err(errors::EnvNotDefined {
|
||||
span: sp,
|
||||
msg: custom_msg,
|
||||
var,
|
||||
help: custom_msg.is_none().then(|| help_for_missing_env_var(var.as_str())),
|
||||
});
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
Some(value) => cx.expr_str(sp, value),
|
||||
@ -97,15 +93,13 @@ pub fn expand_env<'cx>(
|
||||
MacEager::expr(e)
|
||||
}
|
||||
|
||||
fn help_for_missing_env_var(var: &str) -> String {
|
||||
fn help_for_missing_env_var(var: &str) -> errors::EnvNotDefinedHelp {
|
||||
if var.starts_with("CARGO_")
|
||||
|| var.starts_with("DEP_")
|
||||
|| matches!(var, "OUT_DIR" | "OPT_LEVEL" | "PROFILE" | "HOST" | "TARGET")
|
||||
{
|
||||
format!(
|
||||
"Cargo sets build script variables at run time. Use `std::env::var(\"{var}\")` instead"
|
||||
)
|
||||
errors::EnvNotDefinedHelp::CargoVar
|
||||
} else {
|
||||
format!("Use `std::env::var(\"{var}\")` to read the variable at run time")
|
||||
errors::EnvNotDefinedHelp::Other
|
||||
}
|
||||
}
|
||||
|
553
compiler/rustc_builtin_macros/src/errors.rs
Normal file
553
compiler/rustc_builtin_macros/src/errors.rs
Normal file
@ -0,0 +1,553 @@
|
||||
use rustc_errors::{
|
||||
AddToDiagnostic, EmissionGuarantee, IntoDiagnostic, MultiSpan, SingleLabelManySpans,
|
||||
};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_span::{symbol::Ident, Span, Symbol};
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_requires_cfg_pattern)]
|
||||
pub(crate) struct RequiresCfgPattern {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_expected_one_cfg_pattern)]
|
||||
pub(crate) struct OneCfgPattern {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_alloc_error_must_be_fn)]
|
||||
pub(crate) struct AllocErrorMustBeFn {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_assert_requires_boolean)]
|
||||
pub(crate) struct AssertRequiresBoolean {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_assert_requires_expression)]
|
||||
pub(crate) struct AssertRequiresExpression {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
#[suggestion(code = "", applicability = "maybe-incorrect")]
|
||||
pub(crate) token: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_assert_missing_comma)]
|
||||
pub(crate) struct AssertMissingComma {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
#[suggestion(code = ", ", applicability = "maybe-incorrect", style = "short")]
|
||||
pub(crate) comma: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
pub(crate) enum CfgAccessibleInvalid {
|
||||
#[diag(builtin_macros_cfg_accessible_unspecified_path)]
|
||||
UnspecifiedPath(#[primary_span] Span),
|
||||
#[diag(builtin_macros_cfg_accessible_multiple_paths)]
|
||||
MultiplePaths(#[primary_span] Span),
|
||||
#[diag(builtin_macros_cfg_accessible_literal_path)]
|
||||
LiteralPath(#[primary_span] Span),
|
||||
#[diag(builtin_macros_cfg_accessible_has_args)]
|
||||
HasArguments(#[primary_span] Span),
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_cfg_accessible_indeterminate)]
|
||||
pub(crate) struct CfgAccessibleIndeterminate {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_concat_missing_literal)]
|
||||
#[note]
|
||||
pub(crate) struct ConcatMissingLiteral {
|
||||
#[primary_span]
|
||||
pub(crate) spans: Vec<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_concat_bytestr)]
|
||||
pub(crate) struct ConcatBytestr {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_concat_bytes_invalid)]
|
||||
pub(crate) struct ConcatBytesInvalid {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) lit_kind: &'static str,
|
||||
#[subdiagnostic]
|
||||
pub(crate) sugg: Option<ConcatBytesInvalidSuggestion>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum ConcatBytesInvalidSuggestion {
|
||||
#[suggestion(
|
||||
builtin_macros_byte_char,
|
||||
code = "b{snippet}",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
CharLit {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
snippet: String,
|
||||
},
|
||||
#[suggestion(
|
||||
builtin_macros_byte_str,
|
||||
code = "b{snippet}",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
StrLit {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
snippet: String,
|
||||
},
|
||||
#[suggestion(
|
||||
builtin_macros_number_array,
|
||||
code = "[{snippet}]",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
IntLit {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
snippet: String,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_concat_bytes_oob)]
|
||||
pub(crate) struct ConcatBytesOob {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_concat_bytes_non_u8)]
|
||||
pub(crate) struct ConcatBytesNonU8 {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_concat_bytes_missing_literal)]
|
||||
#[note]
|
||||
pub(crate) struct ConcatBytesMissingLiteral {
|
||||
#[primary_span]
|
||||
pub(crate) spans: Vec<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_concat_bytes_array)]
|
||||
pub(crate) struct ConcatBytesArray {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
#[note]
|
||||
#[help]
|
||||
pub(crate) bytestr: bool,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_concat_bytes_bad_repeat)]
|
||||
pub(crate) struct ConcatBytesBadRepeat {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_concat_idents_missing_args)]
|
||||
pub(crate) struct ConcatIdentsMissingArgs {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_concat_idents_missing_comma)]
|
||||
pub(crate) struct ConcatIdentsMissingComma {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_concat_idents_ident_args)]
|
||||
pub(crate) struct ConcatIdentsIdentArgs {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_bad_derive_target, code = "E0774")]
|
||||
pub(crate) struct BadDeriveTarget {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub(crate) span: Span,
|
||||
#[label(builtin_macros_label2)]
|
||||
pub(crate) item: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_unexpected_lit, code = "E0777")]
|
||||
pub(crate) struct BadDeriveLit {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub(crate) span: Span,
|
||||
#[subdiagnostic]
|
||||
pub help: BadDeriveLitHelp,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum BadDeriveLitHelp {
|
||||
#[help(builtin_macros_str_lit)]
|
||||
StrLit { sym: Symbol },
|
||||
#[help(builtin_macros_other)]
|
||||
Other,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_derive_path_args_list)]
|
||||
pub(crate) struct DerivePathArgsList {
|
||||
#[suggestion(code = "", applicability = "machine-applicable")]
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_derive_path_args_value)]
|
||||
pub(crate) struct DerivePathArgsValue {
|
||||
#[suggestion(code = "", applicability = "machine-applicable")]
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_no_default_variant)]
|
||||
#[help]
|
||||
pub(crate) struct NoDefaultVariant {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
#[subdiagnostic]
|
||||
pub(crate) suggs: Vec<NoDefaultVariantSugg>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(
|
||||
builtin_macros_suggestion,
|
||||
code = "#[default] {ident}",
|
||||
applicability = "maybe-incorrect",
|
||||
style = "tool-only"
|
||||
)]
|
||||
pub(crate) struct NoDefaultVariantSugg {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) ident: Ident,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_multiple_defaults)]
|
||||
#[note]
|
||||
pub(crate) struct MultipleDefaults {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
#[label]
|
||||
pub(crate) first: Span,
|
||||
#[label(builtin_macros_additional)]
|
||||
pub additional: Vec<Span>,
|
||||
#[subdiagnostic]
|
||||
pub suggs: Vec<MultipleDefaultsSugg>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
builtin_macros_suggestion,
|
||||
applicability = "maybe-incorrect",
|
||||
style = "tool-only"
|
||||
)]
|
||||
pub(crate) struct MultipleDefaultsSugg {
|
||||
#[suggestion_part(code = "")]
|
||||
pub(crate) spans: Vec<Span>,
|
||||
pub(crate) ident: Ident,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_non_unit_default)]
|
||||
#[help]
|
||||
pub(crate) struct NonUnitDefault {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_non_exhaustive_default)]
|
||||
#[help]
|
||||
pub(crate) struct NonExhaustiveDefault {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
#[label]
|
||||
pub(crate) non_exhaustive: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_multiple_default_attrs)]
|
||||
#[note]
|
||||
pub(crate) struct MultipleDefaultAttrs {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
#[label]
|
||||
pub(crate) first: Span,
|
||||
#[label(builtin_macros_label_again)]
|
||||
pub(crate) first_rest: Span,
|
||||
#[help]
|
||||
pub(crate) rest: MultiSpan,
|
||||
pub(crate) only_one: bool,
|
||||
#[subdiagnostic]
|
||||
pub(crate) sugg: MultipleDefaultAttrsSugg,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
builtin_macros_help,
|
||||
applicability = "machine-applicable",
|
||||
style = "tool-only"
|
||||
)]
|
||||
pub(crate) struct MultipleDefaultAttrsSugg {
|
||||
#[suggestion_part(code = "")]
|
||||
pub(crate) spans: Vec<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_default_arg)]
|
||||
pub(crate) struct DefaultHasArg {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "#[default]", style = "hidden", applicability = "maybe-incorrect")]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_derive_macro_call)]
|
||||
pub(crate) struct DeriveMacroCall {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_cannot_derive_union)]
|
||||
pub(crate) struct DeriveUnion {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_env_takes_args)]
|
||||
pub(crate) struct EnvTakesArgs {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
//#[derive(Diagnostic)]
|
||||
//#[diag(builtin_macros_env_not_defined)]
|
||||
pub(crate) struct EnvNotDefined {
|
||||
pub(crate) span: Span,
|
||||
pub(crate) msg: Option<Symbol>,
|
||||
pub(crate) var: Symbol,
|
||||
pub(crate) help: Option<EnvNotDefinedHelp>,
|
||||
}
|
||||
|
||||
// Hand-written implementation to support custom user messages
|
||||
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for EnvNotDefined {
|
||||
#[track_caller]
|
||||
fn into_diagnostic(
|
||||
self,
|
||||
handler: &'a rustc_errors::Handler,
|
||||
) -> rustc_errors::DiagnosticBuilder<'a, G> {
|
||||
let mut diag = if let Some(msg) = self.msg {
|
||||
handler.struct_diagnostic(msg.as_str())
|
||||
} else {
|
||||
handler.struct_diagnostic(crate::fluent_generated::builtin_macros_env_not_defined)
|
||||
};
|
||||
diag.set_arg("var", self.var);
|
||||
diag.set_span(self.span);
|
||||
if let Some(help) = self.help {
|
||||
diag.subdiagnostic(help);
|
||||
}
|
||||
diag
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum EnvNotDefinedHelp {
|
||||
#[help(builtin_macros_cargo)]
|
||||
CargoVar,
|
||||
#[help(builtin_macros_other)]
|
||||
Other,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_format_requires_string)]
|
||||
pub(crate) struct FormatRequiresString {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_format_duplicate_arg)]
|
||||
pub(crate) struct FormatDuplicateArg {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
#[label(builtin_macros_label1)]
|
||||
pub(crate) prev: Span,
|
||||
#[label(builtin_macros_label2)]
|
||||
pub(crate) duplicate: Span,
|
||||
pub(crate) ident: Ident,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_format_positional_after_named)]
|
||||
pub(crate) struct PositionalAfterNamed {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub(crate) span: Span,
|
||||
#[label(builtin_macros_named_args)]
|
||||
pub(crate) args: Vec<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_format_string_invalid)]
|
||||
pub(crate) struct InvalidFormatString {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) desc: String,
|
||||
pub(crate) label1: String,
|
||||
#[subdiagnostic]
|
||||
pub(crate) note_: Option<InvalidFormatStringNote>,
|
||||
#[subdiagnostic]
|
||||
pub(crate) label_: Option<InvalidFormatStringLabel>,
|
||||
#[subdiagnostic]
|
||||
pub(crate) sugg_: Option<InvalidFormatStringSuggestion>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(builtin_macros_note)]
|
||||
pub(crate) struct InvalidFormatStringNote {
|
||||
pub(crate) note: String,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[label(builtin_macros_second_label)]
|
||||
pub(crate) struct InvalidFormatStringLabel {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) label: String,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
builtin_macros_sugg,
|
||||
style = "verbose",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub(crate) struct InvalidFormatStringSuggestion {
|
||||
#[suggestion_part(code = "{len}")]
|
||||
pub(crate) captured: Span,
|
||||
pub(crate) len: String,
|
||||
#[suggestion_part(code = ", {arg}")]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) arg: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_format_no_arg_named)]
|
||||
#[note]
|
||||
#[note(builtin_macros_note2)]
|
||||
pub(crate) struct FormatNoArgNamed {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_format_unknown_trait)]
|
||||
#[note]
|
||||
pub(crate) struct FormatUnknownTrait<'a> {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) ty: &'a str,
|
||||
#[subdiagnostic]
|
||||
pub(crate) suggs: Vec<FormatUnknownTraitSugg>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(
|
||||
builtin_macros_suggestion,
|
||||
code = "{fmt}",
|
||||
style = "tool-only",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
pub struct FormatUnknownTraitSugg {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub fmt: &'static str,
|
||||
pub trait_name: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_format_unused_arg)]
|
||||
pub(crate) struct FormatUnusedArg {
|
||||
#[primary_span]
|
||||
#[label(builtin_macros_format_unused_arg)]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) named: bool,
|
||||
}
|
||||
|
||||
// Allow the singular form to be a subdiagnostic of the multiple-unused
|
||||
// form of diagnostic.
|
||||
impl AddToDiagnostic for FormatUnusedArg {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, f: F)
|
||||
where
|
||||
F: Fn(
|
||||
&mut rustc_errors::Diagnostic,
|
||||
rustc_errors::SubdiagnosticMessage,
|
||||
) -> rustc_errors::SubdiagnosticMessage,
|
||||
{
|
||||
diag.set_arg("named", self.named);
|
||||
let msg = f(diag, crate::fluent_generated::builtin_macros_format_unused_arg.into());
|
||||
diag.span_label(self.span, msg);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_format_unused_args)]
|
||||
pub(crate) struct FormatUnusedArgs {
|
||||
#[primary_span]
|
||||
pub(crate) unused: Vec<Span>,
|
||||
#[label]
|
||||
pub(crate) fmt: Span,
|
||||
#[subdiagnostic]
|
||||
pub(crate) unused_labels: Vec<FormatUnusedArg>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_format_pos_mismatch)]
|
||||
pub(crate) struct FormatPositionalMismatch {
|
||||
#[primary_span]
|
||||
pub(crate) span: MultiSpan,
|
||||
pub(crate) n: usize,
|
||||
pub(crate) desc: String,
|
||||
#[subdiagnostic]
|
||||
pub(crate) highlight: SingleLabelManySpans,
|
||||
}
|
@ -7,7 +7,7 @@ use rustc_ast::{
|
||||
FormatDebugHex, FormatOptions, FormatPlaceholder, FormatSign, FormatTrait,
|
||||
};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{pluralize, Applicability, MultiSpan, PResult};
|
||||
use rustc_errors::{Applicability, MultiSpan, PResult, SingleLabelManySpans};
|
||||
use rustc_expand::base::{self, *};
|
||||
use rustc_parse_format as parse;
|
||||
use rustc_span::symbol::{Ident, Symbol};
|
||||
@ -36,11 +36,13 @@ enum PositionUsedAs {
|
||||
}
|
||||
use PositionUsedAs::*;
|
||||
|
||||
use crate::errors;
|
||||
|
||||
struct MacroInput {
|
||||
fmtstr: P<Expr>,
|
||||
args: FormatArguments,
|
||||
/// Whether the first argument was a string literal or a result from eager macro expansion.
|
||||
/// If it's not a string literal, we disallow implicit arugment capturing.
|
||||
/// If it's not a string literal, we disallow implicit argument capturing.
|
||||
///
|
||||
/// This does not correspond to whether we can treat spans to the literal normally, as the whole
|
||||
/// invocation might be the result of another macro expansion, in which case this flag may still be true.
|
||||
@ -66,7 +68,7 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<
|
||||
let mut p = ecx.new_parser_from_tts(tts);
|
||||
|
||||
if p.token == token::Eof {
|
||||
return Err(ecx.struct_span_err(sp, "requires at least a format string argument"));
|
||||
return Err(ecx.create_err(errors::FormatRequiresString { span: sp }));
|
||||
}
|
||||
|
||||
let first_token = &p.token;
|
||||
@ -121,13 +123,12 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<
|
||||
p.expect(&token::Eq)?;
|
||||
let expr = p.parse_expr()?;
|
||||
if let Some((_, prev)) = args.by_name(ident.name) {
|
||||
ecx.struct_span_err(
|
||||
ident.span,
|
||||
&format!("duplicate argument named `{}`", ident),
|
||||
)
|
||||
.span_label(prev.kind.ident().unwrap().span, "previously here")
|
||||
.span_label(ident.span, "duplicate argument")
|
||||
.emit();
|
||||
ecx.emit_err(errors::FormatDuplicateArg {
|
||||
span: ident.span,
|
||||
prev: prev.kind.ident().unwrap().span,
|
||||
duplicate: ident.span,
|
||||
ident,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
args.add(FormatArgument { kind: FormatArgumentKind::Named(ident), expr });
|
||||
@ -135,20 +136,21 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<
|
||||
_ => {
|
||||
let expr = p.parse_expr()?;
|
||||
if !args.named_args().is_empty() {
|
||||
let mut err = ecx.struct_span_err(
|
||||
expr.span,
|
||||
"positional arguments cannot follow named arguments",
|
||||
);
|
||||
err.span_label(
|
||||
expr.span,
|
||||
"positional arguments must be before named arguments",
|
||||
);
|
||||
for arg in args.named_args() {
|
||||
if let Some(name) = arg.kind.ident() {
|
||||
err.span_label(name.span.to(arg.expr.span), "named argument");
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
ecx.emit_err(errors::PositionalAfterNamed {
|
||||
span: expr.span,
|
||||
args: args
|
||||
.named_args()
|
||||
.iter()
|
||||
.filter_map(|a| {
|
||||
if let Some(ident) = a.kind.ident() {
|
||||
Some((a, ident))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.map(|(arg, n)| n.span.to(arg.expr.span))
|
||||
.collect(),
|
||||
});
|
||||
}
|
||||
args.add(FormatArgument { kind: FormatArgumentKind::Normal, expr });
|
||||
}
|
||||
@ -234,13 +236,19 @@ fn make_format_args(
|
||||
// argument span here.
|
||||
fmt_span
|
||||
};
|
||||
let mut e = ecx.struct_span_err(sp, &format!("invalid format string: {}", err.description));
|
||||
e.span_label(sp, err.label + " in format string");
|
||||
let mut e = errors::InvalidFormatString {
|
||||
span: sp,
|
||||
note_: None,
|
||||
label_: None,
|
||||
sugg_: None,
|
||||
desc: err.description,
|
||||
label1: err.label,
|
||||
};
|
||||
if let Some(note) = err.note {
|
||||
e.note(¬e);
|
||||
e.note_ = Some(errors::InvalidFormatStringNote { note });
|
||||
}
|
||||
if let Some((label, span)) = err.secondary_label && is_source_literal {
|
||||
e.span_label(fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label);
|
||||
e.label_ = Some(errors::InvalidFormatStringLabel { span: fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label } );
|
||||
}
|
||||
if err.should_be_replaced_with_positional_argument {
|
||||
let captured_arg_span =
|
||||
@ -250,17 +258,15 @@ fn make_format_args(
|
||||
Some(arg) => arg.expr.span,
|
||||
None => fmt_span,
|
||||
};
|
||||
e.multipart_suggestion_verbose(
|
||||
"consider using a positional formatting argument instead",
|
||||
vec![
|
||||
(captured_arg_span, args.unnamed_args().len().to_string()),
|
||||
(span.shrink_to_hi(), format!(", {}", arg)),
|
||||
],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
e.sugg_ = Some(errors::InvalidFormatStringSuggestion {
|
||||
captured: captured_arg_span,
|
||||
len: args.unnamed_args().len().to_string(),
|
||||
span: span.shrink_to_hi(),
|
||||
arg,
|
||||
});
|
||||
}
|
||||
}
|
||||
e.emit();
|
||||
ecx.emit_err(e);
|
||||
return Err(());
|
||||
}
|
||||
|
||||
@ -318,10 +324,7 @@ fn make_format_args(
|
||||
} else {
|
||||
// For the moment capturing variables from format strings expanded from macros is
|
||||
// disabled (see RFC #2795)
|
||||
ecx.struct_span_err(span, &format!("there is no argument named `{name}`"))
|
||||
.note(format!("did you intend to capture a variable `{name}` from the surrounding scope?"))
|
||||
.note("to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro")
|
||||
.emit();
|
||||
ecx.emit_err(errors::FormatNoArgNamed { span, name });
|
||||
DummyResult::raw_expr(span, true)
|
||||
};
|
||||
Ok(args.add(FormatArgument { kind: FormatArgumentKind::Captured(ident), expr }))
|
||||
@ -475,12 +478,8 @@ fn make_format_args(
|
||||
.enumerate()
|
||||
.filter(|&(_, used)| !used)
|
||||
.map(|(i, _)| {
|
||||
let msg = if let FormatArgumentKind::Named(_) = args.explicit_args()[i].kind {
|
||||
"named argument never used"
|
||||
} else {
|
||||
"argument never used"
|
||||
};
|
||||
(args.explicit_args()[i].expr.span, msg)
|
||||
let named = matches!(args.explicit_args()[i].kind, FormatArgumentKind::Named(_));
|
||||
(args.explicit_args()[i].expr.span, named)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@ -531,22 +530,8 @@ fn invalid_placeholder_type_error(
|
||||
fmt_span: Span,
|
||||
) {
|
||||
let sp = ty_span.map(|sp| fmt_span.from_inner(InnerSpan::new(sp.start, sp.end)));
|
||||
let mut err =
|
||||
ecx.struct_span_err(sp.unwrap_or(fmt_span), &format!("unknown format trait `{}`", ty));
|
||||
err.note(
|
||||
"the only appropriate formatting traits are:\n\
|
||||
- ``, which uses the `Display` trait\n\
|
||||
- `?`, which uses the `Debug` trait\n\
|
||||
- `e`, which uses the `LowerExp` trait\n\
|
||||
- `E`, which uses the `UpperExp` trait\n\
|
||||
- `o`, which uses the `Octal` trait\n\
|
||||
- `p`, which uses the `Pointer` trait\n\
|
||||
- `b`, which uses the `Binary` trait\n\
|
||||
- `x`, which uses the `LowerHex` trait\n\
|
||||
- `X`, which uses the `UpperHex` trait",
|
||||
);
|
||||
if let Some(sp) = sp {
|
||||
for (fmt, name) in &[
|
||||
let suggs = if let Some(sp) = sp {
|
||||
[
|
||||
("", "Display"),
|
||||
("?", "Debug"),
|
||||
("e", "LowerExp"),
|
||||
@ -556,40 +541,38 @@ fn invalid_placeholder_type_error(
|
||||
("b", "Binary"),
|
||||
("x", "LowerHex"),
|
||||
("X", "UpperHex"),
|
||||
] {
|
||||
err.tool_only_span_suggestion(
|
||||
sp,
|
||||
&format!("use the `{}` trait", name),
|
||||
*fmt,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
]
|
||||
.into_iter()
|
||||
.map(|(fmt, trait_name)| errors::FormatUnknownTraitSugg { span: sp, fmt, trait_name })
|
||||
.collect()
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
ecx.emit_err(errors::FormatUnknownTrait { span: sp.unwrap_or(fmt_span), ty, suggs });
|
||||
}
|
||||
|
||||
fn report_missing_placeholders(
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
unused: Vec<(Span, &str)>,
|
||||
unused: Vec<(Span, bool)>,
|
||||
detect_foreign_fmt: bool,
|
||||
str_style: Option<usize>,
|
||||
fmt_str: &str,
|
||||
fmt_span: Span,
|
||||
) {
|
||||
let mut diag = if let &[(span, msg)] = &unused[..] {
|
||||
let mut diag = ecx.struct_span_err(span, msg);
|
||||
diag.span_label(span, msg);
|
||||
diag
|
||||
let mut diag = if let &[(span, named)] = &unused[..] {
|
||||
//let mut diag = ecx.struct_span_err(span, msg);
|
||||
//diag.span_label(span, msg);
|
||||
//diag
|
||||
ecx.create_err(errors::FormatUnusedArg { span, named })
|
||||
} else {
|
||||
let mut diag = ecx.struct_span_err(
|
||||
unused.iter().map(|&(sp, _)| sp).collect::<Vec<Span>>(),
|
||||
"multiple unused formatting arguments",
|
||||
);
|
||||
diag.span_label(fmt_span, "multiple missing formatting specifiers");
|
||||
for &(span, msg) in &unused {
|
||||
diag.span_label(span, msg);
|
||||
}
|
||||
diag
|
||||
let unused_labels =
|
||||
unused.iter().map(|&(span, named)| errors::FormatUnusedArg { span, named }).collect();
|
||||
let unused_spans = unused.iter().map(|&(span, _)| span).collect();
|
||||
ecx.create_err(errors::FormatUnusedArgs {
|
||||
fmt: fmt_span,
|
||||
unused: unused_spans,
|
||||
unused_labels,
|
||||
})
|
||||
};
|
||||
|
||||
// Used to ensure we only report translations for *one* kind of foreign format.
|
||||
@ -768,18 +751,16 @@ fn report_invalid_references(
|
||||
} else {
|
||||
MultiSpan::from_spans(spans)
|
||||
};
|
||||
e = ecx.struct_span_err(
|
||||
e = ecx.create_err(errors::FormatPositionalMismatch {
|
||||
span,
|
||||
&format!(
|
||||
"{} positional argument{} in format string, but {}",
|
||||
num_placeholders,
|
||||
pluralize!(num_placeholders),
|
||||
num_args_desc,
|
||||
),
|
||||
);
|
||||
for arg in args.explicit_args() {
|
||||
e.span_label(arg.expr.span, "");
|
||||
}
|
||||
n: num_placeholders,
|
||||
desc: num_args_desc,
|
||||
highlight: SingleLabelManySpans {
|
||||
spans: args.explicit_args().iter().map(|arg| arg.expr.span).collect(),
|
||||
label: "",
|
||||
kind: rustc_errors::LabelKind::Label,
|
||||
},
|
||||
});
|
||||
// Point out `{:.*}` placeholders: those take an extra argument.
|
||||
let mut has_precision_star = false;
|
||||
for piece in template {
|
||||
|
@ -9,6 +9,7 @@
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(is_sorted)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(lint_reasons)]
|
||||
#![feature(proc_macro_internals)]
|
||||
#![feature(proc_macro_quote)]
|
||||
#![recursion_limit = "256"]
|
||||
@ -39,6 +40,7 @@ mod derive;
|
||||
mod deriving;
|
||||
mod edition_panic;
|
||||
mod env;
|
||||
mod errors;
|
||||
mod format;
|
||||
mod format_foreign;
|
||||
mod global_allocator;
|
||||
|
@ -118,34 +118,22 @@ pub fn expand_test_or_bench(
|
||||
}
|
||||
}
|
||||
other => {
|
||||
cx.struct_span_err(
|
||||
other.span(),
|
||||
"`#[test]` attribute is only allowed on non associated functions",
|
||||
)
|
||||
.emit();
|
||||
not_testable_error(cx, attr_sp, None);
|
||||
return vec![other];
|
||||
}
|
||||
};
|
||||
|
||||
// Note: non-associated fn items are already handled by `expand_test_or_bench`
|
||||
let ast::ItemKind::Fn(fn_) = &item.kind else {
|
||||
let diag = &cx.sess.parse_sess.span_diagnostic;
|
||||
let msg = "the `#[test]` attribute may only be used on a non-associated function";
|
||||
let mut err = match item.kind {
|
||||
// These were a warning before #92959 and need to continue being that to avoid breaking
|
||||
// stable user code (#94508).
|
||||
ast::ItemKind::MacCall(_) => diag.struct_span_warn(attr_sp, msg),
|
||||
// `.forget_guarantee()` needed to get these two arms to match types. Because of how
|
||||
// locally close the `.emit()` call is I'm comfortable with it, but if it can be
|
||||
// reworked in the future to not need it, it'd be nice.
|
||||
_ => diag.struct_span_err(attr_sp, msg).forget_guarantee(),
|
||||
not_testable_error(cx, attr_sp, Some(&item));
|
||||
return if is_stmt {
|
||||
vec![Annotatable::Stmt(P(ast::Stmt {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: item.span,
|
||||
kind: ast::StmtKind::Item(item),
|
||||
}))]
|
||||
} else {
|
||||
vec![Annotatable::Item(item)]
|
||||
};
|
||||
err.span_label(attr_sp, "the `#[test]` macro causes a function to be run on a test and has no effect on non-functions")
|
||||
.span_label(item.span, format!("expected a non-associated function, found {} {}", item.kind.article(), item.kind.descr()))
|
||||
.span_suggestion(attr_sp, "replace with conditional compilation to make the item only exist when tests are being run", "#[cfg(test)]", Applicability::MaybeIncorrect)
|
||||
.emit();
|
||||
|
||||
return vec![Annotatable::Item(item)];
|
||||
};
|
||||
|
||||
// has_*_signature will report any errors in the type so compilation
|
||||
@ -398,6 +386,36 @@ pub fn expand_test_or_bench(
|
||||
}
|
||||
}
|
||||
|
||||
fn not_testable_error(cx: &ExtCtxt<'_>, attr_sp: Span, item: Option<&ast::Item>) {
|
||||
let diag = &cx.sess.parse_sess.span_diagnostic;
|
||||
let msg = "the `#[test]` attribute may only be used on a non-associated function";
|
||||
let mut err = match item.map(|i| &i.kind) {
|
||||
// These were a warning before #92959 and need to continue being that to avoid breaking
|
||||
// stable user code (#94508).
|
||||
Some(ast::ItemKind::MacCall(_)) => diag.struct_span_warn(attr_sp, msg),
|
||||
// `.forget_guarantee()` needed to get these two arms to match types. Because of how
|
||||
// locally close the `.emit()` call is I'm comfortable with it, but if it can be
|
||||
// reworked in the future to not need it, it'd be nice.
|
||||
_ => diag.struct_span_err(attr_sp, msg).forget_guarantee(),
|
||||
};
|
||||
if let Some(item) = item {
|
||||
err.span_label(
|
||||
item.span,
|
||||
format!(
|
||||
"expected a non-associated function, found {} {}",
|
||||
item.kind.article(),
|
||||
item.kind.descr()
|
||||
),
|
||||
);
|
||||
}
|
||||
err.span_label(attr_sp, "the `#[test]` macro causes a function to be run as a test and has no effect on non-functions")
|
||||
.span_suggestion(attr_sp,
|
||||
"replace with conditional compilation to make the item only exist when tests are being run",
|
||||
"#[cfg(test)]",
|
||||
Applicability::MaybeIncorrect)
|
||||
.emit();
|
||||
}
|
||||
|
||||
fn get_location_info(cx: &ExtCtxt<'_>, item: &ast::Item) -> (Symbol, usize, usize, usize, usize) {
|
||||
let span = item.ident.span;
|
||||
let (source_file, lo_line, lo_col, hi_line, hi_col) =
|
||||
|
@ -15,6 +15,7 @@
|
||||
const MIN_ALIGN: usize = 8;
|
||||
#[cfg(any(target_arch = "x86_64",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "loongarch64",
|
||||
target_arch = "mips64",
|
||||
target_arch = "s390x",
|
||||
target_arch = "sparc64"))]
|
||||
|
@ -593,6 +593,9 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
|
||||
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w",
|
||||
InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => "a",
|
||||
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => "d",
|
||||
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => "d", // more specific than "r"
|
||||
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => "f",
|
||||
InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => "r",
|
||||
@ -664,6 +667,9 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
|
||||
InlineAsmRegClass::Avr(_) => unimplemented!(),
|
||||
InlineAsmRegClass::Bpf(_) => unimplemented!(),
|
||||
InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(),
|
||||
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(),
|
||||
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => cx.type_i32(),
|
||||
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => cx.type_i32(),
|
||||
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(),
|
||||
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => cx.type_f32(),
|
||||
InlineAsmRegClass::Msp430(_) => unimplemented!(),
|
||||
@ -849,6 +855,7 @@ fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option
|
||||
InlineAsmRegClass::Avr(_) => None,
|
||||
InlineAsmRegClass::S390x(_) => None,
|
||||
InlineAsmRegClass::Msp430(_) => None,
|
||||
InlineAsmRegClass::M68k(_) => None,
|
||||
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
|
||||
bug!("LLVM backend does not support SPIR-V")
|
||||
}
|
||||
|
@ -244,6 +244,9 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
||||
InlineAsmArch::Msp430 => {
|
||||
constraints.push("~{sr}".to_string());
|
||||
}
|
||||
InlineAsmArch::M68k => {
|
||||
constraints.push("~{ccr}".to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
if !options.contains(InlineAsmOptions::NOMEM) {
|
||||
@ -671,6 +674,9 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) ->
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f",
|
||||
InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => "a",
|
||||
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => "d",
|
||||
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
|
||||
bug!("LLVM backend does not support SPIR-V")
|
||||
}
|
||||
@ -768,6 +774,7 @@ fn modifier_to_llvm(
|
||||
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
|
||||
bug!("LLVM backend does not support SPIR-V")
|
||||
}
|
||||
InlineAsmRegClass::M68k(_) => None,
|
||||
InlineAsmRegClass::Err => unreachable!(),
|
||||
}
|
||||
}
|
||||
@ -839,6 +846,9 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => cx.type_i32(),
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(),
|
||||
InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => cx.type_i16(),
|
||||
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(),
|
||||
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => cx.type_i32(),
|
||||
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => cx.type_i32(),
|
||||
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
|
||||
bug!("LLVM backend does not support SPIR-V")
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ codegen_ssa_msvc_missing_linker = the msvc targets depend on the msvc linker but
|
||||
|
||||
codegen_ssa_check_installed_visual_studio = please ensure that Visual Studio 2017 or later, or Build Tools for Visual Studio were installed with the Visual C++ option.
|
||||
|
||||
codegen_ssa_unsufficient_vs_code_product = VS Code is a different product, and is not sufficient.
|
||||
codegen_ssa_insufficient_vs_code_product = VS Code is a different product, and is not sufficient.
|
||||
|
||||
codegen_ssa_processing_dymutil_failed = processing debug info with `dsymutil` failed: {$status}
|
||||
.note = {$output}
|
||||
|
@ -923,7 +923,7 @@ fn link_natively<'a>(
|
||||
if sess.target.is_like_msvc && linker_not_found {
|
||||
sess.emit_note(errors::MsvcMissingLinker);
|
||||
sess.emit_note(errors::CheckInstalledVisualStudio);
|
||||
sess.emit_note(errors::UnsufficientVSCodeProduct);
|
||||
sess.emit_note(errors::InsufficientVSCodeProduct);
|
||||
}
|
||||
sess.abort_if_errors();
|
||||
}
|
||||
|
@ -127,6 +127,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
|
||||
"msp430" => Architecture::Msp430,
|
||||
"hexagon" => Architecture::Hexagon,
|
||||
"bpf" => Architecture::Bpf,
|
||||
"loongarch64" => Architecture::LoongArch64,
|
||||
// Unsupported architecture.
|
||||
_ => return None,
|
||||
};
|
||||
@ -190,6 +191,10 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
|
||||
}
|
||||
e_flags
|
||||
}
|
||||
Architecture::LoongArch64 => {
|
||||
// Source: https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html#_e_flags_identifies_abi_type_and_version
|
||||
elf::EF_LARCH_OBJABI_V1 | elf::EF_LARCH_ABI_DOUBLE_FLOAT
|
||||
}
|
||||
_ => 0,
|
||||
};
|
||||
// adapted from LLVM's `MCELFObjectTargetWriter::getOSABI`
|
||||
|
@ -405,8 +405,8 @@ pub struct MsvcMissingLinker;
|
||||
pub struct CheckInstalledVisualStudio;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_unsufficient_vs_code_product)]
|
||||
pub struct UnsufficientVSCodeProduct;
|
||||
#[diag(codegen_ssa_insufficient_vs_code_product)]
|
||||
pub struct InsufficientVSCodeProduct;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_processing_dymutil_failed)]
|
||||
|
@ -442,11 +442,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
let (var_ty, var_kind) = match var.value {
|
||||
mir::VarDebugInfoContents::Place(place) => {
|
||||
let var_ty = self.monomorphized_place_ty(place.as_ref());
|
||||
let var_kind = if self.mir.local_kind(place.local) == mir::LocalKind::Arg
|
||||
let var_kind = if let Some(arg_index) = var.argument_index
|
||||
&& place.projection.is_empty()
|
||||
&& var.source_info.scope == mir::OUTERMOST_SOURCE_SCOPE
|
||||
{
|
||||
let arg_index = place.local.index() - 1;
|
||||
let arg_index = arg_index as usize;
|
||||
if target_is_msvc {
|
||||
// ScalarPair parameters are spilled to the stack so they need to
|
||||
// be marked as a `LocalVariable` for MSVC debuggers to visualize
|
||||
@ -455,13 +454,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
if let Abi::ScalarPair(_, _) = var_ty_layout.abi {
|
||||
VariableKind::LocalVariable
|
||||
} else {
|
||||
VariableKind::ArgumentVariable(arg_index + 1)
|
||||
VariableKind::ArgumentVariable(arg_index)
|
||||
}
|
||||
} else {
|
||||
// FIXME(eddyb) shouldn't `ArgumentVariable` indices be
|
||||
// offset in closures to account for the hidden environment?
|
||||
// Also, is this `+ 1` needed at all?
|
||||
VariableKind::ArgumentVariable(arg_index + 1)
|
||||
VariableKind::ArgumentVariable(arg_index)
|
||||
}
|
||||
} else {
|
||||
VariableKind::LocalVariable
|
||||
|
@ -251,6 +251,7 @@ const RISCV_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
|
||||
("e", Some(sym::riscv_target_feature)),
|
||||
("f", Some(sym::riscv_target_feature)),
|
||||
("m", Some(sym::riscv_target_feature)),
|
||||
("relax", Some(sym::riscv_target_feature)),
|
||||
("v", Some(sym::riscv_target_feature)),
|
||||
("zba", Some(sym::riscv_target_feature)),
|
||||
("zbb", Some(sym::riscv_target_feature)),
|
||||
|
@ -205,7 +205,7 @@ pub(crate) fn turn_into_const_value<'tcx>(
|
||||
let cid = key.value;
|
||||
let def_id = cid.instance.def.def_id();
|
||||
let is_static = tcx.is_static(def_id);
|
||||
// This is just accessing an already computed constant, so no need to check alginment here.
|
||||
// This is just accessing an already computed constant, so no need to check alignment here.
|
||||
let ecx = mk_eval_cx(
|
||||
tcx,
|
||||
tcx.def_span(key.value.instance.def_id()),
|
||||
|
@ -77,7 +77,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
line: u32,
|
||||
col: u32,
|
||||
) -> MPlaceTy<'tcx, M::Provenance> {
|
||||
let loc_details = &self.tcx.sess.opts.unstable_opts.location_detail;
|
||||
let loc_details = self.tcx.sess.opts.unstable_opts.location_detail;
|
||||
// This can fail if rustc runs out of memory right here. Trying to emit an error would be
|
||||
// pointless, since that would require allocating more memory than these short strings.
|
||||
let file = if loc_details.file {
|
||||
|
@ -679,13 +679,21 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||
// Unlike `mem::transmute`, a MIR `Transmute` is well-formed
|
||||
// for any two `Sized` types, just potentially UB to run.
|
||||
|
||||
if !op_ty.is_sized(self.tcx, self.param_env) {
|
||||
if !self
|
||||
.tcx
|
||||
.normalize_erasing_regions(self.param_env, op_ty)
|
||||
.is_sized(self.tcx, self.param_env)
|
||||
{
|
||||
self.fail(
|
||||
location,
|
||||
format!("Cannot transmute from non-`Sized` type {op_ty:?}"),
|
||||
);
|
||||
}
|
||||
if !target_type.is_sized(self.tcx, self.param_env) {
|
||||
if !self
|
||||
.tcx
|
||||
.normalize_erasing_regions(self.param_env, *target_type)
|
||||
.is_sized(self.tcx, self.param_env)
|
||||
{
|
||||
self.fail(
|
||||
location,
|
||||
format!("Cannot transmute to non-`Sized` type {target_type:?}"),
|
||||
|
@ -33,6 +33,7 @@ tempfile = "3.2"
|
||||
thin-vec = "0.2.12"
|
||||
tracing = "0.1"
|
||||
elsa = "=1.7.1"
|
||||
itertools = "0.10.1"
|
||||
|
||||
[dependencies.parking_lot]
|
||||
version = "0.11"
|
||||
|
@ -1,73 +0,0 @@
|
||||
use std::fmt;
|
||||
use std::iter::FusedIterator;
|
||||
|
||||
/// Iterator which may contain instance of
|
||||
/// one of two specific implementations.
|
||||
///
|
||||
/// Note: For most methods providing custom
|
||||
/// implementation may marginally
|
||||
/// improve performance by avoiding
|
||||
/// doing Left/Right match on every step
|
||||
/// and doing it only once instead.
|
||||
#[derive(Clone)]
|
||||
pub enum EitherIter<L, R> {
|
||||
Left(L),
|
||||
Right(R),
|
||||
}
|
||||
|
||||
impl<L, R> Iterator for EitherIter<L, R>
|
||||
where
|
||||
L: Iterator,
|
||||
R: Iterator<Item = L::Item>,
|
||||
{
|
||||
type Item = L::Item;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self {
|
||||
EitherIter::Left(l) => l.next(),
|
||||
EitherIter::Right(r) => r.next(),
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
match self {
|
||||
EitherIter::Left(l) => l.size_hint(),
|
||||
EitherIter::Right(r) => r.size_hint(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<L, R> ExactSizeIterator for EitherIter<L, R>
|
||||
where
|
||||
L: ExactSizeIterator,
|
||||
R: ExactSizeIterator,
|
||||
EitherIter<L, R>: Iterator,
|
||||
{
|
||||
fn len(&self) -> usize {
|
||||
match self {
|
||||
EitherIter::Left(l) => l.len(),
|
||||
EitherIter::Right(r) => r.len(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<L, R> FusedIterator for EitherIter<L, R>
|
||||
where
|
||||
L: FusedIterator,
|
||||
R: FusedIterator,
|
||||
EitherIter<L, R>: Iterator,
|
||||
{
|
||||
}
|
||||
|
||||
impl<L, R> fmt::Debug for EitherIter<L, R>
|
||||
where
|
||||
L: fmt::Debug,
|
||||
R: fmt::Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
EitherIter::Left(l) => l.fmt(f),
|
||||
EitherIter::Right(r) => r.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
@ -1,24 +1,24 @@
|
||||
use super::either_iter::EitherIter;
|
||||
use crate::fx::FxHashMap;
|
||||
use arrayvec::ArrayVec;
|
||||
use itertools::Either;
|
||||
use std::fmt;
|
||||
use std::hash::Hash;
|
||||
use std::ops::Index;
|
||||
|
||||
// For pointer-sized arguments arrays
|
||||
// are faster than set/map for up to 64
|
||||
// arguments.
|
||||
//
|
||||
// On the other hand such a big array
|
||||
// hurts cache performance, makes passing
|
||||
// sso structures around very expensive.
|
||||
//
|
||||
// Biggest performance benefit is gained
|
||||
// for reasonably small arrays that stay
|
||||
// small in vast majority of cases.
|
||||
//
|
||||
// '8' is chosen as a sane default, to be
|
||||
// reevaluated later.
|
||||
/// For pointer-sized arguments arrays
|
||||
/// are faster than set/map for up to 64
|
||||
/// arguments.
|
||||
///
|
||||
/// On the other hand such a big array
|
||||
/// hurts cache performance, makes passing
|
||||
/// sso structures around very expensive.
|
||||
///
|
||||
/// Biggest performance benefit is gained
|
||||
/// for reasonably small arrays that stay
|
||||
/// small in vast majority of cases.
|
||||
///
|
||||
/// '8' is chosen as a sane default, to be
|
||||
/// reevaluated later.
|
||||
const SSO_ARRAY_SIZE: usize = 8;
|
||||
|
||||
/// Small-storage-optimized implementation of a map.
|
||||
@ -138,8 +138,8 @@ impl<K, V> SsoHashMap<K, V> {
|
||||
/// The iterator element type is `&'a K`.
|
||||
pub fn keys(&self) -> impl Iterator<Item = &'_ K> {
|
||||
match self {
|
||||
SsoHashMap::Array(array) => EitherIter::Left(array.iter().map(|(k, _v)| k)),
|
||||
SsoHashMap::Map(map) => EitherIter::Right(map.keys()),
|
||||
SsoHashMap::Array(array) => Either::Left(array.iter().map(|(k, _v)| k)),
|
||||
SsoHashMap::Map(map) => Either::Right(map.keys()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -147,8 +147,8 @@ impl<K, V> SsoHashMap<K, V> {
|
||||
/// The iterator element type is `&'a V`.
|
||||
pub fn values(&self) -> impl Iterator<Item = &'_ V> {
|
||||
match self {
|
||||
SsoHashMap::Array(array) => EitherIter::Left(array.iter().map(|(_k, v)| v)),
|
||||
SsoHashMap::Map(map) => EitherIter::Right(map.values()),
|
||||
SsoHashMap::Array(array) => Either::Left(array.iter().map(|(_k, v)| v)),
|
||||
SsoHashMap::Map(map) => Either::Right(map.values()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,8 +156,8 @@ impl<K, V> SsoHashMap<K, V> {
|
||||
/// The iterator element type is `&'a mut V`.
|
||||
pub fn values_mut(&mut self) -> impl Iterator<Item = &'_ mut V> {
|
||||
match self {
|
||||
SsoHashMap::Array(array) => EitherIter::Left(array.iter_mut().map(|(_k, v)| v)),
|
||||
SsoHashMap::Map(map) => EitherIter::Right(map.values_mut()),
|
||||
SsoHashMap::Array(array) => Either::Left(array.iter_mut().map(|(_k, v)| v)),
|
||||
SsoHashMap::Map(map) => Either::Right(map.values_mut()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -165,8 +165,8 @@ impl<K, V> SsoHashMap<K, V> {
|
||||
/// allocated memory for reuse.
|
||||
pub fn drain(&mut self) -> impl Iterator<Item = (K, V)> + '_ {
|
||||
match self {
|
||||
SsoHashMap::Array(array) => EitherIter::Left(array.drain(..)),
|
||||
SsoHashMap::Map(map) => EitherIter::Right(map.drain()),
|
||||
SsoHashMap::Array(array) => Either::Left(array.drain(..)),
|
||||
SsoHashMap::Map(map) => Either::Right(map.drain()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -406,16 +406,16 @@ where
|
||||
}
|
||||
|
||||
impl<K, V> IntoIterator for SsoHashMap<K, V> {
|
||||
type IntoIter = EitherIter<
|
||||
<ArrayVec<(K, V), 8> as IntoIterator>::IntoIter,
|
||||
type IntoIter = Either<
|
||||
<ArrayVec<(K, V), SSO_ARRAY_SIZE> as IntoIterator>::IntoIter,
|
||||
<FxHashMap<K, V> as IntoIterator>::IntoIter,
|
||||
>;
|
||||
type Item = <Self::IntoIter as Iterator>::Item;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
match self {
|
||||
SsoHashMap::Array(array) => EitherIter::Left(array.into_iter()),
|
||||
SsoHashMap::Map(map) => EitherIter::Right(map.into_iter()),
|
||||
SsoHashMap::Array(array) => Either::Left(array.into_iter()),
|
||||
SsoHashMap::Map(map) => Either::Right(map.into_iter()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -435,9 +435,9 @@ fn adapt_array_mut_it<K, V>(pair: &mut (K, V)) -> (&K, &mut V) {
|
||||
}
|
||||
|
||||
impl<'a, K, V> IntoIterator for &'a SsoHashMap<K, V> {
|
||||
type IntoIter = EitherIter<
|
||||
type IntoIter = Either<
|
||||
std::iter::Map<
|
||||
<&'a ArrayVec<(K, V), 8> as IntoIterator>::IntoIter,
|
||||
<&'a ArrayVec<(K, V), SSO_ARRAY_SIZE> as IntoIterator>::IntoIter,
|
||||
fn(&'a (K, V)) -> (&'a K, &'a V),
|
||||
>,
|
||||
<&'a FxHashMap<K, V> as IntoIterator>::IntoIter,
|
||||
@ -446,16 +446,16 @@ impl<'a, K, V> IntoIterator for &'a SsoHashMap<K, V> {
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
match self {
|
||||
SsoHashMap::Array(array) => EitherIter::Left(array.into_iter().map(adapt_array_ref_it)),
|
||||
SsoHashMap::Map(map) => EitherIter::Right(map.iter()),
|
||||
SsoHashMap::Array(array) => Either::Left(array.into_iter().map(adapt_array_ref_it)),
|
||||
SsoHashMap::Map(map) => Either::Right(map.iter()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> IntoIterator for &'a mut SsoHashMap<K, V> {
|
||||
type IntoIter = EitherIter<
|
||||
type IntoIter = Either<
|
||||
std::iter::Map<
|
||||
<&'a mut ArrayVec<(K, V), 8> as IntoIterator>::IntoIter,
|
||||
<&'a mut ArrayVec<(K, V), SSO_ARRAY_SIZE> as IntoIterator>::IntoIter,
|
||||
fn(&'a mut (K, V)) -> (&'a K, &'a mut V),
|
||||
>,
|
||||
<&'a mut FxHashMap<K, V> as IntoIterator>::IntoIter,
|
||||
@ -464,8 +464,8 @@ impl<'a, K, V> IntoIterator for &'a mut SsoHashMap<K, V> {
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
match self {
|
||||
SsoHashMap::Array(array) => EitherIter::Left(array.into_iter().map(adapt_array_mut_it)),
|
||||
SsoHashMap::Map(map) => EitherIter::Right(map.iter_mut()),
|
||||
SsoHashMap::Array(array) => Either::Left(array.into_iter().map(adapt_array_mut_it)),
|
||||
SsoHashMap::Map(map) => Either::Right(map.iter_mut()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
mod either_iter;
|
||||
mod map;
|
||||
mod set;
|
||||
|
||||
|
@ -5,7 +5,6 @@
|
||||
//! This API is completely unstable and subject to change.
|
||||
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
#![feature(is_terminal)]
|
||||
#![feature(lazy_cell)]
|
||||
#![feature(decl_macro)]
|
||||
#![recursion_limit = "256"]
|
||||
@ -37,7 +36,7 @@ use rustc_metadata::locator;
|
||||
use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS};
|
||||
use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest, TrimmedDefPaths};
|
||||
use rustc_session::cstore::MetadataLoader;
|
||||
use rustc_session::getopts;
|
||||
use rustc_session::getopts::{self, Matches};
|
||||
use rustc_session::lint::{Lint, LintId};
|
||||
use rustc_session::{config, Session};
|
||||
use rustc_session::{early_error, early_error_no_abort, early_warn};
|
||||
@ -956,6 +955,46 @@ Available lint options:
|
||||
}
|
||||
}
|
||||
|
||||
/// Show help for flag categories shared between rustdoc and rustc.
|
||||
///
|
||||
/// Returns whether a help option was printed.
|
||||
pub fn describe_flag_categories(matches: &Matches) -> bool {
|
||||
// Handle the special case of -Wall.
|
||||
let wall = matches.opt_strs("W");
|
||||
if wall.iter().any(|x| *x == "all") {
|
||||
print_wall_help();
|
||||
rustc_errors::FatalError.raise();
|
||||
}
|
||||
|
||||
// Don't handle -W help here, because we might first load plugins.
|
||||
let debug_flags = matches.opt_strs("Z");
|
||||
if debug_flags.iter().any(|x| *x == "help") {
|
||||
describe_debug_flags();
|
||||
return true;
|
||||
}
|
||||
|
||||
let cg_flags = matches.opt_strs("C");
|
||||
if cg_flags.iter().any(|x| *x == "help") {
|
||||
describe_codegen_flags();
|
||||
return true;
|
||||
}
|
||||
|
||||
if cg_flags.iter().any(|x| *x == "no-stack-check") {
|
||||
early_warn(
|
||||
ErrorOutputType::default(),
|
||||
"the --no-stack-check flag is deprecated and does nothing",
|
||||
);
|
||||
}
|
||||
|
||||
if cg_flags.iter().any(|x| *x == "passes=list") {
|
||||
let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
|
||||
get_codegen_backend(&None, backend_name).print_passes();
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn describe_debug_flags() {
|
||||
println!("\nAvailable options:\n");
|
||||
print_flag_list("-Z", config::Z_OPTIONS);
|
||||
@ -966,7 +1005,7 @@ fn describe_codegen_flags() {
|
||||
print_flag_list("-C", config::CG_OPTIONS);
|
||||
}
|
||||
|
||||
pub fn print_flag_list<T>(
|
||||
fn print_flag_list<T>(
|
||||
cmdline_opt: &str,
|
||||
flag_list: &[(&'static str, T, &'static str, &'static str)],
|
||||
) {
|
||||
@ -1059,37 +1098,7 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Handle the special case of -Wall.
|
||||
let wall = matches.opt_strs("W");
|
||||
if wall.iter().any(|x| *x == "all") {
|
||||
print_wall_help();
|
||||
rustc_errors::FatalError.raise();
|
||||
}
|
||||
|
||||
// Don't handle -W help here, because we might first load plugins.
|
||||
let debug_flags = matches.opt_strs("Z");
|
||||
if debug_flags.iter().any(|x| *x == "help") {
|
||||
describe_debug_flags();
|
||||
return None;
|
||||
}
|
||||
|
||||
let cg_flags = matches.opt_strs("C");
|
||||
|
||||
if cg_flags.iter().any(|x| *x == "help") {
|
||||
describe_codegen_flags();
|
||||
return None;
|
||||
}
|
||||
|
||||
if cg_flags.iter().any(|x| *x == "no-stack-check") {
|
||||
early_warn(
|
||||
ErrorOutputType::default(),
|
||||
"the --no-stack-check flag is deprecated and does nothing",
|
||||
);
|
||||
}
|
||||
|
||||
if cg_flags.iter().any(|x| *x == "passes=list") {
|
||||
let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
|
||||
get_codegen_backend(&None, backend_name).print_passes();
|
||||
if describe_flag_categories(&matches) {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
A visibility qualifier was used when it was unnecessary.
|
||||
A visibility qualifier was used where one is not permitted. Visibility
|
||||
qualifiers are not permitted on enum variants, trait items, impl blocks, and
|
||||
extern blocks, as they already share the visibility of the parent item.
|
||||
|
||||
Erroneous code examples:
|
||||
|
||||
@ -9,15 +11,18 @@ trait Foo {
|
||||
fn foo();
|
||||
}
|
||||
|
||||
pub impl Bar {} // error: unnecessary visibility qualifier
|
||||
enum Baz {
|
||||
pub Qux, // error: visibility qualifiers are not permitted here
|
||||
}
|
||||
|
||||
pub impl Foo for Bar { // error: unnecessary visibility qualifier
|
||||
pub fn foo() {} // error: unnecessary visibility qualifier
|
||||
pub impl Bar {} // error: visibility qualifiers are not permitted here
|
||||
|
||||
pub impl Foo for Bar { // error: visibility qualifiers are not permitted here
|
||||
pub fn foo() {} // error: visibility qualifiers are not permitted here
|
||||
}
|
||||
```
|
||||
|
||||
To fix this error, please remove the visibility qualifier when it is not
|
||||
required. Example:
|
||||
To fix this error, simply remove the visibility qualifier. Example:
|
||||
|
||||
```
|
||||
struct Bar;
|
||||
@ -26,12 +31,18 @@ trait Foo {
|
||||
fn foo();
|
||||
}
|
||||
|
||||
enum Baz {
|
||||
// Enum variants share the visibility of the enum they are in, so
|
||||
// `pub` is not allowed here
|
||||
Qux,
|
||||
}
|
||||
|
||||
// Directly implemented methods share the visibility of the type itself,
|
||||
// so `pub` is unnecessary here
|
||||
// so `pub` is not allowed here
|
||||
impl Bar {}
|
||||
|
||||
// Trait methods share the visibility of the trait, so `pub` is
|
||||
// unnecessary in either case
|
||||
// Trait methods share the visibility of the trait, so `pub` is not
|
||||
// allowed in either case
|
||||
impl Foo for Bar {
|
||||
fn foo() {}
|
||||
}
|
||||
|
@ -880,6 +880,7 @@ impl Diagnostic {
|
||||
///
|
||||
/// This is intended to be used for suggestions that are *very* obvious in what the changes
|
||||
/// need to be from the message, but we still want other tools to be able to apply them.
|
||||
#[rustc_lint_diagnostics]
|
||||
pub fn tool_only_span_suggestion(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::fluent_generated as fluent;
|
||||
use crate::{fluent_generated as fluent, AddToDiagnostic};
|
||||
use crate::{DiagnosticArgValue, DiagnosticBuilder, Handler, IntoDiagnostic, IntoDiagnosticArg};
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast_pretty::pprust;
|
||||
@ -6,6 +6,7 @@ use rustc_hir as hir;
|
||||
use rustc_lint_defs::Level;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol};
|
||||
use rustc_span::Span;
|
||||
use rustc_target::abi::TargetDataLayoutErrors;
|
||||
use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple};
|
||||
use rustc_type_ir as type_ir;
|
||||
@ -276,3 +277,26 @@ impl IntoDiagnostic<'_, !> for TargetDataLayoutErrors<'_> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Utility struct used to apply a single label while highlighting multiple spans
|
||||
pub struct SingleLabelManySpans {
|
||||
pub spans: Vec<Span>,
|
||||
pub label: &'static str,
|
||||
pub kind: LabelKind,
|
||||
}
|
||||
impl AddToDiagnostic for SingleLabelManySpans {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut crate::Diagnostic, _: F) {
|
||||
match self.kind {
|
||||
LabelKind::Note => diag.span_note(self.spans, self.label),
|
||||
LabelKind::Label => diag.span_labels(self.spans, self.label),
|
||||
LabelKind::Help => diag.span_help(self.spans, self.label),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// The kind of label to attach when using [`SingleLabelManySpans`]
|
||||
pub enum LabelKind {
|
||||
Note,
|
||||
Label,
|
||||
Help,
|
||||
}
|
||||
|
@ -1832,6 +1832,12 @@ impl EmitterWriter {
|
||||
}
|
||||
let show_code_change = if has_deletion && !is_multiline {
|
||||
DisplaySuggestion::Diff
|
||||
} else if let [part] = &parts[..]
|
||||
&& part.snippet.ends_with('\n')
|
||||
&& part.snippet.trim() == complete.trim()
|
||||
{
|
||||
// We are adding a line(s) of code before code that was already there.
|
||||
DisplaySuggestion::Add
|
||||
} else if (parts.len() != 1 || parts[0].snippet.trim() != complete.trim())
|
||||
&& !is_multiline
|
||||
{
|
||||
@ -1879,7 +1885,10 @@ impl EmitterWriter {
|
||||
row_num += line_end - line_start;
|
||||
}
|
||||
let mut unhighlighted_lines = Vec::new();
|
||||
let mut last_pos = 0;
|
||||
let mut is_item_attribute = false;
|
||||
for (line_pos, (line, highlight_parts)) in lines.by_ref().zip(highlights).enumerate() {
|
||||
last_pos = line_pos;
|
||||
debug!(%line_pos, %line, ?highlight_parts);
|
||||
|
||||
// Remember lines that are not highlighted to hide them if needed
|
||||
@ -1887,6 +1896,12 @@ impl EmitterWriter {
|
||||
unhighlighted_lines.push((line_pos, line));
|
||||
continue;
|
||||
}
|
||||
if highlight_parts.len() == 1
|
||||
&& line.trim().starts_with("#[")
|
||||
&& line.trim().ends_with(']')
|
||||
{
|
||||
is_item_attribute = true;
|
||||
}
|
||||
|
||||
match unhighlighted_lines.len() {
|
||||
0 => (),
|
||||
@ -1963,13 +1978,41 @@ impl EmitterWriter {
|
||||
is_multiline,
|
||||
)
|
||||
}
|
||||
if let DisplaySuggestion::Add = show_code_change && is_item_attribute {
|
||||
// The suggestion adds an entire line of code, ending on a newline, so we'll also
|
||||
// print the *following* line, to provide context of what we're advicing people to
|
||||
// do. Otherwise you would only see contextless code that can be confused for
|
||||
// already existing code, despite the colors and UI elements.
|
||||
// We special case `#[derive(_)]\n` and other attribute suggestions, because those
|
||||
// are the ones where context is most useful.
|
||||
let file_lines = sm
|
||||
.span_to_lines(span.primary_span().unwrap().shrink_to_hi())
|
||||
.expect("span_to_lines failed when emitting suggestion");
|
||||
let line_num = sm.lookup_char_pos(parts[0].span.lo()).line;
|
||||
if let Some(line) = file_lines.file.get_line(line_num - 1) {
|
||||
let line = normalize_whitespace(&line);
|
||||
self.draw_code_line(
|
||||
&mut buffer,
|
||||
&mut row_num,
|
||||
&[],
|
||||
line_num + last_pos + 1,
|
||||
&line,
|
||||
DisplaySuggestion::None,
|
||||
max_line_num_len,
|
||||
&file_lines,
|
||||
is_multiline,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// This offset and the ones below need to be signed to account for replacement code
|
||||
// that is shorter than the original code.
|
||||
let mut offsets: Vec<(usize, isize)> = Vec::new();
|
||||
// Only show an underline in the suggestions if the suggestion is not the
|
||||
// entirety of the code being shown and the displayed code is not multiline.
|
||||
if let DisplaySuggestion::Diff | DisplaySuggestion::Underline = show_code_change {
|
||||
if let DisplaySuggestion::Diff | DisplaySuggestion::Underline | DisplaySuggestion::Add =
|
||||
show_code_change
|
||||
{
|
||||
draw_col_separator_no_space(&mut buffer, row_num, max_line_num_len + 1);
|
||||
for part in parts {
|
||||
let span_start_pos = sm.lookup_char_pos(part.span.lo()).col_display;
|
||||
@ -2247,6 +2290,10 @@ impl EmitterWriter {
|
||||
}
|
||||
}
|
||||
buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle);
|
||||
} else if let DisplaySuggestion::Add = show_code_change {
|
||||
buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber);
|
||||
buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition);
|
||||
buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle);
|
||||
} else {
|
||||
buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber);
|
||||
draw_col_separator(buffer, *row_num, max_line_num_len + 1);
|
||||
@ -2281,6 +2328,7 @@ enum DisplaySuggestion {
|
||||
Underline,
|
||||
Diff,
|
||||
None,
|
||||
Add,
|
||||
}
|
||||
|
||||
impl FileWithAnnotatedLines {
|
||||
|
@ -6,7 +6,6 @@
|
||||
#![feature(array_windows)]
|
||||
#![feature(drain_filter)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(is_terminal)]
|
||||
#![feature(adt_const_params)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(never_type)]
|
||||
@ -383,7 +382,9 @@ pub use diagnostic::{
|
||||
DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
|
||||
};
|
||||
pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, Noted};
|
||||
pub use diagnostic_impls::{DiagnosticArgFromDisplay, DiagnosticSymbolList};
|
||||
pub use diagnostic_impls::{
|
||||
DiagnosticArgFromDisplay, DiagnosticSymbolList, LabelKind, SingleLabelManySpans,
|
||||
};
|
||||
use std::backtrace::Backtrace;
|
||||
|
||||
/// A handler deals with errors and other compiler output.
|
||||
@ -473,8 +474,6 @@ pub enum StashKey {
|
||||
/// When an invalid lifetime e.g. `'2` should be reinterpreted
|
||||
/// as a char literal in the parser
|
||||
LifetimeIsChar,
|
||||
/// When an invalid lifetime e.g. `'🐱` contains emoji.
|
||||
LifetimeContainsEmoji,
|
||||
/// Maybe there was a typo where a comma was forgotten before
|
||||
/// FRU syntax
|
||||
MaybeFruTypo,
|
||||
|
@ -135,4 +135,4 @@ expand_proc_macro_panicked =
|
||||
.help = message: {$message}
|
||||
|
||||
expand_proc_macro_derive_tokens =
|
||||
proc-macro derive produced unparseable tokens
|
||||
proc-macro derive produced unparsable tokens
|
||||
|
@ -66,7 +66,12 @@ pub(super) fn failed_to_match_macro<'cx>(
|
||||
&& (matches!(expected_token.kind, TokenKind::Interpolated(_))
|
||||
|| matches!(token.kind, TokenKind::Interpolated(_)))
|
||||
{
|
||||
err.note("captured metavariables except for `$tt`, `$ident` and `$lifetime` cannot be compared to other tokens");
|
||||
err.note("captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens");
|
||||
err.note("see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information");
|
||||
|
||||
if !def_span.is_dummy() && !cx.source_map().is_imported(def_span) {
|
||||
err.help("try using `:tt` instead in the macro definition");
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether there's a missing comma in this macro call, like `println!("{}" a);`
|
||||
|
@ -309,7 +309,7 @@ declare_features! (
|
||||
(active, associated_type_defaults, "1.2.0", Some(29661), None),
|
||||
/// Allows `async || body` closures.
|
||||
(active, async_closure, "1.37.0", Some(62290), None),
|
||||
/// Alows async functions to be declared, implemented, and used in traits.
|
||||
/// Allows async functions to be declared, implemented, and used in traits.
|
||||
(incomplete, async_fn_in_trait, "1.66.0", Some(91611), None),
|
||||
/// Allows `extern "C-unwind" fn` to enable unwinding across ABI boundaries.
|
||||
(active, c_unwind, "1.52.0", Some(74990), None),
|
||||
@ -416,6 +416,8 @@ declare_features! (
|
||||
(active, half_open_range_patterns_in_slices, "1.66.0", Some(67264), None),
|
||||
/// Allows `if let` guard in match arms.
|
||||
(active, if_let_guard, "1.47.0", Some(51114), None),
|
||||
/// Allows `impl Trait` to be used inside associated types (RFC 2515).
|
||||
(active, impl_trait_in_assoc_type, "CURRENT_RUSTC_VERSION", Some(63063), None),
|
||||
/// Allows `impl Trait` as output type in `Fn` traits in return position of functions.
|
||||
(active, impl_trait_in_fn_trait_return, "1.64.0", Some(99697), None),
|
||||
/// Allows referencing `Self` and projections in impl-trait.
|
||||
|
@ -1663,39 +1663,45 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
})
|
||||
});
|
||||
|
||||
let existential_projections = projection_bounds.iter().map(|(bound, _)| {
|
||||
bound.map_bound(|mut b| {
|
||||
assert_eq!(b.projection_ty.self_ty(), dummy_self);
|
||||
let existential_projections = projection_bounds
|
||||
.iter()
|
||||
// We filter out traits that don't have `Self` as their self type above,
|
||||
// we need to do the same for projections.
|
||||
.filter(|(bound, _)| bound.skip_binder().self_ty() == dummy_self)
|
||||
.map(|(bound, _)| {
|
||||
bound.map_bound(|mut b| {
|
||||
assert_eq!(b.projection_ty.self_ty(), dummy_self);
|
||||
|
||||
// Like for trait refs, verify that `dummy_self` did not leak inside default type
|
||||
// parameters.
|
||||
let references_self = b.projection_ty.substs.iter().skip(1).any(|arg| {
|
||||
if arg.walk().any(|arg| arg == dummy_self.into()) {
|
||||
return true;
|
||||
// Like for trait refs, verify that `dummy_self` did not leak inside default type
|
||||
// parameters.
|
||||
let references_self = b.projection_ty.substs.iter().skip(1).any(|arg| {
|
||||
if arg.walk().any(|arg| arg == dummy_self.into()) {
|
||||
return true;
|
||||
}
|
||||
false
|
||||
});
|
||||
if references_self {
|
||||
let guar = tcx.sess.delay_span_bug(
|
||||
span,
|
||||
"trait object projection bounds reference `Self`",
|
||||
);
|
||||
let substs: Vec<_> = b
|
||||
.projection_ty
|
||||
.substs
|
||||
.iter()
|
||||
.map(|arg| {
|
||||
if arg.walk().any(|arg| arg == dummy_self.into()) {
|
||||
return tcx.ty_error(guar).into();
|
||||
}
|
||||
arg
|
||||
})
|
||||
.collect();
|
||||
b.projection_ty.substs = tcx.mk_substs(&substs);
|
||||
}
|
||||
false
|
||||
});
|
||||
if references_self {
|
||||
let guar = tcx
|
||||
.sess
|
||||
.delay_span_bug(span, "trait object projection bounds reference `Self`");
|
||||
let substs: Vec<_> = b
|
||||
.projection_ty
|
||||
.substs
|
||||
.iter()
|
||||
.map(|arg| {
|
||||
if arg.walk().any(|arg| arg == dummy_self.into()) {
|
||||
return tcx.ty_error(guar).into();
|
||||
}
|
||||
arg
|
||||
})
|
||||
.collect();
|
||||
b.projection_ty.substs = tcx.mk_substs(&substs);
|
||||
}
|
||||
|
||||
ty::ExistentialProjection::erase_self_ty(tcx, b)
|
||||
})
|
||||
});
|
||||
ty::ExistentialProjection::erase_self_ty(tcx, b)
|
||||
})
|
||||
});
|
||||
|
||||
let regular_trait_predicates = existential_trait_refs
|
||||
.map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait));
|
||||
@ -2514,24 +2520,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
tcx,
|
||||
infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id),
|
||||
);
|
||||
// I guess we don't need to make a universe unless we need it,
|
||||
// but also we're on the error path, so it doesn't matter here.
|
||||
let universe = infcx.create_next_universe();
|
||||
let value = tcx.fold_regions(qself_ty, |_, _| tcx.lifetimes.re_erased);
|
||||
// FIXME: Don't bother dealing with non-lifetime binders here...
|
||||
if value.has_escaping_bound_vars() {
|
||||
return false;
|
||||
}
|
||||
infcx
|
||||
.can_eq(
|
||||
ty::ParamEnv::empty(),
|
||||
impl_.self_ty(),
|
||||
tcx.replace_escaping_bound_vars_uncached(qself_ty, ty::fold::FnMutDelegate {
|
||||
regions: &mut |_| tcx.lifetimes.re_erased,
|
||||
types: &mut |bv| tcx.mk_placeholder(ty::PlaceholderType {
|
||||
universe,
|
||||
bound: bv,
|
||||
}),
|
||||
consts: &mut |bv, ty| tcx.mk_const(ty::PlaceholderConst {
|
||||
universe,
|
||||
bound: bv,
|
||||
}, ty),
|
||||
})
|
||||
value,
|
||||
)
|
||||
})
|
||||
&& tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
|
||||
@ -2580,7 +2578,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
tcx.all_impls(trait_def_id)
|
||||
.filter(|impl_def_id| {
|
||||
// Consider only accessible traits
|
||||
tcx.visibility(*impl_def_id).is_accessible_from(self.item_def_id(), tcx)
|
||||
tcx.visibility(trait_def_id).is_accessible_from(self.item_def_id(), tcx)
|
||||
&& tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
|
||||
})
|
||||
.filter_map(|impl_def_id| tcx.impl_trait_ref(impl_def_id))
|
||||
|
@ -58,7 +58,7 @@ impl<'tcx> Bounds<'tcx> {
|
||||
pub fn push_sized(&mut self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) {
|
||||
let sized_def_id = tcx.require_lang_item(LangItem::Sized, Some(span));
|
||||
let trait_ref = ty::Binder::dummy(tcx.mk_trait_ref(sized_def_id, [ty]));
|
||||
// Preferrable to put this obligation first, since we report better errors for sized ambiguity.
|
||||
// Preferable to put this obligation first, since we report better errors for sized ambiguity.
|
||||
self.predicates.insert(0, (trait_ref.without_const().to_predicate(tcx), span));
|
||||
}
|
||||
|
||||
|
@ -452,11 +452,8 @@ fn check_opaque_meets_bounds<'tcx>(
|
||||
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {}
|
||||
// Can have different predicates to their defining use
|
||||
hir::OpaqueTyOrigin::TyAlias => {
|
||||
let outlives_environment = OutlivesEnvironment::new(param_env);
|
||||
let _ = infcx.err_ctxt().check_region_obligations_and_report_errors(
|
||||
defining_use_anchor,
|
||||
&outlives_environment,
|
||||
);
|
||||
let outlives_env = OutlivesEnvironment::new(param_env);
|
||||
let _ = ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env);
|
||||
}
|
||||
}
|
||||
// Clean up after ourselves
|
||||
|
@ -332,10 +332,6 @@ fn compare_method_predicate_entailment<'tcx>(
|
||||
param_env,
|
||||
infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys.clone()),
|
||||
);
|
||||
infcx.process_registered_region_obligations(
|
||||
outlives_env.region_bound_pairs(),
|
||||
outlives_env.param_env,
|
||||
);
|
||||
let errors = infcx.resolve_regions(&outlives_env);
|
||||
if !errors.is_empty() {
|
||||
// FIXME(compiler-errors): This can be simplified when IMPLIED_BOUNDS_ENTAILMENT
|
||||
@ -722,18 +718,18 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
|
||||
return Err(reported);
|
||||
}
|
||||
|
||||
let collected_types = collector.types;
|
||||
|
||||
// Finally, resolve all regions. This catches wily misuses of
|
||||
// lifetime parameters.
|
||||
let outlives_environment = OutlivesEnvironment::with_bounds(
|
||||
let outlives_env = OutlivesEnvironment::with_bounds(
|
||||
param_env,
|
||||
infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys),
|
||||
);
|
||||
infcx
|
||||
.err_ctxt()
|
||||
.check_region_obligations_and_report_errors(impl_m_def_id, &outlives_environment)?;
|
||||
ocx.resolve_regions_and_report_errors(impl_m_def_id, &outlives_env)?;
|
||||
|
||||
let mut collected_tys = FxHashMap::default();
|
||||
for (def_id, (ty, substs)) in collector.types {
|
||||
for (def_id, (ty, substs)) in collected_types {
|
||||
match infcx.fully_resolve(ty) {
|
||||
Ok(ty) => {
|
||||
// `ty` contains free regions that we created earlier while liberating the
|
||||
@ -1742,11 +1738,8 @@ pub(super) fn compare_impl_const_raw(
|
||||
return Err(infcx.err_ctxt().report_fulfillment_errors(&errors));
|
||||
}
|
||||
|
||||
let outlives_environment = OutlivesEnvironment::new(param_env);
|
||||
infcx
|
||||
.err_ctxt()
|
||||
.check_region_obligations_and_report_errors(impl_const_item_def, &outlives_environment)?;
|
||||
Ok(())
|
||||
let outlives_env = OutlivesEnvironment::new(param_env);
|
||||
ocx.resolve_regions_and_report_errors(impl_const_item_def, &outlives_env)
|
||||
}
|
||||
|
||||
pub(super) fn compare_impl_ty<'tcx>(
|
||||
@ -1845,13 +1838,8 @@ fn compare_type_predicate_entailment<'tcx>(
|
||||
|
||||
// Finally, resolve all regions. This catches wily misuses of
|
||||
// lifetime parameters.
|
||||
let outlives_environment = OutlivesEnvironment::new(param_env);
|
||||
infcx.err_ctxt().check_region_obligations_and_report_errors(
|
||||
impl_ty.def_id.expect_local(),
|
||||
&outlives_environment,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
let outlives_env = OutlivesEnvironment::new(param_env);
|
||||
ocx.resolve_regions_and_report_errors(impl_ty_def_id, &outlives_env)
|
||||
}
|
||||
|
||||
/// Validate that `ProjectionCandidate`s created for this associated type will
|
||||
@ -2063,14 +2051,8 @@ pub(super) fn check_type_bounds<'tcx>(
|
||||
// Finally, resolve all regions. This catches wily misuses of
|
||||
// lifetime parameters.
|
||||
let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_def_id, assumed_wf_types);
|
||||
let outlives_environment = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
|
||||
|
||||
infcx.err_ctxt().check_region_obligations_and_report_errors(
|
||||
impl_ty.def_id.expect_local(),
|
||||
&outlives_environment,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
|
||||
ocx.resolve_regions_and_report_errors(impl_ty_def_id, &outlives_env)
|
||||
}
|
||||
|
||||
fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str {
|
||||
|
@ -114,11 +114,9 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
|
||||
return;
|
||||
}
|
||||
|
||||
let outlives_environment = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
|
||||
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
|
||||
|
||||
let _ = infcx
|
||||
.err_ctxt()
|
||||
.check_region_obligations_and_report_errors(body_def_id, &outlives_environment);
|
||||
let _ = wfcx.ocx.resolve_regions_and_report_errors(body_def_id, &outlives_env);
|
||||
}
|
||||
|
||||
fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) {
|
||||
@ -680,12 +678,7 @@ fn resolve_regions_with_wf_tys<'tcx>(
|
||||
|
||||
add_constraints(&infcx, region_bound_pairs);
|
||||
|
||||
infcx.process_registered_region_obligations(
|
||||
outlives_environment.region_bound_pairs(),
|
||||
param_env,
|
||||
);
|
||||
let errors = infcx.resolve_regions(&outlives_environment);
|
||||
|
||||
debug!(?errors, "errors");
|
||||
|
||||
// If we were able to prove that the type outlives the region without
|
||||
|
@ -354,9 +354,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
|
||||
|
||||
// Finally, resolve all regions.
|
||||
let outlives_env = OutlivesEnvironment::new(param_env);
|
||||
let _ = infcx
|
||||
.err_ctxt()
|
||||
.check_region_obligations_and_report_errors(impl_did, &outlives_env);
|
||||
let _ = ocx.resolve_regions_and_report_errors(impl_did, &outlives_env);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
@ -592,7 +590,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
|
||||
|
||||
// Finally, resolve all regions.
|
||||
let outlives_env = OutlivesEnvironment::new(param_env);
|
||||
let _ = infcx.err_ctxt().check_region_obligations_and_report_errors(impl_did, &outlives_env);
|
||||
let _ = ocx.resolve_regions_and_report_errors(impl_did, &outlives_env);
|
||||
|
||||
CoerceUnsizedInfo { custom_kind: kind }
|
||||
}
|
||||
|
@ -64,6 +64,7 @@ pub fn provide(providers: &mut Providers) {
|
||||
predicates_defined_on,
|
||||
explicit_predicates_of: predicates_of::explicit_predicates_of,
|
||||
super_predicates_of: predicates_of::super_predicates_of,
|
||||
implied_predicates_of: predicates_of::implied_predicates_of,
|
||||
super_predicates_that_define_assoc_type:
|
||||
predicates_of::super_predicates_that_define_assoc_type,
|
||||
trait_explicit_predicates_and_bounds: predicates_of::trait_explicit_predicates_and_bounds,
|
||||
@ -596,6 +597,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
|
||||
}
|
||||
hir::ItemKind::TraitAlias(..) => {
|
||||
tcx.ensure().generics_of(def_id);
|
||||
tcx.at(it.span).implied_predicates_of(def_id);
|
||||
tcx.at(it.span).super_predicates_of(def_id);
|
||||
tcx.ensure().predicates_of(def_id);
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
||||
// on a trait we need to add in the supertrait bounds and bounds found on
|
||||
// associated types.
|
||||
if let Some(_trait_ref) = is_trait {
|
||||
predicates.extend(tcx.super_predicates_of(def_id).predicates.iter().cloned());
|
||||
predicates.extend(tcx.implied_predicates_of(def_id).predicates.iter().cloned());
|
||||
}
|
||||
|
||||
// In default impls, we can assume that the self type implements
|
||||
@ -534,6 +534,19 @@ pub(super) fn explicit_predicates_of<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum PredicateFilter {
|
||||
/// All predicates may be implied by the trait
|
||||
All,
|
||||
|
||||
/// Only traits that reference `Self: ..` are implied by the trait
|
||||
SelfOnly,
|
||||
|
||||
/// Only traits that reference `Self: ..` and define an associated type
|
||||
/// with the given ident are implied by the trait
|
||||
SelfThatDefines(Ident),
|
||||
}
|
||||
|
||||
/// Ensures that the super-predicates of the trait with a `DefId`
|
||||
/// of `trait_def_id` are converted and stored. This also ensures that
|
||||
/// the transitive super-predicates are converted.
|
||||
@ -541,24 +554,42 @@ pub(super) fn super_predicates_of(
|
||||
tcx: TyCtxt<'_>,
|
||||
trait_def_id: LocalDefId,
|
||||
) -> ty::GenericPredicates<'_> {
|
||||
tcx.super_predicates_that_define_assoc_type((trait_def_id.to_def_id(), None))
|
||||
implied_predicates_with_filter(tcx, trait_def_id.to_def_id(), PredicateFilter::SelfOnly)
|
||||
}
|
||||
|
||||
pub(super) fn super_predicates_that_define_assoc_type(
|
||||
tcx: TyCtxt<'_>,
|
||||
(trait_def_id, assoc_name): (DefId, Ident),
|
||||
) -> ty::GenericPredicates<'_> {
|
||||
implied_predicates_with_filter(tcx, trait_def_id, PredicateFilter::SelfThatDefines(assoc_name))
|
||||
}
|
||||
|
||||
pub(super) fn implied_predicates_of(
|
||||
tcx: TyCtxt<'_>,
|
||||
trait_def_id: LocalDefId,
|
||||
) -> ty::GenericPredicates<'_> {
|
||||
if tcx.is_trait_alias(trait_def_id.to_def_id()) {
|
||||
implied_predicates_with_filter(tcx, trait_def_id.to_def_id(), PredicateFilter::All)
|
||||
} else {
|
||||
tcx.super_predicates_of(trait_def_id)
|
||||
}
|
||||
}
|
||||
|
||||
/// Ensures that the super-predicates of the trait with a `DefId`
|
||||
/// of `trait_def_id` are converted and stored. This also ensures that
|
||||
/// the transitive super-predicates are converted.
|
||||
pub(super) fn super_predicates_that_define_assoc_type(
|
||||
pub(super) fn implied_predicates_with_filter(
|
||||
tcx: TyCtxt<'_>,
|
||||
(trait_def_id, assoc_name): (DefId, Option<Ident>),
|
||||
trait_def_id: DefId,
|
||||
filter: PredicateFilter,
|
||||
) -> ty::GenericPredicates<'_> {
|
||||
let Some(trait_def_id) = trait_def_id.as_local() else {
|
||||
// if `assoc_name` is None, then the query should've been redirected to an
|
||||
// external provider
|
||||
assert!(assoc_name.is_some());
|
||||
assert!(matches!(filter, PredicateFilter::SelfThatDefines(_)));
|
||||
return tcx.super_predicates_of(trait_def_id);
|
||||
};
|
||||
|
||||
debug!("local trait");
|
||||
let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id);
|
||||
|
||||
let Node::Item(item) = tcx.hir().get(trait_hir_id) else {
|
||||
@ -573,40 +604,58 @@ pub(super) fn super_predicates_that_define_assoc_type(
|
||||
|
||||
let icx = ItemCtxt::new(tcx, trait_def_id);
|
||||
|
||||
// Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`.
|
||||
let self_param_ty = tcx.types.self_param;
|
||||
let superbounds1 = if let Some(assoc_name) = assoc_name {
|
||||
icx.astconv().compute_bounds_that_match_assoc_type(self_param_ty, bounds, assoc_name)
|
||||
} else {
|
||||
icx.astconv().compute_bounds(self_param_ty, bounds)
|
||||
let (superbounds, where_bounds_that_match) = match filter {
|
||||
PredicateFilter::All => (
|
||||
// Convert the bounds that follow the colon (or equal in trait aliases)
|
||||
icx.astconv().compute_bounds(self_param_ty, bounds),
|
||||
// Also include all where clause bounds
|
||||
icx.type_parameter_bounds_in_generics(
|
||||
generics,
|
||||
item.owner_id.def_id,
|
||||
self_param_ty,
|
||||
OnlySelfBounds(false),
|
||||
None,
|
||||
),
|
||||
),
|
||||
PredicateFilter::SelfOnly => (
|
||||
// Convert the bounds that follow the colon (or equal in trait aliases)
|
||||
icx.astconv().compute_bounds(self_param_ty, bounds),
|
||||
// Include where clause bounds for `Self`
|
||||
icx.type_parameter_bounds_in_generics(
|
||||
generics,
|
||||
item.owner_id.def_id,
|
||||
self_param_ty,
|
||||
OnlySelfBounds(true),
|
||||
None,
|
||||
),
|
||||
),
|
||||
PredicateFilter::SelfThatDefines(assoc_name) => (
|
||||
// Convert the bounds that follow the colon (or equal) that reference the associated name
|
||||
icx.astconv().compute_bounds_that_match_assoc_type(self_param_ty, bounds, assoc_name),
|
||||
// Include where clause bounds for `Self` that reference the associated name
|
||||
icx.type_parameter_bounds_in_generics(
|
||||
generics,
|
||||
item.owner_id.def_id,
|
||||
self_param_ty,
|
||||
OnlySelfBounds(true),
|
||||
Some(assoc_name),
|
||||
),
|
||||
),
|
||||
};
|
||||
|
||||
let superbounds1 = superbounds1.predicates();
|
||||
|
||||
// Convert any explicit superbounds in the where-clause,
|
||||
// e.g., `trait Foo where Self: Bar`.
|
||||
// In the case of trait aliases, however, we include all bounds in the where-clause,
|
||||
// so e.g., `trait Foo = where u32: PartialEq<Self>` would include `u32: PartialEq<Self>`
|
||||
// as one of its "superpredicates".
|
||||
let is_trait_alias = tcx.is_trait_alias(trait_def_id.to_def_id());
|
||||
let superbounds2 = icx.type_parameter_bounds_in_generics(
|
||||
generics,
|
||||
item.owner_id.def_id,
|
||||
self_param_ty,
|
||||
OnlySelfBounds(!is_trait_alias),
|
||||
assoc_name,
|
||||
);
|
||||
|
||||
// Combine the two lists to form the complete set of superbounds:
|
||||
let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2));
|
||||
debug!(?superbounds);
|
||||
let implied_bounds = &*tcx
|
||||
.arena
|
||||
.alloc_from_iter(superbounds.predicates().into_iter().chain(where_bounds_that_match));
|
||||
debug!(?implied_bounds);
|
||||
|
||||
// Now require that immediate supertraits are converted,
|
||||
// which will, in turn, reach indirect supertraits.
|
||||
if assoc_name.is_none() {
|
||||
if matches!(filter, PredicateFilter::SelfOnly) {
|
||||
// Now require that immediate supertraits are converted,
|
||||
// which will, in turn, reach indirect supertraits.
|
||||
for &(pred, span) in superbounds {
|
||||
for &(pred, span) in implied_bounds {
|
||||
debug!("superbound: {:?}", pred);
|
||||
if let ty::PredicateKind::Clause(ty::Clause::Trait(bound)) = pred.kind().skip_binder() {
|
||||
tcx.at(span).super_predicates_of(bound.def_id());
|
||||
@ -614,7 +663,7 @@ pub(super) fn super_predicates_that_define_assoc_type(
|
||||
}
|
||||
}
|
||||
|
||||
ty::GenericPredicates { parent: None, predicates: superbounds }
|
||||
ty::GenericPredicates { parent: None, predicates: implied_bounds }
|
||||
}
|
||||
|
||||
/// Returns the predicates defined on `item_def_id` of the form
|
||||
|
@ -1749,8 +1749,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
||||
if trait_defines_associated_type_named(def_id) {
|
||||
break Some(bound_vars.into_iter().collect());
|
||||
}
|
||||
let predicates =
|
||||
tcx.super_predicates_that_define_assoc_type((def_id, Some(assoc_name)));
|
||||
let predicates = tcx.super_predicates_that_define_assoc_type((def_id, assoc_name));
|
||||
let obligations = predicates.predicates.iter().filter_map(|&(pred, _)| {
|
||||
let bound_predicate = pred.kind();
|
||||
match bound_predicate.skip_binder() {
|
||||
|
@ -8,10 +8,7 @@ use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::ty::print::with_forced_trimmed_paths;
|
||||
use rustc_middle::ty::subst::InternalSubsts;
|
||||
use rustc_middle::ty::util::IntTypeExt;
|
||||
use rustc_middle::ty::{
|
||||
self, ImplTraitInTraitData, IsSuggestable, Ty, TyCtxt, TypeFolder, TypeSuperFoldable,
|
||||
TypeVisitableExt,
|
||||
};
|
||||
use rustc_middle::ty::{self, ImplTraitInTraitData, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
@ -874,28 +871,6 @@ fn infer_placeholder_type<'a>(
|
||||
item_ident: Ident,
|
||||
kind: &'static str,
|
||||
) -> Ty<'a> {
|
||||
// Attempts to make the type nameable by turning FnDefs into FnPtrs.
|
||||
struct MakeNameable<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for MakeNameable<'tcx> {
|
||||
fn interner(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
let ty = match *ty.kind() {
|
||||
ty::FnDef(def_id, substs) => {
|
||||
self.tcx.mk_fn_ptr(self.tcx.fn_sig(def_id).subst(self.tcx, substs))
|
||||
}
|
||||
_ => ty,
|
||||
};
|
||||
|
||||
ty.super_fold_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
let ty = tcx.diagnostic_only_typeck(def_id).node_type(body_id.hir_id);
|
||||
|
||||
// If this came from a free `const` or `static mut?` item,
|
||||
|
@ -180,8 +180,7 @@ fn get_impl_substs(
|
||||
|
||||
let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_def_id, assumed_wf_types);
|
||||
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
|
||||
let _ =
|
||||
infcx.err_ctxt().check_region_obligations_and_report_errors(impl1_def_id, &outlives_env);
|
||||
let _ = ocx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env);
|
||||
let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {
|
||||
let span = tcx.def_span(impl1_def_id);
|
||||
tcx.sess.emit_err(SubstsOnOverriddenImpl { span });
|
||||
|
@ -210,7 +210,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// and we want to keep inference generally in the same order of
|
||||
// the registered obligations.
|
||||
predicates.rev(),
|
||||
) {
|
||||
)
|
||||
// We only care about self bounds
|
||||
.filter_only_self()
|
||||
{
|
||||
debug!(?pred);
|
||||
let bound_predicate = pred.kind();
|
||||
|
||||
|
@ -308,7 +308,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let rcvr_ty = self.node_ty(rcvr.hir_id);
|
||||
// Get the evaluated type *after* calling the method call, so that the influence
|
||||
// of the arguments can be reflected in the receiver type. The receiver
|
||||
// expression has the type *before* theis analysis is done.
|
||||
// expression has the type *before* this analysis is done.
|
||||
let ty = match self.lookup_probe_for_diagnostic(
|
||||
segment.ident,
|
||||
rcvr_ty,
|
||||
|
@ -120,7 +120,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
ty
|
||||
}
|
||||
|
||||
pub(super) fn check_expr_coercable_to_type(
|
||||
pub(super) fn check_expr_coercible_to_type(
|
||||
&self,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
expected: Ty<'tcx>,
|
||||
@ -1128,7 +1128,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
};
|
||||
|
||||
// This is (basically) inlined `check_expr_coercable_to_type`, but we want
|
||||
// This is (basically) inlined `check_expr_coercible_to_type`, but we want
|
||||
// to suggest an additional fixup here in `suggest_deref_binop`.
|
||||
let rhs_ty = self.check_expr_with_hint(&rhs, lhs_ty);
|
||||
if let (_, Some(mut diag)) =
|
||||
@ -1401,7 +1401,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
let (element_ty, t) = match uty {
|
||||
Some(uty) => {
|
||||
self.check_expr_coercable_to_type(&element, uty, None);
|
||||
self.check_expr_coercible_to_type(&element, uty, None);
|
||||
(uty, uty)
|
||||
}
|
||||
None => {
|
||||
@ -1478,7 +1478,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let elt_ts_iter = elts.iter().enumerate().map(|(i, e)| match flds {
|
||||
Some(fs) if i < fs.len() => {
|
||||
let ety = fs[i];
|
||||
self.check_expr_coercable_to_type(&e, ety, None);
|
||||
self.check_expr_coercible_to_type(&e, ety, None);
|
||||
ety
|
||||
}
|
||||
_ => self.check_expr_with_expectation(&e, NoExpectation),
|
||||
@ -2869,7 +2869,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
) -> Ty<'tcx> {
|
||||
match self.resume_yield_tys {
|
||||
Some((resume_ty, yield_ty)) => {
|
||||
self.check_expr_coercable_to_type(&value, yield_ty, None);
|
||||
self.check_expr_coercible_to_type(&value, yield_ty, None);
|
||||
|
||||
resume_ty
|
||||
}
|
||||
@ -2878,7 +2878,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// information. Hence, we check the source of the yield expression here and check its
|
||||
// value's type against `()` (this check should always hold).
|
||||
None if src.is_await() => {
|
||||
self.check_expr_coercable_to_type(&value, self.tcx.mk_unit(), None);
|
||||
self.check_expr_coercible_to_type(&value, self.tcx.mk_unit(), None);
|
||||
self.tcx.mk_unit()
|
||||
}
|
||||
_ => {
|
||||
|
@ -578,7 +578,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub(in super::super) fn report_ambiguity_errors(&self) {
|
||||
let mut errors = self.fulfillment_cx.borrow_mut().collect_remaining_errors();
|
||||
let mut errors = self.fulfillment_cx.borrow_mut().collect_remaining_errors(self);
|
||||
|
||||
if !errors.is_empty() {
|
||||
self.adjust_fulfillment_errors_for_expr_obligation(&mut errors);
|
||||
|
@ -78,7 +78,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// Finally, for ambiguity-related errors, we actually want to look
|
||||
// for a parameter that is the source of the inference type left
|
||||
// over in this predicate.
|
||||
if let traits::FulfillmentErrorCode::CodeAmbiguity = error.code {
|
||||
if let traits::FulfillmentErrorCode::CodeAmbiguity { .. } = error.code {
|
||||
fallback_param_to_point_at = None;
|
||||
self_param_to_point_at = None;
|
||||
param_to_point_at =
|
||||
@ -466,7 +466,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
/// obligation. Hence we refine the `expr` "outwards-in" and bail at the first kind of expression/impl we don't recognize.
|
||||
///
|
||||
/// This function returns a `Result<&Expr, &Expr>` - either way, it returns the `Expr` whose span should be
|
||||
/// reported as an error. If it is `Ok`, then it means it refined successfull. If it is `Err`, then it may be
|
||||
/// reported as an error. If it is `Ok`, then it means it refined successful. If it is `Err`, then it may be
|
||||
/// only a partial success - but it cannot be refined even further.
|
||||
fn blame_specific_expr_if_possible_for_derived_predicate_obligation(
|
||||
&self,
|
||||
@ -534,7 +534,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
/// - in_ty: `(Option<Vec<T>, bool)`
|
||||
/// we would drill until we arrive at `vec![1, 2, 3]`.
|
||||
///
|
||||
/// If successful, we return `Ok(refined_expr)`. If unsuccesful, we return `Err(partially_refined_expr`),
|
||||
/// If successful, we return `Ok(refined_expr)`. If unsuccessful, we return `Err(partially_refined_expr`),
|
||||
/// which will go as far as possible. For example, given `(foo(), false)` instead, we would drill to
|
||||
/// `foo()` and then return `Err("foo()")`.
|
||||
///
|
||||
|
@ -768,7 +768,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let (provided_ty, provided_span) = provided_arg_tys[*provided_idx];
|
||||
let trace =
|
||||
mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty);
|
||||
if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308(_)) {
|
||||
if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308) {
|
||||
self.err_ctxt().report_and_explain_type_error(trace, *e).emit();
|
||||
return true;
|
||||
}
|
||||
@ -1191,11 +1191,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// index position where it *should have been*, which is *after* the previous one.
|
||||
if let Some(provided_idx) = provided_idx {
|
||||
prev = provided_idx.index() as i64;
|
||||
continue;
|
||||
}
|
||||
let idx = ProvidedIdx::from_usize((prev + 1) as usize);
|
||||
if let None = provided_idx
|
||||
&& let Some((_, arg_span)) = provided_arg_tys.get(idx)
|
||||
{
|
||||
if let Some((_, arg_span)) = provided_arg_tys.get(idx) {
|
||||
prev += 1;
|
||||
// There is a type that was *not* found anywhere, so it isn't a move, but a
|
||||
// replacement and we look at what type it should have been. This will allow us
|
||||
// To suggest a multipart suggestion when encountering `foo(1, "")` where the def
|
||||
@ -1413,7 +1413,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
self.demand_eqtype(init.span, local_ty, init_ty);
|
||||
init_ty
|
||||
} else {
|
||||
self.check_expr_coercable_to_type(init, local_ty, None)
|
||||
self.check_expr_coercible_to_type(init, local_ty, None)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -239,8 +239,7 @@ pub fn resolve_interior<'a, 'tcx>(
|
||||
// typeck had previously found constraints that would cause them to be related.
|
||||
|
||||
let mut counter = 0;
|
||||
let mut mk_bound_region = |span| {
|
||||
let kind = ty::BrAnon(span);
|
||||
let mut mk_bound_region = |kind| {
|
||||
let var = ty::BoundVar::from_u32(counter);
|
||||
counter += 1;
|
||||
ty::BoundRegion { var, kind }
|
||||
@ -252,24 +251,23 @@ pub fn resolve_interior<'a, 'tcx>(
|
||||
let origin = fcx.region_var_origin(vid);
|
||||
match origin {
|
||||
RegionVariableOrigin::EarlyBoundRegion(span, _) => {
|
||||
mk_bound_region(Some(span))
|
||||
mk_bound_region(ty::BrAnon(Some(span)))
|
||||
}
|
||||
_ => mk_bound_region(None),
|
||||
_ => mk_bound_region(ty::BrAnon(None)),
|
||||
}
|
||||
}
|
||||
// FIXME: these should use `BrNamed`
|
||||
ty::ReEarlyBound(region) => {
|
||||
mk_bound_region(Some(fcx.tcx.def_span(region.def_id)))
|
||||
mk_bound_region(ty::BrNamed(region.def_id, region.name))
|
||||
}
|
||||
ty::ReLateBound(_, ty::BoundRegion { kind, .. })
|
||||
| ty::ReFree(ty::FreeRegion { bound_region: kind, .. }) => match kind {
|
||||
ty::BoundRegionKind::BrAnon(span) => mk_bound_region(span),
|
||||
ty::BoundRegionKind::BrNamed(def_id, _) => {
|
||||
mk_bound_region(Some(fcx.tcx.def_span(def_id)))
|
||||
ty::BoundRegionKind::BrAnon(span) => mk_bound_region(ty::BrAnon(span)),
|
||||
ty::BoundRegionKind::BrNamed(def_id, sym) => {
|
||||
mk_bound_region(ty::BrNamed(def_id, sym))
|
||||
}
|
||||
ty::BoundRegionKind::BrEnv => mk_bound_region(None),
|
||||
ty::BoundRegionKind::BrEnv => mk_bound_region(ty::BrAnon(None)),
|
||||
},
|
||||
_ => mk_bound_region(None),
|
||||
_ => mk_bound_region(ty::BrAnon(None)),
|
||||
};
|
||||
let r = fcx.tcx.mk_re_late_bound(current_depth, br);
|
||||
r
|
||||
@ -293,10 +291,7 @@ pub fn resolve_interior<'a, 'tcx>(
|
||||
type_causes,
|
||||
FnMutDelegate {
|
||||
regions: &mut |br| {
|
||||
let kind = match br.kind {
|
||||
ty::BrAnon(span) => ty::BrAnon(span),
|
||||
_ => br.kind,
|
||||
};
|
||||
let kind = br.kind;
|
||||
let var = ty::BoundVar::from_usize(bound_vars.len());
|
||||
bound_vars.push(ty::BoundVariableKind::Region(kind));
|
||||
counter += 1;
|
||||
|
@ -280,7 +280,7 @@ fn typeck_with_fallback<'tcx>(
|
||||
// Gather locals in statics (because of block expressions).
|
||||
GatherLocalsVisitor::new(&fcx).visit_body(body);
|
||||
|
||||
fcx.check_expr_coercable_to_type(&body.value, expected_type, None);
|
||||
fcx.check_expr_coercible_to_type(&body.value, expected_type, None);
|
||||
|
||||
fcx.write_ty(id, expected_type);
|
||||
};
|
||||
|
@ -1531,23 +1531,18 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
|
||||
// Convert the bounds into obligations.
|
||||
let impl_obligations = traits::predicates_for_generics(
|
||||
|_idx, span| {
|
||||
let misc = traits::ObligationCause::misc(span, self.body_id);
|
||||
let parent_trait_pred = ty::Binder::dummy(ty::TraitPredicate {
|
||||
trait_ref: ty::TraitRef::from_method(self.tcx, impl_def_id, substs),
|
||||
constness: ty::BoundConstness::NotConst,
|
||||
polarity: ty::ImplPolarity::Positive,
|
||||
});
|
||||
misc.derived_cause(parent_trait_pred, |derived| {
|
||||
traits::ImplDerivedObligation(Box::new(
|
||||
traits::ImplDerivedObligationCause {
|
||||
derived,
|
||||
impl_or_alias_def_id: impl_def_id,
|
||||
impl_def_predicate_index: None,
|
||||
span,
|
||||
},
|
||||
))
|
||||
})
|
||||
|idx, span| {
|
||||
let code = if span.is_dummy() {
|
||||
traits::ExprItemObligation(impl_def_id, self.scope_expr_id, idx)
|
||||
} else {
|
||||
traits::ExprBindingObligation(
|
||||
impl_def_id,
|
||||
span,
|
||||
self.scope_expr_id,
|
||||
idx,
|
||||
)
|
||||
};
|
||||
ObligationCause::new(self.span, self.body_id, code)
|
||||
},
|
||||
self.param_env,
|
||||
impl_bounds,
|
||||
|
@ -300,7 +300,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
};
|
||||
|
||||
// We could pass the file for long types into these two, but it isn't strictly necessary
|
||||
// given how targetted they are.
|
||||
// given how targeted they are.
|
||||
if self.suggest_wrapping_range_with_parens(
|
||||
tcx,
|
||||
rcvr_ty,
|
||||
@ -661,19 +661,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// Find all the requirements that come from a local `impl` block.
|
||||
let mut skip_list: FxHashSet<_> = Default::default();
|
||||
let mut spanned_predicates = FxHashMap::default();
|
||||
for (p, parent_p, impl_def_id, cause) in unsatisfied_predicates
|
||||
.iter()
|
||||
.filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c)))
|
||||
.filter_map(|(p, parent, c)| match c.code() {
|
||||
ObligationCauseCode::ImplDerivedObligation(data)
|
||||
if matches!(p.kind().skip_binder(), ty::PredicateKind::Clause(_)) =>
|
||||
{
|
||||
Some((p, parent, data.impl_or_alias_def_id, data))
|
||||
for (p, parent_p, cause) in unsatisfied_predicates {
|
||||
// Extract the predicate span and parent def id of the cause,
|
||||
// if we have one.
|
||||
let (item_def_id, cause_span) = match cause.as_ref().map(|cause| cause.code()) {
|
||||
Some(ObligationCauseCode::ImplDerivedObligation(data)) => {
|
||||
(data.impl_or_alias_def_id, data.span)
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
{
|
||||
match self.tcx.hir().get_if_local(impl_def_id) {
|
||||
Some(
|
||||
ObligationCauseCode::ExprBindingObligation(def_id, span, _, _)
|
||||
| ObligationCauseCode::BindingObligation(def_id, span),
|
||||
) => (*def_id, *span),
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
// Don't point out the span of `WellFormed` predicates.
|
||||
if !matches!(p.kind().skip_binder(), ty::PredicateKind::Clause(_)) {
|
||||
continue;
|
||||
};
|
||||
|
||||
match self.tcx.hir().get_if_local(item_def_id) {
|
||||
// Unmet obligation comes from a `derive` macro, point at it once to
|
||||
// avoid multiple span labels pointing at the same place.
|
||||
Some(Node::Item(hir::Item {
|
||||
@ -718,7 +725,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
});
|
||||
for param in generics.params {
|
||||
if param.span == cause.span && sized_pred {
|
||||
if param.span == cause_span && sized_pred {
|
||||
let (sp, sugg) = match param.colon_span {
|
||||
Some(sp) => (sp.shrink_to_hi(), " ?Sized +"),
|
||||
None => (param.span.shrink_to_hi(), ": ?Sized"),
|
||||
@ -741,9 +748,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
(FxHashSet::default(), FxHashSet::default(), Vec::new())
|
||||
});
|
||||
entry.2.push(p);
|
||||
if cause.span != *item_span {
|
||||
entry.0.insert(cause.span);
|
||||
entry.1.insert((cause.span, "unsatisfied trait bound introduced here"));
|
||||
if cause_span != *item_span {
|
||||
entry.0.insert(cause_span);
|
||||
entry.1.insert((cause_span, "unsatisfied trait bound introduced here"));
|
||||
} else {
|
||||
if let Some(trait_ref) = of_trait {
|
||||
entry.0.insert(trait_ref.path.span);
|
||||
@ -775,9 +782,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let entry = entry.or_insert_with(|| {
|
||||
(FxHashSet::default(), FxHashSet::default(), Vec::new())
|
||||
});
|
||||
entry.0.insert(cause.span);
|
||||
entry.0.insert(cause_span);
|
||||
entry.1.insert((ident.span, ""));
|
||||
entry.1.insert((cause.span, "unsatisfied trait bound introduced here"));
|
||||
entry.1.insert((cause_span, "unsatisfied trait bound introduced here"));
|
||||
entry.2.push(p);
|
||||
}
|
||||
Some(node) => unreachable!("encountered `{node:?}`"),
|
||||
|
@ -12,9 +12,7 @@ use rustc_middle::ty::adjustment::{
|
||||
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
|
||||
};
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::{
|
||||
self, IsSuggestable, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
|
||||
};
|
||||
use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_session::errors::ExprParenthesesNeeded;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::{sym, Ident};
|
||||
@ -103,9 +101,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
match BinOpCategory::from(op) {
|
||||
BinOpCategory::Shortcircuit => {
|
||||
// && and || are a simple case.
|
||||
self.check_expr_coercable_to_type(lhs_expr, tcx.types.bool, None);
|
||||
self.check_expr_coercible_to_type(lhs_expr, tcx.types.bool, None);
|
||||
let lhs_diverges = self.diverges.get();
|
||||
self.check_expr_coercable_to_type(rhs_expr, tcx.types.bool, None);
|
||||
self.check_expr_coercible_to_type(rhs_expr, tcx.types.bool, None);
|
||||
|
||||
// Depending on the LHS' value, the RHS can never execute.
|
||||
self.diverges.set(lhs_diverges);
|
||||
@ -255,7 +253,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
);
|
||||
|
||||
// see `NB` above
|
||||
let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var, Some(lhs_expr));
|
||||
let rhs_ty = self.check_expr_coercible_to_type(rhs_expr, rhs_ty_var, Some(lhs_expr));
|
||||
let rhs_ty = self.resolve_vars_with_obligations(rhs_ty);
|
||||
|
||||
let return_ty = match result {
|
||||
@ -965,21 +963,3 @@ fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>, rhs: Ty<'tcx>, op: hir::BinOp) -> bool
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct TypeParamEraser<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, Span);
|
||||
|
||||
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for TypeParamEraser<'_, 'tcx> {
|
||||
fn interner(&self) -> TyCtxt<'tcx> {
|
||||
self.0.tcx
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
match ty.kind() {
|
||||
ty::Param(_) => self.0.next_ty_var(TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::MiscVariable,
|
||||
span: self.1,
|
||||
}),
|
||||
_ => ty.super_fold_with(self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -163,7 +163,6 @@ infer_region_explanation = {$pref_kind ->
|
||||
[as_defined] the lifetime `{$desc_arg}` as defined here
|
||||
[as_defined_anon] the anonymous lifetime as defined here
|
||||
[defined_here] the anonymous lifetime defined here
|
||||
[anon_num_here] the anonymous lifetime #{$desc_num_arg} defined here
|
||||
[defined_here_reg] the lifetime `{$desc_arg}` as defined here
|
||||
}{$suff_kind ->
|
||||
*[should_not_happen] [{$suff_kind}]
|
||||
@ -174,7 +173,7 @@ infer_region_explanation = {$pref_kind ->
|
||||
|
||||
infer_outlives_content = lifetime of reference outlives lifetime of borrowed content...
|
||||
infer_outlives_bound = lifetime of the source pointer does not outlive lifetime bound of the object type
|
||||
infer_fullfill_req_lifetime = the type `{$ty}` does not fulfill the required lifetime
|
||||
infer_fulfill_req_lifetime = the type `{$ty}` does not fulfill the required lifetime
|
||||
infer_lf_bound_not_satisfied = lifetime bound not satisfied
|
||||
infer_borrowed_too_long = a value of type `{$ty}` is borrowed for too long
|
||||
infer_ref_longer_than_data = in type `{$ty}`, reference has a longer lifetime than the data it references
|
||||
@ -348,3 +347,47 @@ infer_prlf_known_limitation = this is a known limitation that will be removed in
|
||||
|
||||
infer_opaque_captures_lifetime = hidden type for `{$opaque_ty}` captures lifetime that does not appear in bounds
|
||||
.label = opaque type defined here
|
||||
|
||||
infer_fps_use_ref = consider using a reference
|
||||
infer_fps_remove_ref = consider removing the reference
|
||||
infer_fps_cast = consider casting to a fn pointer
|
||||
infer_fps_items_are_distinct = fn items are distinct from fn pointers
|
||||
infer_fps_cast_both = consider casting both fn items to fn pointers using `as {$expected_sig}`
|
||||
|
||||
infer_fn_uniq_types = different fn items have unique types, even if their signatures are the same
|
||||
infer_fn_consider_casting = consider casting the fn item to a fn pointer: `{$casting}`
|
||||
|
||||
infer_sarwa_option = you can convert from `&Option<T>` to `Option<&T>` using `.as_ref()`
|
||||
infer_sarwa_result = you can convert from `&Result<T, E>` to `Result<&T, &E>` using `.as_ref()`
|
||||
|
||||
infer_suggest_accessing_field = you might have meant to use field `{$name}` whose type is `{$ty}`
|
||||
|
||||
infer_sbfrit_change_return_type = you could change the return type to be a boxed trait object
|
||||
infer_sbfrit_box_return_expr = if you change the return type to expect trait objects, box the returned expressions
|
||||
|
||||
infer_stp_wrap_one = try wrapping the pattern in `{$variant}`
|
||||
infer_stp_wrap_many = try wrapping the pattern in a variant of `{$path}`
|
||||
|
||||
infer_tuple_trailing_comma = use a trailing comma to create a tuple with one element
|
||||
|
||||
infer_oc_method_compat = method not compatible with trait
|
||||
infer_oc_type_compat = type not compatible with trait
|
||||
infer_oc_const_compat = const not compatible with trait
|
||||
infer_oc_try_compat = `?` operator has incompatible types
|
||||
infer_oc_match_compat = `match` arms have incompatible types
|
||||
infer_oc_if_else_different = `if` and `else` have incompatible types
|
||||
infer_oc_no_else = `if` may be missing an `else` clause
|
||||
infer_oc_no_diverge = `else` clause of `let...else` does not diverge
|
||||
infer_oc_fn_main_correct_type = `main` function has wrong type
|
||||
infer_oc_fn_start_correct_type = `#[start]` function has wrong type
|
||||
infer_oc_intristic_correct_type = intrinsic has wrong type
|
||||
infer_oc_method_correct_type = mismatched `self` parameter type
|
||||
infer_oc_closure_selfref = closure/generator type that references itself
|
||||
infer_oc_cant_coerce = cannot coerce intrinsics to function pointers
|
||||
infer_oc_generic = mismatched types
|
||||
|
||||
infer_meant_byte_literal = if you meant to write a byte literal, prefix with `b`
|
||||
infer_meant_char_literal = if you meant to write a `char` literal, use single quotes
|
||||
infer_meant_str_literal = if you meant to write a `str` literal, use double quotes
|
||||
infer_consider_specifying_length = consider specifying the actual array length
|
||||
infer_try_cannot_convert = `?` operator cannot convert from `{$found}` to `{$expected}`
|
||||
|
@ -53,7 +53,7 @@ pub struct AnnotationRequired<'a> {
|
||||
// Copy of `AnnotationRequired` for E0283
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(infer_type_annotations_needed, code = "E0283")]
|
||||
pub struct AmbigousImpl<'a> {
|
||||
pub struct AmbiguousImpl<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub source_kind: &'static str,
|
||||
@ -184,18 +184,6 @@ pub enum SourceKindMultiSuggestion<'a> {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(
|
||||
infer_suggest_add_let_for_letchains,
|
||||
style = "verbose",
|
||||
applicability = "machine-applicable",
|
||||
code = "let "
|
||||
)]
|
||||
pub(crate) struct SuggAddLetForLetChains {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl<'a> SourceKindMultiSuggestion<'a> {
|
||||
pub fn new_fully_qualified(
|
||||
span: Span,
|
||||
@ -954,8 +942,8 @@ pub struct OutlivesBound<'a> {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(infer_fullfill_req_lifetime, code = "E0477")]
|
||||
pub struct FullfillReqLifetime<'a> {
|
||||
#[diag(infer_fulfill_req_lifetime, code = "E0477")]
|
||||
pub struct FulfillReqLifetime<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub ty: Ty<'a>,
|
||||
@ -1157,3 +1145,380 @@ pub struct OpaqueCapturesLifetime<'tcx> {
|
||||
pub opaque_ty_span: Span,
|
||||
pub opaque_ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum FunctionPointerSuggestion<'a> {
|
||||
#[suggestion(
|
||||
infer_fps_use_ref,
|
||||
code = "&{fn_name}",
|
||||
style = "verbose",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
UseRef {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[skip_arg]
|
||||
fn_name: String,
|
||||
},
|
||||
#[suggestion(
|
||||
infer_fps_remove_ref,
|
||||
code = "{fn_name}",
|
||||
style = "verbose",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
RemoveRef {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[skip_arg]
|
||||
fn_name: String,
|
||||
},
|
||||
#[suggestion(
|
||||
infer_fps_cast,
|
||||
code = "&({fn_name} as {sig})",
|
||||
style = "verbose",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
CastRef {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[skip_arg]
|
||||
fn_name: String,
|
||||
#[skip_arg]
|
||||
sig: Binder<'a, FnSig<'a>>,
|
||||
},
|
||||
#[suggestion(
|
||||
infer_fps_cast,
|
||||
code = "{fn_name} as {sig}",
|
||||
style = "verbose",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
Cast {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[skip_arg]
|
||||
fn_name: String,
|
||||
#[skip_arg]
|
||||
sig: Binder<'a, FnSig<'a>>,
|
||||
},
|
||||
#[suggestion(
|
||||
infer_fps_cast_both,
|
||||
code = "{fn_name} as {found_sig}",
|
||||
style = "hidden",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
CastBoth {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[skip_arg]
|
||||
fn_name: String,
|
||||
#[skip_arg]
|
||||
found_sig: Binder<'a, FnSig<'a>>,
|
||||
expected_sig: Binder<'a, FnSig<'a>>,
|
||||
},
|
||||
#[suggestion(
|
||||
infer_fps_cast_both,
|
||||
code = "&({fn_name} as {found_sig})",
|
||||
style = "hidden",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
CastBothRef {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[skip_arg]
|
||||
fn_name: String,
|
||||
#[skip_arg]
|
||||
found_sig: Binder<'a, FnSig<'a>>,
|
||||
expected_sig: Binder<'a, FnSig<'a>>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(infer_fps_items_are_distinct)]
|
||||
pub struct FnItemsAreDistinct;
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(infer_fn_uniq_types)]
|
||||
pub struct FnUniqTypes;
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[help(infer_fn_consider_casting)]
|
||||
pub struct FnConsiderCasting {
|
||||
pub casting: String,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum SuggestAsRefWhereAppropriate<'a> {
|
||||
#[suggestion(
|
||||
infer_sarwa_option,
|
||||
code = "{snippet}.as_ref()",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
Option {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
snippet: &'a str,
|
||||
},
|
||||
#[suggestion(
|
||||
infer_sarwa_result,
|
||||
code = "{snippet}.as_ref()",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
Result {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
snippet: &'a str,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum SuggestAccessingField<'a> {
|
||||
#[suggestion(
|
||||
infer_suggest_accessing_field,
|
||||
code = "{snippet}.{name}",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
Safe {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
snippet: String,
|
||||
name: Symbol,
|
||||
ty: Ty<'a>,
|
||||
},
|
||||
#[suggestion(
|
||||
infer_suggest_accessing_field,
|
||||
code = "unsafe {{ {snippet}.{name} }}",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
Unsafe {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
snippet: String,
|
||||
name: Symbol,
|
||||
ty: Ty<'a>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum SuggestBoxingForReturnImplTrait {
|
||||
#[multipart_suggestion(infer_sbfrit_change_return_type, applicability = "maybe-incorrect")]
|
||||
ChangeReturnType {
|
||||
#[suggestion_part(code = "Box<dyn")]
|
||||
start_sp: Span,
|
||||
#[suggestion_part(code = ">")]
|
||||
end_sp: Span,
|
||||
},
|
||||
#[multipart_suggestion(infer_sbfrit_box_return_expr, applicability = "maybe-incorrect")]
|
||||
BoxReturnExpr {
|
||||
#[suggestion_part(code = "Box::new(")]
|
||||
starts: Vec<Span>,
|
||||
#[suggestion_part(code = ")")]
|
||||
ends: Vec<Span>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(infer_stp_wrap_one, applicability = "maybe-incorrect")]
|
||||
pub struct SuggestTuplePatternOne {
|
||||
pub variant: String,
|
||||
#[suggestion_part(code = "{variant}(")]
|
||||
pub span_low: Span,
|
||||
#[suggestion_part(code = ")")]
|
||||
pub span_high: Span,
|
||||
}
|
||||
|
||||
pub struct SuggestTuplePatternMany {
|
||||
pub path: String,
|
||||
pub cause_span: Span,
|
||||
pub compatible_variants: Vec<String>,
|
||||
}
|
||||
|
||||
impl AddToDiagnostic for SuggestTuplePatternMany {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, f: F)
|
||||
where
|
||||
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
|
||||
{
|
||||
diag.set_arg("path", self.path);
|
||||
let message = f(diag, crate::fluent_generated::infer_stp_wrap_many.into());
|
||||
diag.multipart_suggestions(
|
||||
message,
|
||||
self.compatible_variants.into_iter().map(|variant| {
|
||||
vec![
|
||||
(self.cause_span.shrink_to_lo(), format!("{}(", variant)),
|
||||
(self.cause_span.shrink_to_hi(), ")".to_string()),
|
||||
]
|
||||
}),
|
||||
rustc_errors::Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum TypeErrorAdditionalDiags {
|
||||
#[suggestion(
|
||||
infer_meant_byte_literal,
|
||||
code = "b'{code}'",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
MeantByteLiteral {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
code: String,
|
||||
},
|
||||
#[suggestion(
|
||||
infer_meant_char_literal,
|
||||
code = "'{code}'",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
MeantCharLiteral {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
code: String,
|
||||
},
|
||||
#[suggestion(
|
||||
infer_meant_str_literal,
|
||||
code = "\"{code}\"",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
MeantStrLiteral {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
code: String,
|
||||
},
|
||||
#[suggestion(
|
||||
infer_consider_specifying_length,
|
||||
code = "{length}",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
ConsiderSpecifyingLength {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
length: u64,
|
||||
},
|
||||
#[note(infer_try_cannot_convert)]
|
||||
TryCannotConvert { found: String, expected: String },
|
||||
#[suggestion(infer_tuple_trailing_comma, code = ",", applicability = "machine-applicable")]
|
||||
TupleOnlyComma {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[multipart_suggestion(infer_tuple_trailing_comma, applicability = "machine-applicable")]
|
||||
TupleAlsoParentheses {
|
||||
#[suggestion_part(code = "(")]
|
||||
span_low: Span,
|
||||
#[suggestion_part(code = ",)")]
|
||||
span_high: Span,
|
||||
},
|
||||
#[suggestion(
|
||||
infer_suggest_add_let_for_letchains,
|
||||
style = "verbose",
|
||||
applicability = "machine-applicable",
|
||||
code = "let "
|
||||
)]
|
||||
AddLetForLetChains {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
pub enum ObligationCauseFailureCode {
|
||||
#[diag(infer_oc_method_compat, code = "E0308")]
|
||||
MethodCompat {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[subdiagnostic]
|
||||
subdiags: Vec<TypeErrorAdditionalDiags>,
|
||||
},
|
||||
#[diag(infer_oc_type_compat, code = "E0308")]
|
||||
TypeCompat {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[subdiagnostic]
|
||||
subdiags: Vec<TypeErrorAdditionalDiags>,
|
||||
},
|
||||
#[diag(infer_oc_const_compat, code = "E0308")]
|
||||
ConstCompat {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[subdiagnostic]
|
||||
subdiags: Vec<TypeErrorAdditionalDiags>,
|
||||
},
|
||||
#[diag(infer_oc_try_compat, code = "E0308")]
|
||||
TryCompat {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[subdiagnostic]
|
||||
subdiags: Vec<TypeErrorAdditionalDiags>,
|
||||
},
|
||||
#[diag(infer_oc_match_compat, code = "E0308")]
|
||||
MatchCompat {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[subdiagnostic]
|
||||
subdiags: Vec<TypeErrorAdditionalDiags>,
|
||||
},
|
||||
#[diag(infer_oc_if_else_different, code = "E0308")]
|
||||
IfElseDifferent {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[subdiagnostic]
|
||||
subdiags: Vec<TypeErrorAdditionalDiags>,
|
||||
},
|
||||
#[diag(infer_oc_no_else, code = "E0317")]
|
||||
NoElse {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[diag(infer_oc_no_diverge, code = "E0308")]
|
||||
NoDiverge {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[subdiagnostic]
|
||||
subdiags: Vec<TypeErrorAdditionalDiags>,
|
||||
},
|
||||
#[diag(infer_oc_fn_main_correct_type, code = "E0580")]
|
||||
FnMainCorrectType {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[diag(infer_oc_fn_start_correct_type, code = "E0308")]
|
||||
FnStartCorrectType {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[subdiagnostic]
|
||||
subdiags: Vec<TypeErrorAdditionalDiags>,
|
||||
},
|
||||
#[diag(infer_oc_intristic_correct_type, code = "E0308")]
|
||||
IntristicCorrectType {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[subdiagnostic]
|
||||
subdiags: Vec<TypeErrorAdditionalDiags>,
|
||||
},
|
||||
#[diag(infer_oc_method_correct_type, code = "E0308")]
|
||||
MethodCorrectType {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[subdiagnostic]
|
||||
subdiags: Vec<TypeErrorAdditionalDiags>,
|
||||
},
|
||||
#[diag(infer_oc_closure_selfref, code = "E0644")]
|
||||
ClosureSelfref {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[diag(infer_oc_cant_coerce, code = "E0308")]
|
||||
CantCoerce {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[subdiagnostic]
|
||||
subdiags: Vec<TypeErrorAdditionalDiags>,
|
||||
},
|
||||
#[diag(infer_oc_generic, code = "E0308")]
|
||||
Generic {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[subdiagnostic]
|
||||
subdiags: Vec<TypeErrorAdditionalDiags>,
|
||||
},
|
||||
}
|
||||
|
@ -4,12 +4,10 @@ use rustc_errors::{self, AddToDiagnostic, Diagnostic, IntoDiagnosticArg, Subdiag
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_span::{symbol::kw, Span};
|
||||
|
||||
#[derive(Default)]
|
||||
struct DescriptionCtx<'a> {
|
||||
span: Option<Span>,
|
||||
kind: &'a str,
|
||||
arg: String,
|
||||
num_arg: u32,
|
||||
}
|
||||
|
||||
impl<'a> DescriptionCtx<'a> {
|
||||
@ -18,19 +16,63 @@ impl<'a> DescriptionCtx<'a> {
|
||||
region: ty::Region<'tcx>,
|
||||
alt_span: Option<Span>,
|
||||
) -> Option<Self> {
|
||||
let mut me = DescriptionCtx::default();
|
||||
me.span = alt_span;
|
||||
match *region {
|
||||
ty::ReEarlyBound(_) | ty::ReFree(_) => {
|
||||
return Self::from_early_bound_and_free_regions(tcx, region);
|
||||
let (span, kind, arg) = match *region {
|
||||
ty::ReEarlyBound(ref br) => {
|
||||
let scope = region.free_region_binding_scope(tcx).expect_local();
|
||||
let span = if let Some(param) =
|
||||
tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
|
||||
{
|
||||
param.span
|
||||
} else {
|
||||
tcx.def_span(scope)
|
||||
};
|
||||
if br.has_name() {
|
||||
(Some(span), "as_defined", br.name.to_string())
|
||||
} else {
|
||||
(Some(span), "as_defined_anon", String::new())
|
||||
}
|
||||
}
|
||||
ty::ReStatic => {
|
||||
me.kind = "restatic";
|
||||
ty::ReFree(ref fr) => {
|
||||
if !fr.bound_region.is_named()
|
||||
&& let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region)
|
||||
{
|
||||
(Some(ty.span), "defined_here", String::new())
|
||||
} else {
|
||||
let scope = region.free_region_binding_scope(tcx).expect_local();
|
||||
match fr.bound_region {
|
||||
ty::BoundRegionKind::BrNamed(_, name) => {
|
||||
let span = if let Some(param) = tcx
|
||||
.hir()
|
||||
.get_generics(scope)
|
||||
.and_then(|generics| generics.get_named(name))
|
||||
{
|
||||
param.span
|
||||
} else {
|
||||
tcx.def_span(scope)
|
||||
};
|
||||
if name == kw::UnderscoreLifetime {
|
||||
(Some(span), "as_defined_anon", String::new())
|
||||
} else {
|
||||
(Some(span), "as_defined", name.to_string())
|
||||
}
|
||||
}
|
||||
ty::BrAnon(span) => {
|
||||
let span = match span {
|
||||
Some(_) => span,
|
||||
None => Some(tcx.def_span(scope)),
|
||||
};
|
||||
(span, "defined_here", String::new())
|
||||
}
|
||||
_ => {
|
||||
(Some(tcx.def_span(scope)), "defined_here_reg", region.to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ty::RePlaceholder(_) => return None,
|
||||
ty::ReStatic => (alt_span, "restatic", String::new()),
|
||||
|
||||
ty::ReError(_) => return None,
|
||||
ty::RePlaceholder(_) | ty::ReError(_) => return None,
|
||||
|
||||
// FIXME(#13998) RePlaceholder should probably print like
|
||||
// ReFree rather than dumping Debug output on the user.
|
||||
@ -38,82 +80,10 @@ impl<'a> DescriptionCtx<'a> {
|
||||
// We shouldn't really be having unification failures with ReVar
|
||||
// and ReLateBound though.
|
||||
ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => {
|
||||
me.kind = "revar";
|
||||
me.arg = format!("{:?}", region);
|
||||
(alt_span, "revar", format!("{:?}", region))
|
||||
}
|
||||
};
|
||||
Some(me)
|
||||
}
|
||||
|
||||
fn from_early_bound_and_free_regions<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
region: ty::Region<'tcx>,
|
||||
) -> Option<Self> {
|
||||
let mut me = DescriptionCtx::default();
|
||||
let scope = region.free_region_binding_scope(tcx).expect_local();
|
||||
match *region {
|
||||
ty::ReEarlyBound(ref br) => {
|
||||
let mut sp = tcx.def_span(scope);
|
||||
if let Some(param) =
|
||||
tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
|
||||
{
|
||||
sp = param.span;
|
||||
}
|
||||
if br.has_name() {
|
||||
me.kind = "as_defined";
|
||||
me.arg = br.name.to_string();
|
||||
} else {
|
||||
me.kind = "as_defined_anon";
|
||||
};
|
||||
me.span = Some(sp)
|
||||
}
|
||||
ty::ReFree(ref fr) => {
|
||||
if !fr.bound_region.is_named()
|
||||
&& let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region)
|
||||
{
|
||||
me.kind = "defined_here";
|
||||
me.span = Some(ty.span);
|
||||
} else {
|
||||
match fr.bound_region {
|
||||
ty::BoundRegionKind::BrNamed(_, name) => {
|
||||
let mut sp = tcx.def_span(scope);
|
||||
if let Some(param) =
|
||||
tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
|
||||
{
|
||||
sp = param.span;
|
||||
}
|
||||
if name == kw::UnderscoreLifetime {
|
||||
me.kind = "as_defined_anon";
|
||||
} else {
|
||||
me.kind = "as_defined";
|
||||
me.arg = name.to_string();
|
||||
};
|
||||
me.span = Some(sp);
|
||||
}
|
||||
ty::BrAnon(span) => {
|
||||
me.kind = "defined_here";
|
||||
me.span = match span {
|
||||
Some(_) => span,
|
||||
None => Some(tcx.def_span(scope)),
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
me.kind = "defined_here_reg";
|
||||
me.arg = region.to_string();
|
||||
me.span = Some(tcx.def_span(scope));
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => bug!(),
|
||||
}
|
||||
Some(me)
|
||||
}
|
||||
|
||||
fn add_to(self, diag: &mut rustc_errors::Diagnostic) {
|
||||
diag.set_arg("desc_kind", self.kind);
|
||||
diag.set_arg("desc_arg", self.arg);
|
||||
diag.set_arg("desc_num_arg", self.num_arg);
|
||||
Some(DescriptionCtx { span, kind, arg })
|
||||
}
|
||||
}
|
||||
|
||||
@ -198,10 +168,11 @@ impl AddToDiagnostic for RegionExplanation<'_> {
|
||||
{
|
||||
diag.set_arg("pref_kind", self.prefix);
|
||||
diag.set_arg("suff_kind", self.suffix);
|
||||
let desc_span = self.desc.span;
|
||||
self.desc.add_to(diag);
|
||||
diag.set_arg("desc_kind", self.desc.kind);
|
||||
diag.set_arg("desc_arg", self.desc.arg);
|
||||
|
||||
let msg = f(diag, fluent::infer_region_explanation.into());
|
||||
if let Some(span) = desc_span {
|
||||
if let Some(span) = self.desc.span {
|
||||
diag.span_note(span, msg);
|
||||
} else {
|
||||
diag.note(msg);
|
||||
|
@ -49,11 +49,10 @@ use super::lexical_region_resolve::RegionResolutionError;
|
||||
use super::region_constraints::GenericKind;
|
||||
use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs};
|
||||
|
||||
use crate::errors;
|
||||
use crate::errors::{self, ObligationCauseFailureCode, TypeErrorAdditionalDiags};
|
||||
use crate::infer;
|
||||
use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
|
||||
use crate::infer::ExpectedFound;
|
||||
use crate::traits::error_reporting::report_object_safety_error;
|
||||
use crate::traits::{
|
||||
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
|
||||
PredicateObligation,
|
||||
@ -75,6 +74,7 @@ use rustc_middle::ty::{
|
||||
self, error::TypeError, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
|
||||
TypeVisitable, TypeVisitableExt,
|
||||
};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span};
|
||||
use rustc_target::spec::abi;
|
||||
use std::ops::{ControlFlow, Deref};
|
||||
@ -90,9 +90,35 @@ pub use need_type_info::TypeAnnotationNeeded;
|
||||
|
||||
pub mod nice_region_error;
|
||||
|
||||
/// Makes a valid string literal from a string by escaping special characters (" and \),
|
||||
/// unless they are already escaped.
|
||||
fn escape_literal(s: &str) -> String {
|
||||
let mut escaped = String::with_capacity(s.len());
|
||||
let mut chrs = s.chars().peekable();
|
||||
while let Some(first) = chrs.next() {
|
||||
match (first, chrs.peek()) {
|
||||
('\\', Some(&delim @ '"') | Some(&delim @ '\'')) => {
|
||||
escaped.push('\\');
|
||||
escaped.push(delim);
|
||||
chrs.next();
|
||||
}
|
||||
('"' | '\'', _) => {
|
||||
escaped.push('\\');
|
||||
escaped.push(first)
|
||||
}
|
||||
(c, _) => escaped.push(c),
|
||||
};
|
||||
}
|
||||
escaped
|
||||
}
|
||||
|
||||
/// A helper for building type related errors. The `typeck_results`
|
||||
/// field is only populated during an in-progress typeck.
|
||||
/// Get an instance by calling `InferCtxt::err` or `FnCtxt::infer_err`.
|
||||
/// Get an instance by calling `InferCtxt::err_ctxt` or `FnCtxt::err_ctxt`.
|
||||
///
|
||||
/// You must only create this if you intend to actually emit an error.
|
||||
/// This provides a lot of utility methods which should not be used
|
||||
/// during the happy path.
|
||||
pub struct TypeErrCtxt<'a, 'tcx> {
|
||||
pub infcx: &'a InferCtxt<'tcx>,
|
||||
pub typeck_results: Option<std::cell::Ref<'a, ty::TypeckResults<'tcx>>>,
|
||||
@ -104,6 +130,19 @@ pub struct TypeErrCtxt<'a, 'tcx> {
|
||||
Box<dyn Fn(Ty<'tcx>) -> Vec<(Ty<'tcx>, Vec<PredicateObligation<'tcx>>)> + 'a>,
|
||||
}
|
||||
|
||||
impl Drop for TypeErrCtxt<'_, '_> {
|
||||
fn drop(&mut self) {
|
||||
if let Some(_) = self.infcx.tcx.sess.has_errors_or_delayed_span_bugs() {
|
||||
// ok, emitted an error.
|
||||
} else {
|
||||
self.infcx
|
||||
.tcx
|
||||
.sess
|
||||
.delay_span_bug(DUMMY_SP, "used a `TypeErrCtxt` without failing compilation");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeErrCtxt<'_, '_> {
|
||||
/// This is just to avoid a potential footgun of accidentally
|
||||
/// dropping `typeck_results` by calling `InferCtxt::err_ctxt`
|
||||
@ -164,9 +203,58 @@ fn msg_span_from_named_region<'tcx>(
|
||||
alt_span: Option<Span>,
|
||||
) -> (String, Option<Span>) {
|
||||
match *region {
|
||||
ty::ReEarlyBound(_) | ty::ReFree(_) => {
|
||||
let (msg, span) = msg_span_from_early_bound_and_free_regions(tcx, region);
|
||||
(msg, Some(span))
|
||||
ty::ReEarlyBound(ref br) => {
|
||||
let scope = region.free_region_binding_scope(tcx).expect_local();
|
||||
let span = if let Some(param) =
|
||||
tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
|
||||
{
|
||||
param.span
|
||||
} else {
|
||||
tcx.def_span(scope)
|
||||
};
|
||||
let text = if br.has_name() {
|
||||
format!("the lifetime `{}` as defined here", br.name)
|
||||
} else {
|
||||
"the anonymous lifetime as defined here".to_string()
|
||||
};
|
||||
(text, Some(span))
|
||||
}
|
||||
ty::ReFree(ref fr) => {
|
||||
if !fr.bound_region.is_named()
|
||||
&& let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region)
|
||||
{
|
||||
("the anonymous lifetime defined here".to_string(), Some(ty.span))
|
||||
} else {
|
||||
let scope = region.free_region_binding_scope(tcx).expect_local();
|
||||
match fr.bound_region {
|
||||
ty::BoundRegionKind::BrNamed(_, name) => {
|
||||
let span = if let Some(param) =
|
||||
tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
|
||||
{
|
||||
param.span
|
||||
} else {
|
||||
tcx.def_span(scope)
|
||||
};
|
||||
let text = if name == kw::UnderscoreLifetime {
|
||||
"the anonymous lifetime as defined here".to_string()
|
||||
} else {
|
||||
format!("the lifetime `{}` as defined here", name)
|
||||
};
|
||||
(text, Some(span))
|
||||
}
|
||||
ty::BrAnon(span) => (
|
||||
"the anonymous lifetime as defined here".to_string(),
|
||||
Some(match span {
|
||||
Some(span) => span,
|
||||
None => tcx.def_span(scope)
|
||||
})
|
||||
),
|
||||
_ => (
|
||||
format!("the lifetime `{}` as defined here", region),
|
||||
Some(tcx.def_span(scope)),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::ReStatic => ("the static lifetime".to_owned(), alt_span),
|
||||
ty::RePlaceholder(ty::PlaceholderRegion {
|
||||
@ -185,65 +273,6 @@ fn msg_span_from_named_region<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
fn msg_span_from_early_bound_and_free_regions<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
region: ty::Region<'tcx>,
|
||||
) -> (String, Span) {
|
||||
let scope = region.free_region_binding_scope(tcx).expect_local();
|
||||
match *region {
|
||||
ty::ReEarlyBound(ref br) => {
|
||||
let mut sp = tcx.def_span(scope);
|
||||
if let Some(param) =
|
||||
tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
|
||||
{
|
||||
sp = param.span;
|
||||
}
|
||||
let text = if br.has_name() {
|
||||
format!("the lifetime `{}` as defined here", br.name)
|
||||
} else {
|
||||
"the anonymous lifetime as defined here".to_string()
|
||||
};
|
||||
(text, sp)
|
||||
}
|
||||
ty::ReFree(ref fr) => {
|
||||
if !fr.bound_region.is_named()
|
||||
&& let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region)
|
||||
{
|
||||
("the anonymous lifetime defined here".to_string(), ty.span)
|
||||
} else {
|
||||
match fr.bound_region {
|
||||
ty::BoundRegionKind::BrNamed(_, name) => {
|
||||
let mut sp = tcx.def_span(scope);
|
||||
if let Some(param) =
|
||||
tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
|
||||
{
|
||||
sp = param.span;
|
||||
}
|
||||
let text = if name == kw::UnderscoreLifetime {
|
||||
"the anonymous lifetime as defined here".to_string()
|
||||
} else {
|
||||
format!("the lifetime `{}` as defined here", name)
|
||||
};
|
||||
(text, sp)
|
||||
}
|
||||
ty::BrAnon(span) => (
|
||||
"the anonymous lifetime as defined here".to_string(),
|
||||
match span {
|
||||
Some(span) => span,
|
||||
None => tcx.def_span(scope)
|
||||
}
|
||||
),
|
||||
_ => (
|
||||
format!("the lifetime `{}` as defined here", region),
|
||||
tcx.def_span(scope),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => bug!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_msg_span(
|
||||
err: &mut Diagnostic,
|
||||
prefix: &str,
|
||||
@ -398,7 +427,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
&self,
|
||||
generic_param_scope: LocalDefId,
|
||||
errors: &[RegionResolutionError<'tcx>],
|
||||
) {
|
||||
) -> ErrorGuaranteed {
|
||||
if let Some(guaranteed) = self.infcx.tainted_by_errors() {
|
||||
return guaranteed;
|
||||
}
|
||||
|
||||
debug!("report_region_errors(): {} errors to start", errors.len());
|
||||
|
||||
// try to pre-process the errors, which will group some of them
|
||||
@ -478,6 +511,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.tcx
|
||||
.sess
|
||||
.delay_span_bug(self.tcx.def_span(generic_param_scope), "expected region errors")
|
||||
}
|
||||
|
||||
// This method goes through all the errors and try to group certain types
|
||||
@ -1808,7 +1845,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
// will try to hide in some case such as `async fn`, so
|
||||
// to make an error more use friendly we will
|
||||
// avoid to suggest a mismatch type with a
|
||||
// type that the user usually are not usign
|
||||
// type that the user usually are not using
|
||||
// directly such as `impl Future<Output = u8>`.
|
||||
if !self.tcx.ty_is_opaque_future(found_ty) {
|
||||
diag.note_expected_found_extra(
|
||||
@ -1899,233 +1936,182 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
debug!(?diag);
|
||||
}
|
||||
|
||||
pub fn type_error_additional_suggestions(
|
||||
&self,
|
||||
trace: &TypeTrace<'tcx>,
|
||||
terr: TypeError<'tcx>,
|
||||
) -> Vec<TypeErrorAdditionalDiags> {
|
||||
use crate::traits::ObligationCauseCode::MatchExpressionArm;
|
||||
let mut suggestions = Vec::new();
|
||||
let span = trace.cause.span();
|
||||
let values = self.resolve_vars_if_possible(trace.values);
|
||||
if let Some((expected, found)) = values.ty() {
|
||||
match (expected.kind(), found.kind()) {
|
||||
(ty::Tuple(_), ty::Tuple(_)) => {}
|
||||
// If a tuple of length one was expected and the found expression has
|
||||
// parentheses around it, perhaps the user meant to write `(expr,)` to
|
||||
// build a tuple (issue #86100)
|
||||
(ty::Tuple(fields), _) => {
|
||||
suggestions.extend(self.suggest_wrap_to_build_a_tuple( span, found, fields))
|
||||
}
|
||||
// If a byte was expected and the found expression is a char literal
|
||||
// containing a single ASCII character, perhaps the user meant to write `b'c'` to
|
||||
// specify a byte literal
|
||||
(ty::Uint(ty::UintTy::U8), ty::Char) => {
|
||||
if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
|
||||
&& let Some(code) = code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
|
||||
&& !code.starts_with("\\u") // forbid all Unicode escapes
|
||||
&& code.chars().next().map_or(false, |c| c.is_ascii()) // forbids literal Unicode characters beyond ASCII
|
||||
{
|
||||
suggestions.push(TypeErrorAdditionalDiags::MeantByteLiteral { span, code: escape_literal(code) })
|
||||
}
|
||||
}
|
||||
// If a character was expected and the found expression is a string literal
|
||||
// containing a single character, perhaps the user meant to write `'c'` to
|
||||
// specify a character literal (issue #92479)
|
||||
(ty::Char, ty::Ref(_, r, _)) if r.is_str() => {
|
||||
if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
|
||||
&& let Some(code) = code.strip_prefix('"').and_then(|s| s.strip_suffix('"'))
|
||||
&& code.chars().count() == 1
|
||||
{
|
||||
suggestions.push(TypeErrorAdditionalDiags::MeantCharLiteral { span, code: escape_literal(code) })
|
||||
}
|
||||
}
|
||||
// If a string was expected and the found expression is a character literal,
|
||||
// perhaps the user meant to write `"s"` to specify a string literal.
|
||||
(ty::Ref(_, r, _), ty::Char) if r.is_str() => {
|
||||
if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
|
||||
if let Some(code) =
|
||||
code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
|
||||
{
|
||||
suggestions.push(TypeErrorAdditionalDiags::MeantStrLiteral { span, code: escape_literal(code) })
|
||||
}
|
||||
}
|
||||
}
|
||||
// For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`,
|
||||
// we try to suggest to add the missing `let` for `if let Some(..) = expr`
|
||||
(ty::Bool, ty::Tuple(list)) => if list.len() == 0 {
|
||||
suggestions.extend(self.suggest_let_for_letchains(&trace.cause, span));
|
||||
}
|
||||
(ty::Array(_, _), ty::Array(_, _)) => suggestions.extend(self.suggest_specify_actual_length(terr, trace, span)),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
let code = trace.cause.code();
|
||||
if let &MatchExpressionArm(box MatchExpressionArmCause { source, .. }) = code
|
||||
&& let hir::MatchSource::TryDesugar = source
|
||||
&& let Some((expected_ty, found_ty, _, _)) = self.values_str(trace.values)
|
||||
{
|
||||
suggestions.push(TypeErrorAdditionalDiags::TryCannotConvert { found: found_ty.content(), expected: expected_ty.content() });
|
||||
}
|
||||
suggestions
|
||||
}
|
||||
|
||||
fn suggest_specify_actual_length(
|
||||
&self,
|
||||
terr: TypeError<'_>,
|
||||
trace: &TypeTrace<'_>,
|
||||
span: Span,
|
||||
) -> Option<TypeErrorAdditionalDiags> {
|
||||
let hir = self.tcx.hir();
|
||||
let TypeError::FixedArraySize(sz) = terr else {
|
||||
return None;
|
||||
};
|
||||
let tykind = match hir.find_by_def_id(trace.cause.body_id) {
|
||||
Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) => {
|
||||
let body = hir.body(*body_id);
|
||||
struct LetVisitor<'v> {
|
||||
span: Span,
|
||||
result: Option<&'v hir::Ty<'v>>,
|
||||
}
|
||||
impl<'v> Visitor<'v> for LetVisitor<'v> {
|
||||
fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) {
|
||||
if self.result.is_some() {
|
||||
return;
|
||||
}
|
||||
// Find a local statement where the initializer has
|
||||
// the same span as the error and the type is specified.
|
||||
if let hir::Stmt {
|
||||
kind: hir::StmtKind::Local(hir::Local {
|
||||
init: Some(hir::Expr {
|
||||
span: init_span,
|
||||
..
|
||||
}),
|
||||
ty: Some(array_ty),
|
||||
..
|
||||
}),
|
||||
..
|
||||
} = s
|
||||
&& init_span == &self.span {
|
||||
self.result = Some(*array_ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut visitor = LetVisitor { span, result: None };
|
||||
visitor.visit_body(body);
|
||||
visitor.result.map(|r| &r.peel_refs().kind)
|
||||
}
|
||||
Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _), .. })) => {
|
||||
Some(&ty.peel_refs().kind)
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
if let Some(tykind) = tykind
|
||||
&& let hir::TyKind::Array(_, length) = tykind
|
||||
&& let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length
|
||||
&& let Some(span) = self.tcx.hir().opt_span(*hir_id)
|
||||
{
|
||||
Some(TypeErrorAdditionalDiags::ConsiderSpecifyingLength { span, length: sz.found })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn report_and_explain_type_error(
|
||||
&self,
|
||||
trace: TypeTrace<'tcx>,
|
||||
terr: TypeError<'tcx>,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
use crate::traits::ObligationCauseCode::MatchExpressionArm;
|
||||
|
||||
debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr);
|
||||
|
||||
let span = trace.cause.span();
|
||||
let failure_code = trace.cause.as_failure_code(terr);
|
||||
let mut diag = match failure_code {
|
||||
FailureCode::Error0038(did) => {
|
||||
let violations = self.tcx.object_safety_violations(did);
|
||||
report_object_safety_error(self.tcx, span, did, violations)
|
||||
}
|
||||
FailureCode::Error0317(failure_str) => {
|
||||
struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str)
|
||||
}
|
||||
FailureCode::Error0580(failure_str) => {
|
||||
struct_span_err!(self.tcx.sess, span, E0580, "{}", failure_str)
|
||||
}
|
||||
FailureCode::Error0308(failure_str) => {
|
||||
fn escape_literal(s: &str) -> String {
|
||||
let mut escaped = String::with_capacity(s.len());
|
||||
let mut chrs = s.chars().peekable();
|
||||
while let Some(first) = chrs.next() {
|
||||
match (first, chrs.peek()) {
|
||||
('\\', Some(&delim @ '"') | Some(&delim @ '\'')) => {
|
||||
escaped.push('\\');
|
||||
escaped.push(delim);
|
||||
chrs.next();
|
||||
}
|
||||
('"' | '\'', _) => {
|
||||
escaped.push('\\');
|
||||
escaped.push(first)
|
||||
}
|
||||
(c, _) => escaped.push(c),
|
||||
};
|
||||
}
|
||||
escaped
|
||||
}
|
||||
let mut err = struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str);
|
||||
let values = self.resolve_vars_if_possible(trace.values);
|
||||
if let Some((expected, found)) = values.ty() {
|
||||
match (expected.kind(), found.kind()) {
|
||||
(ty::Tuple(_), ty::Tuple(_)) => {}
|
||||
// If a tuple of length one was expected and the found expression has
|
||||
// parentheses around it, perhaps the user meant to write `(expr,)` to
|
||||
// build a tuple (issue #86100)
|
||||
(ty::Tuple(fields), _) => {
|
||||
self.emit_tuple_wrap_err(&mut err, span, found, fields)
|
||||
}
|
||||
// If a byte was expected and the found expression is a char literal
|
||||
// containing a single ASCII character, perhaps the user meant to write `b'c'` to
|
||||
// specify a byte literal
|
||||
(ty::Uint(ty::UintTy::U8), ty::Char) => {
|
||||
if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
|
||||
&& let Some(code) = code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
|
||||
&& !code.starts_with("\\u") // forbid all Unicode escapes
|
||||
&& code.chars().next().map_or(false, |c| c.is_ascii()) // forbids literal Unicode characters beyond ASCII
|
||||
{
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"if you meant to write a byte literal, prefix with `b`",
|
||||
format!("b'{}'", escape_literal(code)),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
// If a character was expected and the found expression is a string literal
|
||||
// containing a single character, perhaps the user meant to write `'c'` to
|
||||
// specify a character literal (issue #92479)
|
||||
(ty::Char, ty::Ref(_, r, _)) if r.is_str() => {
|
||||
if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
|
||||
&& let Some(code) = code.strip_prefix('"').and_then(|s| s.strip_suffix('"'))
|
||||
&& code.chars().count() == 1
|
||||
{
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"if you meant to write a `char` literal, use single quotes",
|
||||
format!("'{}'", escape_literal(code)),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
// If a string was expected and the found expression is a character literal,
|
||||
// perhaps the user meant to write `"s"` to specify a string literal.
|
||||
(ty::Ref(_, r, _), ty::Char) if r.is_str() => {
|
||||
if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
|
||||
if let Some(code) =
|
||||
code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
|
||||
{
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"if you meant to write a `str` literal, use double quotes",
|
||||
format!("\"{}\"", escape_literal(code)),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`,
|
||||
// we try to suggest to add the missing `let` for `if let Some(..) = expr`
|
||||
(ty::Bool, ty::Tuple(list)) => if list.len() == 0 {
|
||||
self.suggest_let_for_letchains(&mut err, &trace.cause, span);
|
||||
}
|
||||
(ty::Array(_, _), ty::Array(_, _)) => 'block: {
|
||||
let hir = self.tcx.hir();
|
||||
let TypeError::FixedArraySize(sz) = terr else {
|
||||
break 'block;
|
||||
};
|
||||
let tykind = match hir.find_by_def_id(trace.cause.body_id) {
|
||||
Some(hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Fn(_, _, body_id),
|
||||
..
|
||||
})) => {
|
||||
let body = hir.body(*body_id);
|
||||
struct LetVisitor<'v> {
|
||||
span: Span,
|
||||
result: Option<&'v hir::Ty<'v>>,
|
||||
}
|
||||
impl<'v> Visitor<'v> for LetVisitor<'v> {
|
||||
fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) {
|
||||
if self.result.is_some() {
|
||||
return;
|
||||
}
|
||||
// Find a local statement where the initializer has
|
||||
// the same span as the error and the type is specified.
|
||||
if let hir::Stmt {
|
||||
kind: hir::StmtKind::Local(hir::Local {
|
||||
init: Some(hir::Expr {
|
||||
span: init_span,
|
||||
..
|
||||
}),
|
||||
ty: Some(array_ty),
|
||||
..
|
||||
}),
|
||||
..
|
||||
} = s
|
||||
&& init_span == &self.span {
|
||||
self.result = Some(*array_ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut visitor = LetVisitor {span, result: None};
|
||||
visitor.visit_body(body);
|
||||
visitor.result.map(|r| &r.peel_refs().kind)
|
||||
}
|
||||
Some(hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Const(ty, _),
|
||||
..
|
||||
})) => {
|
||||
Some(&ty.peel_refs().kind)
|
||||
}
|
||||
_ => None
|
||||
};
|
||||
|
||||
if let Some(tykind) = tykind
|
||||
&& let hir::TyKind::Array(_, length) = tykind
|
||||
&& let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length
|
||||
&& let Some(span) = self.tcx.hir().opt_span(*hir_id)
|
||||
{
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"consider specifying the actual array length",
|
||||
sz.found,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
let code = trace.cause.code();
|
||||
if let &MatchExpressionArm(box MatchExpressionArmCause { source, .. }) = code
|
||||
&& let hir::MatchSource::TryDesugar = source
|
||||
&& let Some((expected_ty, found_ty, _, _)) = self.values_str(trace.values)
|
||||
{
|
||||
err.note(&format!(
|
||||
"`?` operator cannot convert from `{}` to `{}`",
|
||||
found_ty.content(),
|
||||
expected_ty.content(),
|
||||
));
|
||||
}
|
||||
err
|
||||
}
|
||||
FailureCode::Error0644(failure_str) => {
|
||||
struct_span_err!(self.tcx.sess, span, E0644, "{}", failure_str)
|
||||
}
|
||||
};
|
||||
let failure_code = trace.cause.as_failure_code_diag(
|
||||
terr,
|
||||
span,
|
||||
self.type_error_additional_suggestions(&trace, terr),
|
||||
);
|
||||
let mut diag = self.tcx.sess.create_err(failure_code);
|
||||
self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr, false, false);
|
||||
diag
|
||||
}
|
||||
|
||||
fn emit_tuple_wrap_err(
|
||||
fn suggest_wrap_to_build_a_tuple(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
span: Span,
|
||||
found: Ty<'tcx>,
|
||||
expected_fields: &List<Ty<'tcx>>,
|
||||
) {
|
||||
let [expected_tup_elem] = expected_fields[..] else { return };
|
||||
) -> Option<TypeErrorAdditionalDiags> {
|
||||
let [expected_tup_elem] = expected_fields[..] else { return None};
|
||||
|
||||
if !self.same_type_modulo_infer(expected_tup_elem, found) {
|
||||
return;
|
||||
return None;
|
||||
}
|
||||
|
||||
let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
|
||||
else { return };
|
||||
else { return None };
|
||||
|
||||
let msg = "use a trailing comma to create a tuple with one element";
|
||||
if code.starts_with('(') && code.ends_with(')') {
|
||||
let sugg = if code.starts_with('(') && code.ends_with(')') {
|
||||
let before_close = span.hi() - BytePos::from_u32(1);
|
||||
err.span_suggestion(
|
||||
span.with_hi(before_close).shrink_to_hi(),
|
||||
msg,
|
||||
",",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
TypeErrorAdditionalDiags::TupleOnlyComma {
|
||||
span: span.with_hi(before_close).shrink_to_hi(),
|
||||
}
|
||||
} else {
|
||||
err.multipart_suggestion(
|
||||
msg,
|
||||
vec![(span.shrink_to_lo(), "(".into()), (span.shrink_to_hi(), ",)".into())],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
TypeErrorAdditionalDiags::TupleAlsoParentheses {
|
||||
span_low: span.shrink_to_lo(),
|
||||
span_high: span.shrink_to_hi(),
|
||||
}
|
||||
};
|
||||
Some(sugg)
|
||||
}
|
||||
|
||||
fn values_str(
|
||||
@ -2828,57 +2814,91 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
}
|
||||
|
||||
pub enum FailureCode {
|
||||
Error0038(DefId),
|
||||
Error0317(&'static str),
|
||||
Error0580(&'static str),
|
||||
Error0308(&'static str),
|
||||
Error0644(&'static str),
|
||||
Error0317,
|
||||
Error0580,
|
||||
Error0308,
|
||||
Error0644,
|
||||
}
|
||||
|
||||
pub trait ObligationCauseExt<'tcx> {
|
||||
fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode;
|
||||
|
||||
fn as_failure_code_diag(
|
||||
&self,
|
||||
terr: TypeError<'tcx>,
|
||||
span: Span,
|
||||
subdiags: Vec<TypeErrorAdditionalDiags>,
|
||||
) -> ObligationCauseFailureCode;
|
||||
fn as_requirement_str(&self) -> &'static str;
|
||||
}
|
||||
|
||||
impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
|
||||
fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode {
|
||||
use self::FailureCode::*;
|
||||
use crate::traits::ObligationCauseCode::*;
|
||||
match self.code() {
|
||||
IfExpressionWithNoElse => Error0317,
|
||||
MainFunctionType => Error0580,
|
||||
CompareImplItemObligation { .. }
|
||||
| MatchExpressionArm(_)
|
||||
| IfExpression { .. }
|
||||
| LetElse
|
||||
| StartFunctionType
|
||||
| IntrinsicType
|
||||
| MethodReceiver => Error0308,
|
||||
|
||||
// In the case where we have no more specific thing to
|
||||
// say, also take a look at the error code, maybe we can
|
||||
// tailor to that.
|
||||
_ => match terr {
|
||||
TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() => Error0644,
|
||||
TypeError::IntrinsicCast => Error0308,
|
||||
_ => Error0308,
|
||||
},
|
||||
}
|
||||
}
|
||||
fn as_failure_code_diag(
|
||||
&self,
|
||||
terr: TypeError<'tcx>,
|
||||
span: Span,
|
||||
subdiags: Vec<TypeErrorAdditionalDiags>,
|
||||
) -> ObligationCauseFailureCode {
|
||||
use crate::traits::ObligationCauseCode::*;
|
||||
match self.code() {
|
||||
CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => {
|
||||
Error0308("method not compatible with trait")
|
||||
ObligationCauseFailureCode::MethodCompat { span, subdiags }
|
||||
}
|
||||
CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => {
|
||||
Error0308("type not compatible with trait")
|
||||
ObligationCauseFailureCode::TypeCompat { span, subdiags }
|
||||
}
|
||||
CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => {
|
||||
Error0308("const not compatible with trait")
|
||||
ObligationCauseFailureCode::ConstCompat { span, subdiags }
|
||||
}
|
||||
MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => {
|
||||
Error0308(match source {
|
||||
hir::MatchSource::TryDesugar => "`?` operator has incompatible types",
|
||||
_ => "`match` arms have incompatible types",
|
||||
})
|
||||
}
|
||||
IfExpression { .. } => Error0308("`if` and `else` have incompatible types"),
|
||||
IfExpressionWithNoElse => Error0317("`if` may be missing an `else` clause"),
|
||||
LetElse => Error0308("`else` clause of `let...else` does not diverge"),
|
||||
MainFunctionType => Error0580("`main` function has wrong type"),
|
||||
StartFunctionType => Error0308("`#[start]` function has wrong type"),
|
||||
IntrinsicType => Error0308("intrinsic has wrong type"),
|
||||
MethodReceiver => Error0308("mismatched `self` parameter type"),
|
||||
MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => match source {
|
||||
hir::MatchSource::TryDesugar => {
|
||||
ObligationCauseFailureCode::TryCompat { span, subdiags }
|
||||
}
|
||||
_ => ObligationCauseFailureCode::MatchCompat { span, subdiags },
|
||||
},
|
||||
IfExpression { .. } => ObligationCauseFailureCode::IfElseDifferent { span, subdiags },
|
||||
IfExpressionWithNoElse => ObligationCauseFailureCode::NoElse { span },
|
||||
LetElse => ObligationCauseFailureCode::NoDiverge { span, subdiags },
|
||||
MainFunctionType => ObligationCauseFailureCode::FnMainCorrectType { span },
|
||||
StartFunctionType => ObligationCauseFailureCode::FnStartCorrectType { span, subdiags },
|
||||
IntrinsicType => ObligationCauseFailureCode::IntristicCorrectType { span, subdiags },
|
||||
MethodReceiver => ObligationCauseFailureCode::MethodCorrectType { span, subdiags },
|
||||
|
||||
// In the case where we have no more specific thing to
|
||||
// say, also take a look at the error code, maybe we can
|
||||
// tailor to that.
|
||||
_ => match terr {
|
||||
TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() => {
|
||||
Error0644("closure/generator type that references itself")
|
||||
ObligationCauseFailureCode::ClosureSelfref { span }
|
||||
}
|
||||
TypeError::IntrinsicCast => {
|
||||
Error0308("cannot coerce intrinsics to function pointers")
|
||||
ObligationCauseFailureCode::CantCoerce { span, subdiags }
|
||||
}
|
||||
_ => Error0308("mismatched types"),
|
||||
_ => ObligationCauseFailureCode::Generic { span, subdiags },
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::errors::{
|
||||
AmbigousImpl, AmbigousReturn, AnnotationRequired, InferenceBadError, NeedTypeInfoInGenerator,
|
||||
AmbigousReturn, AmbiguousImpl, AnnotationRequired, InferenceBadError, NeedTypeInfoInGenerator,
|
||||
SourceKindMultiSuggestion, SourceKindSubdiag,
|
||||
};
|
||||
use crate::infer::error_reporting::TypeErrCtxt;
|
||||
@ -358,7 +358,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
bad_label,
|
||||
}
|
||||
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
|
||||
TypeAnnotationNeeded::E0283 => AmbigousImpl {
|
||||
TypeAnnotationNeeded::E0283 => AmbiguousImpl {
|
||||
span,
|
||||
source_kind,
|
||||
source_name,
|
||||
@ -563,7 +563,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
bad_label: None,
|
||||
}
|
||||
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
|
||||
TypeAnnotationNeeded::E0283 => AmbigousImpl {
|
||||
TypeAnnotationNeeded::E0283 => AmbiguousImpl {
|
||||
span,
|
||||
source_kind,
|
||||
source_name: &name,
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::errors::{
|
||||
note_and_explain, FullfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent,
|
||||
note_and_explain, FulfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent,
|
||||
RefLongerThanData, RegionOriginNote, WhereClauseSuggestions,
|
||||
};
|
||||
use crate::fluent_generated as fluent;
|
||||
@ -176,7 +176,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
let note = note_and_explain::RegionExplanation::new(
|
||||
self.tcx, sub, opt_span, prefix, suffix,
|
||||
);
|
||||
FullfillReqLifetime { span, ty: self.resolve_vars_if_possible(ty), note }
|
||||
FulfillReqLifetime { span, ty: self.resolve_vars_if_possible(ty), note }
|
||||
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic)
|
||||
}
|
||||
infer::RelateRegionParamBound(span) => {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user