Merge pull request #4349 from rust-lang/rustup-2025-05-25
Automatic Rustup
This commit is contained in:
commit
0e5a162b08
290 changed files with 4000 additions and 2429 deletions
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
|
|
@ -234,8 +234,8 @@ jobs:
|
|||
fi
|
||||
exit ${STATUS}
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: ${{ env.CACHES_AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}
|
||||
AWS_ACCESS_KEY_ID: ${{ (github.repository == 'rust-lang/rust' && secrets.CACHES_AWS_ACCESS_KEY_ID) || env.CACHES_AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ (github.repository == 'rust-lang/rust' && secrets.CACHES_AWS_SECRET_ACCESS_KEY) || secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}
|
||||
|
||||
- name: create github artifacts
|
||||
run: src/ci/scripts/create-doc-artifacts.sh
|
||||
|
|
@ -257,8 +257,8 @@ jobs:
|
|||
- name: upload artifacts to S3
|
||||
run: src/ci/scripts/upload-artifacts.sh
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: ${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}
|
||||
AWS_ACCESS_KEY_ID: ${{ (github.repository == 'rust-lang/rust' && secrets.ARTIFACTS_AWS_ACCESS_KEY_ID) || env.ARTIFACTS_AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ (github.repository == 'rust-lang/rust' && secrets.ARTIFACTS_AWS_SECRET_ACCESS_KEY) || secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}
|
||||
# Adding a condition on DEPLOY=1 or DEPLOY_ALT=1 is not needed as all deploy
|
||||
# builders *should* have the AWS credentials available. Still, explicitly
|
||||
# adding the condition is helpful as this way CI will not silently skip
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ and we appreciate all of them.
|
|||
|
||||
The best way to get started is by asking for help in the [#new
|
||||
members](https://rust-lang.zulipchat.com/#narrow/stream/122652-new-members)
|
||||
Zulip stream. We have lots of docs below of how to get started on your own, but
|
||||
Zulip stream. We have a lot of documentation below on how to get started on your own, but
|
||||
the Zulip stream is the best place to *ask* for help.
|
||||
|
||||
Documentation for contributing to the compiler or tooling is located in the [Guide to Rustc
|
||||
|
|
@ -14,7 +14,7 @@ standard library in the [Standard library developers Guide][std-dev-guide], comm
|
|||
|
||||
## Making changes to subtrees and submodules
|
||||
|
||||
For submodules, changes need to be made against the repository corresponding the
|
||||
For submodules, changes need to be made against the repository corresponding to the
|
||||
submodule, and not the main `rust-lang/rust` repository.
|
||||
|
||||
For subtrees, prefer sending a PR against the subtree's repository if it does
|
||||
|
|
@ -25,7 +25,7 @@ rustc-dev-guide change that does not accompany a compiler change).
|
|||
|
||||
The [rustc-dev-guide] is meant to help document how rustc –the Rust compiler– works,
|
||||
as well as to help new contributors get involved in rustc development. It is recommended
|
||||
to read and understand the [rustc-dev-guide] before making a contribution. This guide
|
||||
that you read and understand the [rustc-dev-guide] before making a contribution. This guide
|
||||
talks about the different bots in the Rust ecosystem, the Rust development tools,
|
||||
bootstrapping, the compiler architecture, source code representation, and more.
|
||||
|
||||
|
|
@ -33,7 +33,7 @@ bootstrapping, the compiler architecture, source code representation, and more.
|
|||
|
||||
There are many ways you can get help when you're stuck. Rust has many platforms for this:
|
||||
[internals], [rust-zulip], and [rust-discord]. It is recommended to ask for help on
|
||||
the [rust-zulip], but any of these platforms are a great way to seek help and even
|
||||
the [rust-zulip], but any of these platforms are great ways to seek help and even
|
||||
find a mentor! You can learn more about asking questions and getting help in the
|
||||
[Asking Questions](https://rustc-dev-guide.rust-lang.org/getting-started.html#asking-questions) chapter of the [rustc-dev-guide].
|
||||
|
||||
|
|
|
|||
52
Cargo.lock
52
Cargo.lock
|
|
@ -183,7 +183,20 @@ version = "0.13.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d4744ed2eef2645831b441d8f5459689ade2ab27c854488fbab1fbe94fce1a7"
|
||||
dependencies = [
|
||||
"askama_derive",
|
||||
"askama_derive 0.13.1",
|
||||
"itoa",
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4"
|
||||
dependencies = [
|
||||
"askama_derive 0.14.0",
|
||||
"itoa",
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
|
|
@ -196,7 +209,24 @@ version = "0.13.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d661e0f57be36a5c14c48f78d09011e67e0cb618f269cca9f2fd8d15b68c46ac"
|
||||
dependencies = [
|
||||
"askama_parser",
|
||||
"askama_parser 0.13.0",
|
||||
"basic-toml",
|
||||
"memchr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc-hash 2.1.1",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_derive"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f"
|
||||
dependencies = [
|
||||
"askama_parser 0.14.0",
|
||||
"basic-toml",
|
||||
"memchr",
|
||||
"proc-macro2",
|
||||
|
|
@ -219,6 +249,18 @@ dependencies = [
|
|||
"winnow 0.7.10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_parser"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"winnow 0.7.10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.4.0"
|
||||
|
|
@ -540,7 +582,7 @@ name = "clippy"
|
|||
version = "0.1.89"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"askama",
|
||||
"askama 0.13.1",
|
||||
"cargo_metadata 0.18.1",
|
||||
"clippy_config",
|
||||
"clippy_lints",
|
||||
|
|
@ -1389,7 +1431,7 @@ name = "generate-copyright"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"askama",
|
||||
"askama 0.14.0",
|
||||
"cargo_metadata 0.18.1",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
@ -4622,7 +4664,7 @@ name = "rustdoc"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"askama",
|
||||
"askama 0.14.0",
|
||||
"base64",
|
||||
"expect-test",
|
||||
"indexmap",
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use rustc_ast::*;
|
|||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_hir as hir;
|
||||
use rustc_session::config::FmtDebug;
|
||||
use rustc_span::{Ident, Span, Symbol, kw, sym};
|
||||
use rustc_span::{Ident, Span, Symbol, sym};
|
||||
|
||||
use super::LoweringContext;
|
||||
|
||||
|
|
@ -418,7 +418,7 @@ fn expand_format_args<'hir>(
|
|||
&FormatArgsPiece::Placeholder(_) => {
|
||||
// Inject empty string before placeholders when not already preceded by a literal piece.
|
||||
if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_)) {
|
||||
Some(ctx.expr_str(fmt.span, kw::Empty))
|
||||
Some(ctx.expr_str(fmt.span, sym::empty))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,7 +131,8 @@ impl UniversalRegionRelations<'_> {
|
|||
assert!(self.universal_regions.is_universal_region(fr0));
|
||||
|
||||
let mut external_parents = vec![];
|
||||
let mut queue = vec![fr0];
|
||||
|
||||
let mut queue = vec![relation.minimal_scc_representative(fr0)];
|
||||
|
||||
// Keep expanding `fr` into its parents until we reach
|
||||
// non-local regions.
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ impl<'gcc, 'tcx> StaticCodegenMethods for CodegenCx<'gcc, 'tcx> {
|
|||
// TODO(antoyo): set link section.
|
||||
}
|
||||
|
||||
if attrs.flags.contains(CodegenFnAttrFlags::USED)
|
||||
if attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER)
|
||||
|| attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
|
||||
{
|
||||
self.add_used_global(global.to_rvalue());
|
||||
|
|
|
|||
|
|
@ -527,7 +527,7 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
|
||||
base::set_variable_sanitizer_attrs(g, attrs);
|
||||
|
||||
if attrs.flags.contains(CodegenFnAttrFlags::USED) {
|
||||
if attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) {
|
||||
// `USED` and `USED_LINKER` can't be used together.
|
||||
assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER));
|
||||
|
||||
|
|
@ -551,7 +551,7 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
}
|
||||
if attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) {
|
||||
// `USED` and `USED_LINKER` can't be used together.
|
||||
assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED));
|
||||
assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER));
|
||||
|
||||
self.add_used_global(g);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
codegen_ssa_L4Bender_exporting_symbols_unimplemented = exporting symbols not implemented yet for L4Bender
|
||||
|
||||
codegen_ssa_aarch64_softfloat_neon = enabling the `neon` target feature on the current target is unsound due to ABI issues
|
||||
|
||||
codegen_ssa_add_native_library = failed to add native library {$library_path}: {$error}
|
||||
|
||||
codegen_ssa_aix_strip_not_used = using host's `strip` binary to cross-compile to AIX which is not guaranteed to work
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S
|
|||
} else {
|
||||
SymbolExportKind::Text
|
||||
},
|
||||
used: codegen_attrs.flags.contains(CodegenFnAttrFlags::USED)
|
||||
used: codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER)
|
||||
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
|
||||
|| used,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
)
|
||||
.emit();
|
||||
}
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_COMPILER;
|
||||
}
|
||||
Some(_) => {
|
||||
tcx.dcx().emit_err(errors::ExpectedUsedSymbol { span: attr.span() });
|
||||
|
|
@ -220,7 +220,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
|| tcx.sess.target.is_like_windows
|
||||
|| tcx.sess.target.is_like_wasm);
|
||||
codegen_fn_attrs.flags |= if is_like_elf {
|
||||
CodegenFnAttrFlags::USED
|
||||
CodegenFnAttrFlags::USED_COMPILER
|
||||
} else {
|
||||
CodegenFnAttrFlags::USED_LINKER
|
||||
};
|
||||
|
|
@ -299,6 +299,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
}
|
||||
from_target_feature_attr(
|
||||
tcx,
|
||||
did,
|
||||
attr,
|
||||
rust_target_features,
|
||||
&mut codegen_fn_attrs.target_features,
|
||||
|
|
|
|||
|
|
@ -1316,3 +1316,7 @@ pub(crate) struct XcrunSdkPathWarning {
|
|||
pub sdk_name: &'static str,
|
||||
pub stderr: String,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(codegen_ssa_aarch64_softfloat_neon)]
|
||||
pub(crate) struct Aarch64SoftfloatNeon;
|
||||
|
|
|
|||
|
|
@ -1181,6 +1181,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
(_, Some(llfn)) => llfn,
|
||||
_ => span_bug!(span, "no instance or llfn for call"),
|
||||
};
|
||||
self.set_debug_loc(bx, mir::SourceInfo { span: fn_span, ..source_info });
|
||||
helper.do_call(
|
||||
self,
|
||||
bx,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
|
|||
use rustc_middle::ty::{Instance, Ty};
|
||||
use rustc_middle::{bug, mir, ty};
|
||||
use rustc_session::config::DebugInfo;
|
||||
use rustc_span::{BytePos, Span, Symbol, hygiene, kw};
|
||||
use rustc_span::{BytePos, Span, Symbol, hygiene, sym};
|
||||
|
||||
use super::operand::{OperandRef, OperandValue};
|
||||
use super::place::{PlaceRef, PlaceValue};
|
||||
|
|
@ -283,7 +283,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
// (after #67586 gets fixed).
|
||||
None
|
||||
} else {
|
||||
let name = kw::Empty;
|
||||
let name = sym::empty;
|
||||
let decl = &self.mir.local_decls[local];
|
||||
let dbg_var = if full_debug_info {
|
||||
self.adjusted_span_and_dbg_scope(decl.source_info).map(
|
||||
|
|
@ -318,7 +318,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
None
|
||||
} else {
|
||||
Some(match whole_local_var.or(fallback_var.clone()) {
|
||||
Some(var) if var.name != kw::Empty => var.name.to_string(),
|
||||
Some(var) if var.name != sym::empty => var.name.to_string(),
|
||||
_ => format!("{local:?}"),
|
||||
})
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
|
|||
use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
use rustc_target::target_features::{self, Stability};
|
||||
|
|
@ -18,6 +19,7 @@ use crate::errors;
|
|||
/// Enabled target features are added to `target_features`.
|
||||
pub(crate) fn from_target_feature_attr(
|
||||
tcx: TyCtxt<'_>,
|
||||
did: LocalDefId,
|
||||
attr: &hir::Attribute,
|
||||
rust_target_features: &UnordMap<String, target_features::Stability>,
|
||||
target_features: &mut Vec<TargetFeature>,
|
||||
|
|
@ -92,11 +94,22 @@ pub(crate) fn from_target_feature_attr(
|
|||
// generating code so "it's fine".
|
||||
if !tcx.sess.opts.actually_rustdoc {
|
||||
if abi_feature_constraints.incompatible.contains(&name.as_str()) {
|
||||
tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
|
||||
span: item.span(),
|
||||
feature: name.as_str(),
|
||||
reason: "this feature is incompatible with the target ABI",
|
||||
});
|
||||
// For "neon" specifically, we emit an FCW instead of a hard error.
|
||||
// See <https://github.com/rust-lang/rust/issues/134375>.
|
||||
if tcx.sess.target.arch == "aarch64" && name.as_str() == "neon" {
|
||||
tcx.emit_node_span_lint(
|
||||
AARCH64_SOFTFLOAT_NEON,
|
||||
tcx.local_def_id_to_hir_id(did),
|
||||
item.span(),
|
||||
errors::Aarch64SoftfloatNeon,
|
||||
);
|
||||
} else {
|
||||
tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
|
||||
span: item.span(),
|
||||
feature: name.as_str(),
|
||||
reason: "this feature is incompatible with the target ABI",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
target_features.push(TargetFeature { name, implied: name != feature_sym })
|
||||
|
|
|
|||
|
|
@ -354,6 +354,20 @@ impl<T: Eq + Hash + Copy> TransitiveRelation<T> {
|
|||
.collect()
|
||||
}
|
||||
|
||||
/// Given an element A, elements B with the lowest index such that `A R B`
|
||||
/// and `B R A`, or `A` if no such element exists.
|
||||
pub fn minimal_scc_representative(&self, a: T) -> T {
|
||||
match self.index(a) {
|
||||
Some(a_i) => self.with_closure(|closure| {
|
||||
closure
|
||||
.iter(a_i.0)
|
||||
.find(|i| closure.contains(*i, a_i.0))
|
||||
.map_or(a, |i| self.elements[i])
|
||||
}),
|
||||
None => a,
|
||||
}
|
||||
}
|
||||
|
||||
fn with_closure<OP, R>(&self, op: OP) -> R
|
||||
where
|
||||
OP: FnOnce(&BitMatrix<usize, usize>) -> R,
|
||||
|
|
|
|||
|
|
@ -376,3 +376,44 @@ fn parent() {
|
|||
let p = relation.postdom_parent(3);
|
||||
assert_eq!(p, Some(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn minimal_scc_representative_1() {
|
||||
// +---------+
|
||||
// v |
|
||||
// a -> c -> d -> e
|
||||
// ^ ^
|
||||
// | |
|
||||
// b ---+
|
||||
|
||||
// "digraph { a -> c -> d -> e -> c; b -> d; b -> e; }",
|
||||
let mut relation = TransitiveRelationBuilder::default();
|
||||
relation.add("a", "c");
|
||||
relation.add("c", "d");
|
||||
relation.add("d", "e");
|
||||
relation.add("e", "c");
|
||||
relation.add("b", "d");
|
||||
relation.add("b", "e");
|
||||
let relation = relation.freeze();
|
||||
|
||||
assert_eq!(relation.minimal_scc_representative("a"), "a");
|
||||
assert_eq!(relation.minimal_scc_representative("b"), "b");
|
||||
assert_eq!(relation.minimal_scc_representative("c"), "c");
|
||||
assert_eq!(relation.minimal_scc_representative("d"), "c");
|
||||
assert_eq!(relation.minimal_scc_representative("e"), "c");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn minimal_scc_representative_2() {
|
||||
// "digraph { a -> b; a -> a; b -> a; c -> c}",
|
||||
let mut relation = TransitiveRelationBuilder::default();
|
||||
relation.add("a", "b");
|
||||
relation.add("b", "a");
|
||||
relation.add("a", "a");
|
||||
relation.add("c", "c");
|
||||
let relation = relation.freeze();
|
||||
|
||||
assert_eq!(relation.minimal_scc_representative("a"), "a");
|
||||
assert_eq!(relation.minimal_scc_representative("b"), "a");
|
||||
assert_eq!(relation.minimal_scc_representative("c"), "c");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ impl From<Ident> for LifetimeSyntax {
|
|||
fn from(ident: Ident) -> Self {
|
||||
let name = ident.name;
|
||||
|
||||
if name == kw::Empty {
|
||||
if name == sym::empty {
|
||||
unreachable!("A lifetime name should never be empty");
|
||||
} else if name == kw::UnderscoreLifetime {
|
||||
LifetimeSyntax::Anonymous
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ hir_analysis_assoc_kind_mismatch = expected {$expected}, found {$got}
|
|||
|
||||
hir_analysis_assoc_kind_mismatch_wrap_in_braces_sugg = consider adding braces here
|
||||
|
||||
hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the associated {$what} of a trait with uninferred generic parameters
|
||||
hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the {$what} of a trait with uninferred generic parameters
|
||||
.suggestion = use a fully qualified path with inferred lifetimes
|
||||
|
||||
hir_analysis_associated_type_trait_uninferred_generic_params_multipart_suggestion = use a fully qualified path with explicit lifetimes
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ use rustc_trait_selection::traits::ObligationCtxt;
|
|||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::errors;
|
||||
use crate::hir_ty_lowering::errors::assoc_tag_str;
|
||||
use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason};
|
||||
|
||||
pub(crate) mod dump;
|
||||
|
|
@ -89,6 +88,7 @@ pub(crate) fn provide(providers: &mut Providers) {
|
|||
opaque_ty_origin,
|
||||
rendered_precise_capturing_args,
|
||||
const_param_default,
|
||||
anon_const_kind,
|
||||
..*providers
|
||||
};
|
||||
}
|
||||
|
|
@ -444,13 +444,12 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
|
|||
self.tcx.at(span).type_param_predicates((self.item_def_id, def_id, assoc_ident))
|
||||
}
|
||||
|
||||
fn lower_assoc_shared(
|
||||
fn lower_assoc_item_path(
|
||||
&self,
|
||||
span: Span,
|
||||
item_def_id: DefId,
|
||||
item_segment: &rustc_hir::PathSegment<'tcx>,
|
||||
poly_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
assoc_tag: ty::AssocTag,
|
||||
) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> {
|
||||
if let Some(trait_ref) = poly_trait_ref.no_bound_vars() {
|
||||
let item_args = self.lowerer().lower_generic_args_of_assoc_item(
|
||||
|
|
@ -525,7 +524,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
|
|||
inferred_sugg,
|
||||
bound,
|
||||
mpart_sugg,
|
||||
what: assoc_tag_str(assoc_tag),
|
||||
what: self.tcx.def_descr(item_def_id),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
|
@ -1828,3 +1827,27 @@ fn const_param_default<'tcx>(
|
|||
.lower_const_arg(default_ct, FeedConstTy::Param(def_id.to_def_id(), identity_args));
|
||||
ty::EarlyBinder::bind(ct)
|
||||
}
|
||||
|
||||
fn anon_const_kind<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ty::AnonConstKind {
|
||||
let hir_id = tcx.local_def_id_to_hir_id(def);
|
||||
let const_arg_id = tcx.parent_hir_id(hir_id);
|
||||
match tcx.hir_node(const_arg_id) {
|
||||
hir::Node::ConstArg(_) => {
|
||||
if tcx.features().generic_const_exprs() {
|
||||
ty::AnonConstKind::GCE
|
||||
} else if tcx.features().min_generic_const_args() {
|
||||
ty::AnonConstKind::MCG
|
||||
} else if let hir::Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::Repeat(_, repeat_count),
|
||||
..
|
||||
}) = tcx.hir_node(tcx.parent_hir_id(const_arg_id))
|
||||
&& repeat_count.hir_id == const_arg_id
|
||||
{
|
||||
ty::AnonConstKind::RepeatExprCount
|
||||
} else {
|
||||
ty::AnonConstKind::MCG
|
||||
}
|
||||
}
|
||||
_ => ty::AnonConstKind::NonTypeSystem,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,19 +104,27 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
|||
}
|
||||
}
|
||||
|
||||
if in_param_ty {
|
||||
// We do not allow generic parameters in anon consts if we are inside
|
||||
// of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
|
||||
None
|
||||
} else if tcx.features().generic_const_exprs() {
|
||||
let parent_node = tcx.parent_hir_node(hir_id);
|
||||
debug!(?parent_node);
|
||||
if let Node::Variant(Variant { disr_expr: Some(constant), .. }) = parent_node
|
||||
&& constant.hir_id == hir_id
|
||||
{
|
||||
// enum variant discriminants are not allowed to use any kind of generics
|
||||
None
|
||||
} else if let Some(param_id) = tcx.hir_opt_const_param_default_param_def_id(hir_id)
|
||||
match tcx.anon_const_kind(def_id) {
|
||||
// Stable: anon consts are not able to use any generic parameters...
|
||||
ty::AnonConstKind::MCG => None,
|
||||
// we provide generics to repeat expr counts as a backwards compatibility hack. #76200
|
||||
ty::AnonConstKind::RepeatExprCount => Some(parent_did),
|
||||
|
||||
// Even GCE anon const should not be allowed to use generic parameters as it would be
|
||||
// trivially forward declared uses once desugared. E.g. `const N: [u8; ANON::<N>]`.
|
||||
//
|
||||
// We could potentially mirror the hack done for defaults of generic parameters but
|
||||
// this case just doesn't come up much compared to `const N: u32 = ...`. Long term the
|
||||
// hack for defaulted parameters should be removed eventually anyway.
|
||||
ty::AnonConstKind::GCE if in_param_ty => None,
|
||||
// GCE anon consts as a default for a generic parameter should have their provided generics
|
||||
// "truncated" up to whatever generic parameter this anon const is within the default of.
|
||||
//
|
||||
// FIXME(generic_const_exprs): This only handles `const N: usize = /*defid*/` but not type
|
||||
// parameter defaults, e.g. `T = Foo</*defid*/>`.
|
||||
ty::AnonConstKind::GCE
|
||||
if let Some(param_id) =
|
||||
tcx.hir_opt_const_param_default_param_def_id(hir_id) =>
|
||||
{
|
||||
// If the def_id we are calling generics_of on is an anon ct default i.e:
|
||||
//
|
||||
|
|
@ -160,36 +168,17 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
|||
has_self: generics.has_self,
|
||||
has_late_bound_regions: generics.has_late_bound_regions,
|
||||
};
|
||||
} else {
|
||||
// HACK(eddyb) this provides the correct generics when
|
||||
// `feature(generic_const_expressions)` is enabled, so that const expressions
|
||||
// used with const generics, e.g. `Foo<{N+1}>`, can work at all.
|
||||
//
|
||||
// Note that we do not supply the parent generics when using
|
||||
// `min_const_generics`.
|
||||
}
|
||||
ty::AnonConstKind::GCE => Some(parent_did),
|
||||
|
||||
// Field defaults are allowed to use generic parameters, e.g. `field: u32 = /*defid: N + 1*/`
|
||||
ty::AnonConstKind::NonTypeSystem
|
||||
if matches!(tcx.parent_hir_node(hir_id), Node::TyPat(_) | Node::Field(_)) =>
|
||||
{
|
||||
Some(parent_did)
|
||||
}
|
||||
} else {
|
||||
let parent_node = tcx.parent_hir_node(hir_id);
|
||||
let parent_node = match parent_node {
|
||||
Node::ConstArg(ca) => tcx.parent_hir_node(ca.hir_id),
|
||||
_ => parent_node,
|
||||
};
|
||||
match parent_node {
|
||||
// HACK(eddyb) this provides the correct generics for repeat
|
||||
// expressions' count (i.e. `N` in `[x; N]`), and explicit
|
||||
// `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`),
|
||||
// as they shouldn't be able to cause query cycle errors.
|
||||
Node::Expr(Expr { kind: ExprKind::Repeat(_, ct), .. })
|
||||
if ct.anon_const_hir_id() == Some(hir_id) =>
|
||||
{
|
||||
Some(parent_did)
|
||||
}
|
||||
Node::TyPat(_) => Some(parent_did),
|
||||
// Field default values inherit the ADT's generics.
|
||||
Node::Field(_) => Some(parent_did),
|
||||
_ => None,
|
||||
}
|
||||
// Default to no generic parameters for other kinds of anon consts
|
||||
ty::AnonConstKind::NonTypeSystem => None,
|
||||
}
|
||||
}
|
||||
Node::ConstBlock(_)
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
|||
use rustc_errors::codes::*;
|
||||
use rustc_errors::struct_span_code_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::AmbigArg;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::{AmbigArg, HirId};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::{
|
||||
self as ty, IsSuggestable, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable,
|
||||
|
|
@ -309,7 +309,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
false => "`?Sized`",
|
||||
};
|
||||
// There was a `?Trait` bound, but it was neither `?Sized` nor `experimental_default_bounds`.
|
||||
tcx.dcx().span_err(
|
||||
self.dcx().span_err(
|
||||
unbound.span,
|
||||
format!(
|
||||
"relaxing a default bound only does something for {}; \
|
||||
|
|
@ -675,7 +675,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
// Good error for `where Trait::method(..): Send`.
|
||||
let Some(self_ty) = opt_self_ty else {
|
||||
let guar = self.error_missing_qpath_self_ty(
|
||||
let guar = self.report_missing_self_ty_for_resolved_path(
|
||||
trait_def_id,
|
||||
hir_ty.span,
|
||||
item_segment,
|
||||
|
|
@ -713,21 +713,45 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
Err(guar) => Ty::new_error(tcx, guar),
|
||||
}
|
||||
}
|
||||
hir::QPath::TypeRelative(qself, item_segment)
|
||||
if item_segment.args.is_some_and(|args| {
|
||||
hir::QPath::TypeRelative(hir_self_ty, segment)
|
||||
if segment.args.is_some_and(|args| {
|
||||
matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation)
|
||||
}) =>
|
||||
{
|
||||
match self
|
||||
.resolve_type_relative_return_type_notation(
|
||||
qself,
|
||||
item_segment,
|
||||
hir_ty.hir_id,
|
||||
hir_ty.span,
|
||||
)
|
||||
.and_then(|(candidate, item_def_id)| {
|
||||
self.lower_return_type_notation_ty(candidate, item_def_id, hir_ty.span)
|
||||
}) {
|
||||
let self_ty = self.lower_ty(hir_self_ty);
|
||||
let (item_def_id, bound) = match self.resolve_type_relative_path(
|
||||
self_ty,
|
||||
hir_self_ty,
|
||||
ty::AssocTag::Fn,
|
||||
segment,
|
||||
hir_ty.hir_id,
|
||||
hir_ty.span,
|
||||
None,
|
||||
) {
|
||||
Ok(result) => result,
|
||||
Err(guar) => return Ty::new_error(tcx, guar),
|
||||
};
|
||||
|
||||
// Don't let `T::method` resolve to some `for<'a> <T as Tr<'a>>::method`,
|
||||
// which may happen via a higher-ranked where clause or supertrait.
|
||||
// This is the same restrictions as associated types; even though we could
|
||||
// support it, it just makes things a lot more difficult to support in
|
||||
// `resolve_bound_vars`, since we'd need to introduce those as elided
|
||||
// bound vars on the where clause too.
|
||||
if bound.has_bound_vars() {
|
||||
return Ty::new_error(
|
||||
tcx,
|
||||
self.dcx().emit_err(errors::AssociatedItemTraitUninferredGenericParams {
|
||||
span: hir_ty.span,
|
||||
inferred_sugg: Some(hir_ty.span.with_hi(segment.ident.span.lo())),
|
||||
bound: format!("{}::", tcx.anonymize_bound_vars(bound).skip_binder()),
|
||||
mpart_sugg: None,
|
||||
what: tcx.def_descr(item_def_id),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
match self.lower_return_type_notation_ty(bound, item_def_id, hir_ty.span) {
|
||||
Ok(ty) => Ty::new_alias(tcx, ty::Projection, ty),
|
||||
Err(guar) => Ty::new_error(tcx, guar),
|
||||
}
|
||||
|
|
@ -736,99 +760,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
}
|
||||
|
||||
/// Perform type-dependent lookup for a *method* for return type notation.
|
||||
/// This generally mirrors `<dyn HirTyLowerer>::lower_assoc_path`.
|
||||
fn resolve_type_relative_return_type_notation(
|
||||
&self,
|
||||
qself: &'tcx hir::Ty<'tcx>,
|
||||
item_segment: &'tcx hir::PathSegment<'tcx>,
|
||||
qpath_hir_id: HirId,
|
||||
span: Span,
|
||||
) -> Result<(ty::PolyTraitRef<'tcx>, DefId), ErrorGuaranteed> {
|
||||
let tcx = self.tcx();
|
||||
let qself_ty = self.lower_ty(qself);
|
||||
let assoc_ident = item_segment.ident;
|
||||
let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
|
||||
path.res
|
||||
} else {
|
||||
Res::Err
|
||||
};
|
||||
|
||||
let bound = match (qself_ty.kind(), qself_res) {
|
||||
(_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => {
|
||||
// `Self` in an impl of a trait -- we have a concrete self type and a
|
||||
// trait reference.
|
||||
let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else {
|
||||
// A cycle error occurred, most likely.
|
||||
self.dcx().span_bug(span, "expected cycle error");
|
||||
};
|
||||
|
||||
self.probe_single_bound_for_assoc_item(
|
||||
|| {
|
||||
traits::supertraits(
|
||||
tcx,
|
||||
ty::Binder::dummy(trait_ref.instantiate_identity()),
|
||||
)
|
||||
},
|
||||
AssocItemQSelf::SelfTyAlias,
|
||||
ty::AssocTag::Fn,
|
||||
assoc_ident,
|
||||
span,
|
||||
None,
|
||||
)?
|
||||
}
|
||||
(
|
||||
&ty::Param(_),
|
||||
Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did),
|
||||
) => self.probe_single_ty_param_bound_for_assoc_item(
|
||||
param_did.expect_local(),
|
||||
qself.span,
|
||||
ty::AssocTag::Fn,
|
||||
assoc_ident,
|
||||
span,
|
||||
)?,
|
||||
_ => {
|
||||
if let Err(reported) = qself_ty.error_reported() {
|
||||
return Err(reported);
|
||||
} else {
|
||||
// FIXME(return_type_notation): Provide some structured suggestion here.
|
||||
let err = struct_span_code_err!(
|
||||
self.dcx(),
|
||||
span,
|
||||
E0223,
|
||||
"ambiguous associated function"
|
||||
);
|
||||
return Err(err.emit());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Don't let `T::method` resolve to some `for<'a> <T as Tr<'a>>::method`,
|
||||
// which may happen via a higher-ranked where clause or supertrait.
|
||||
// This is the same restrictions as associated types; even though we could
|
||||
// support it, it just makes things a lot more difficult to support in
|
||||
// `resolve_bound_vars`, since we'd need to introduce those as elided
|
||||
// bound vars on the where clause too.
|
||||
if bound.has_bound_vars() {
|
||||
return Err(self.tcx().dcx().emit_err(
|
||||
errors::AssociatedItemTraitUninferredGenericParams {
|
||||
span,
|
||||
inferred_sugg: Some(span.with_hi(item_segment.ident.span.lo())),
|
||||
bound: format!("{}::", tcx.anonymize_bound_vars(bound).skip_binder(),),
|
||||
mpart_sugg: None,
|
||||
what: "function",
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
let trait_def_id = bound.def_id();
|
||||
let assoc_ty = self
|
||||
.probe_assoc_item(assoc_ident, ty::AssocTag::Fn, qpath_hir_id, span, trait_def_id)
|
||||
.expect("failed to find associated type");
|
||||
|
||||
Ok((bound, assoc_ty.def_id))
|
||||
}
|
||||
|
||||
/// Do the common parts of lowering an RTN type. This involves extending the
|
||||
/// candidate binder to include all of the early- and late-bound vars that are
|
||||
/// defined on the function itself, and constructing a projection to the RPITIT
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ pub(crate) fn validate_cmse_abi<'tcx>(
|
|||
_ => tcx.hir_span(hir_id),
|
||||
};
|
||||
struct_span_code_err!(
|
||||
tcx.dcx(),
|
||||
dcx,
|
||||
span,
|
||||
E0781,
|
||||
"the `\"C-cmse-nonsecure-call\"` ABI is only allowed on function pointers"
|
||||
|
|
|
|||
|
|
@ -78,15 +78,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
// We don't support empty trait objects.
|
||||
if regular_traits.is_empty() && auto_traits.is_empty() {
|
||||
let guar = self.report_trait_object_with_no_traits_error(
|
||||
span,
|
||||
user_written_bounds.iter().copied(),
|
||||
);
|
||||
let guar =
|
||||
self.report_trait_object_with_no_traits(span, user_written_bounds.iter().copied());
|
||||
return Ty::new_error(tcx, guar);
|
||||
}
|
||||
// We don't support >1 principal
|
||||
if regular_traits.len() > 1 {
|
||||
let guar = self.report_trait_object_addition_traits_error(®ular_traits);
|
||||
let guar = self.report_trait_object_addition_traits(®ular_traits);
|
||||
return Ty::new_error(tcx, guar);
|
||||
}
|
||||
// Don't create a dyn trait if we have errors in the principal.
|
||||
|
|
@ -132,7 +130,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
if references_self {
|
||||
// With trait alias and type alias combined, type resolver
|
||||
// may not be able to catch all illegal `Self` usages (issue 139082)
|
||||
let guar = tcx.dcx().emit_err(SelfInTypeAlias { span });
|
||||
let guar = self.dcx().emit_err(SelfInTypeAlias { span });
|
||||
b.term = replace_dummy_self_with_error(tcx, b.term, guar);
|
||||
}
|
||||
}
|
||||
|
|
@ -360,7 +358,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id)
|
||||
&& hir_bound.span.contains(span)
|
||||
});
|
||||
self.complain_about_missing_type_params(
|
||||
self.report_missing_type_params(
|
||||
missing_type_params,
|
||||
trait_ref.def_id,
|
||||
span,
|
||||
|
|
|
|||
|
|
@ -3,11 +3,12 @@ use rustc_data_structures::sorted_map::SortedMap;
|
|||
use rustc_data_structures::unord::UnordMap;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, ErrorGuaranteed, MultiSpan, listify, pluralize, struct_span_code_err,
|
||||
Applicability, Diag, ErrorGuaranteed, MultiSpan, SuggestionStyle, listify, pluralize,
|
||||
struct_span_code_err,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorOf, DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{self as hir, HirId};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::fast_reject::{TreatParams, simplify_type};
|
||||
use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _};
|
||||
|
|
@ -23,6 +24,7 @@ use rustc_trait_selection::traits::{
|
|||
FulfillmentError, dyn_compatibility_violations_for_assoc_item,
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::errors::{
|
||||
self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams,
|
||||
|
|
@ -34,7 +36,7 @@ use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer};
|
|||
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
/// On missing type parameters, emit an E0393 error and provide a structured suggestion using
|
||||
/// the type parameter's name as a placeholder.
|
||||
pub(crate) fn complain_about_missing_type_params(
|
||||
pub(crate) fn report_missing_type_params(
|
||||
&self,
|
||||
missing_type_params: Vec<Symbol>,
|
||||
def_id: DefId,
|
||||
|
|
@ -56,7 +58,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
/// When the code is using the `Fn` traits directly, instead of the `Fn(A) -> B` syntax, emit
|
||||
/// an error and attempt to build a reasonable structured suggestion.
|
||||
pub(crate) fn complain_about_internal_fn_trait(
|
||||
pub(crate) fn report_internal_fn_trait(
|
||||
&self,
|
||||
span: Span,
|
||||
trait_def_id: DefId,
|
||||
|
|
@ -112,7 +114,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn complain_about_assoc_item_not_found<I>(
|
||||
pub(super) fn report_unresolved_assoc_item<I>(
|
||||
&self,
|
||||
all_candidates: impl Fn() -> I,
|
||||
qself: AssocItemQSelf,
|
||||
|
|
@ -132,7 +134,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
.filter_by_name_unhygienic(assoc_ident.name)
|
||||
.find(|item| tcx.hygienic_eq(assoc_ident, item.ident(tcx), r.def_id()))
|
||||
}) {
|
||||
return self.complain_about_assoc_kind_mismatch(
|
||||
return self.report_assoc_kind_mismatch(
|
||||
assoc_item,
|
||||
assoc_tag,
|
||||
assoc_ident,
|
||||
|
|
@ -331,7 +333,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
self.dcx().emit_err(err)
|
||||
}
|
||||
|
||||
fn complain_about_assoc_kind_mismatch(
|
||||
fn report_assoc_kind_mismatch(
|
||||
&self,
|
||||
assoc_item: &ty::AssocItem,
|
||||
assoc_tag: ty::AssocTag,
|
||||
|
|
@ -396,12 +398,177 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
})
|
||||
}
|
||||
|
||||
pub(super) fn report_ambiguous_assoc(
|
||||
pub(crate) fn report_missing_self_ty_for_resolved_path(
|
||||
&self,
|
||||
trait_def_id: DefId,
|
||||
span: Span,
|
||||
item_segment: &hir::PathSegment<'tcx>,
|
||||
assoc_tag: ty::AssocTag,
|
||||
) -> ErrorGuaranteed {
|
||||
let tcx = self.tcx();
|
||||
let path_str = tcx.def_path_str(trait_def_id);
|
||||
|
||||
let def_id = self.item_def_id();
|
||||
debug!(item_def_id = ?def_id);
|
||||
|
||||
// FIXME: document why/how this is different from `tcx.local_parent(def_id)`
|
||||
let parent_def_id = tcx.hir_get_parent_item(tcx.local_def_id_to_hir_id(def_id)).to_def_id();
|
||||
debug!(?parent_def_id);
|
||||
|
||||
// If the trait in segment is the same as the trait defining the item,
|
||||
// use the `<Self as ..>` syntax in the error.
|
||||
let is_part_of_self_trait_constraints = def_id.to_def_id() == trait_def_id;
|
||||
let is_part_of_fn_in_self_trait = parent_def_id == trait_def_id;
|
||||
|
||||
let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
|
||||
vec!["Self".to_string()]
|
||||
} else {
|
||||
// Find all the types that have an `impl` for the trait.
|
||||
tcx.all_impls(trait_def_id)
|
||||
.filter_map(|impl_def_id| tcx.impl_trait_header(impl_def_id))
|
||||
.filter(|header| {
|
||||
// Consider only accessible traits
|
||||
tcx.visibility(trait_def_id).is_accessible_from(self.item_def_id(), tcx)
|
||||
&& header.polarity != ty::ImplPolarity::Negative
|
||||
})
|
||||
.map(|header| header.trait_ref.instantiate_identity().self_ty())
|
||||
// We don't care about blanket impls.
|
||||
.filter(|self_ty| !self_ty.has_non_region_param())
|
||||
.map(|self_ty| tcx.erase_regions(self_ty).to_string())
|
||||
.collect()
|
||||
};
|
||||
// FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that
|
||||
// references the trait. Relevant for the first case in
|
||||
// `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs`
|
||||
self.report_ambiguous_assoc_item_path(
|
||||
span,
|
||||
&type_names,
|
||||
&[path_str],
|
||||
item_segment.ident,
|
||||
assoc_tag,
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn report_unresolved_type_relative_path(
|
||||
&self,
|
||||
self_ty: Ty<'tcx>,
|
||||
hir_self_ty: &hir::Ty<'_>,
|
||||
assoc_tag: ty::AssocTag,
|
||||
ident: Ident,
|
||||
qpath_hir_id: HirId,
|
||||
span: Span,
|
||||
variant_def_id: Option<DefId>,
|
||||
) -> ErrorGuaranteed {
|
||||
let tcx = self.tcx();
|
||||
let kind_str = assoc_tag_str(assoc_tag);
|
||||
if variant_def_id.is_some() {
|
||||
// Variant in type position
|
||||
let msg = format!("expected {kind_str}, found variant `{ident}`");
|
||||
self.dcx().span_err(span, msg)
|
||||
} else if self_ty.is_enum() {
|
||||
let mut err = self.dcx().create_err(errors::NoVariantNamed {
|
||||
span: ident.span,
|
||||
ident,
|
||||
ty: self_ty,
|
||||
});
|
||||
|
||||
let adt_def = self_ty.ty_adt_def().expect("enum is not an ADT");
|
||||
if let Some(variant_name) = find_best_match_for_name(
|
||||
&adt_def.variants().iter().map(|variant| variant.name).collect::<Vec<Symbol>>(),
|
||||
ident.name,
|
||||
None,
|
||||
) && let Some(variant) = adt_def.variants().iter().find(|s| s.name == variant_name)
|
||||
{
|
||||
let mut suggestion = vec![(ident.span, variant_name.to_string())];
|
||||
if let hir::Node::Stmt(&hir::Stmt { kind: hir::StmtKind::Semi(expr), .. })
|
||||
| hir::Node::Expr(expr) = tcx.parent_hir_node(qpath_hir_id)
|
||||
&& let hir::ExprKind::Struct(..) = expr.kind
|
||||
{
|
||||
match variant.ctor {
|
||||
None => {
|
||||
// struct
|
||||
suggestion = vec![(
|
||||
ident.span.with_hi(expr.span.hi()),
|
||||
if variant.fields.is_empty() {
|
||||
format!("{variant_name} {{}}")
|
||||
} else {
|
||||
format!(
|
||||
"{variant_name} {{ {} }}",
|
||||
variant
|
||||
.fields
|
||||
.iter()
|
||||
.map(|f| format!("{}: /* value */", f.name))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
)
|
||||
},
|
||||
)];
|
||||
}
|
||||
Some((hir::def::CtorKind::Fn, def_id)) => {
|
||||
// tuple
|
||||
let fn_sig = tcx.fn_sig(def_id).instantiate_identity();
|
||||
let inputs = fn_sig.inputs().skip_binder();
|
||||
suggestion = vec![(
|
||||
ident.span.with_hi(expr.span.hi()),
|
||||
format!(
|
||||
"{variant_name}({})",
|
||||
inputs
|
||||
.iter()
|
||||
.map(|i| format!("/* {i} */"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
),
|
||||
)];
|
||||
}
|
||||
Some((hir::def::CtorKind::Const, _)) => {
|
||||
// unit
|
||||
suggestion = vec![(
|
||||
ident.span.with_hi(expr.span.hi()),
|
||||
variant_name.to_string(),
|
||||
)];
|
||||
}
|
||||
}
|
||||
}
|
||||
err.multipart_suggestion_verbose(
|
||||
"there is a variant with a similar name",
|
||||
suggestion,
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
} else {
|
||||
err.span_label(ident.span, format!("variant not found in `{self_ty}`"));
|
||||
}
|
||||
|
||||
if let Some(sp) = tcx.hir_span_if_local(adt_def.did()) {
|
||||
err.span_label(sp, format!("variant `{ident}` not found here"));
|
||||
}
|
||||
|
||||
err.emit()
|
||||
} else if let Err(reported) = self_ty.error_reported() {
|
||||
reported
|
||||
} else {
|
||||
match self.maybe_report_similar_assoc_fn(span, self_ty, hir_self_ty) {
|
||||
Ok(()) => {}
|
||||
Err(reported) => return reported,
|
||||
}
|
||||
|
||||
let traits: Vec<_> = self.probe_traits_that_match_assoc_ty(self_ty, ident);
|
||||
|
||||
self.report_ambiguous_assoc_item_path(
|
||||
span,
|
||||
&[self_ty.to_string()],
|
||||
&traits,
|
||||
ident,
|
||||
assoc_tag,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn report_ambiguous_assoc_item_path(
|
||||
&self,
|
||||
span: Span,
|
||||
types: &[String],
|
||||
traits: &[String],
|
||||
name: Symbol,
|
||||
ident: Ident,
|
||||
assoc_tag: ty::AssocTag,
|
||||
) -> ErrorGuaranteed {
|
||||
let kind_str = assoc_tag_str(assoc_tag);
|
||||
|
|
@ -421,6 +588,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
let sugg_sp = span.until(ident.span);
|
||||
|
||||
let mut types = types.to_vec();
|
||||
types.sort();
|
||||
let mut traits = traits.to_vec();
|
||||
|
|
@ -428,76 +597,79 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
match (&types[..], &traits[..]) {
|
||||
([], []) => {
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
sugg_sp,
|
||||
format!(
|
||||
"if there were a type named `Type` that implements a trait named \
|
||||
`Trait` with associated {kind_str} `{name}`, you could use the \
|
||||
`Trait` with associated {kind_str} `{ident}`, you could use the \
|
||||
fully-qualified path",
|
||||
),
|
||||
format!("<Type as Trait>::{name}"),
|
||||
"<Type as Trait>::",
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
([], [trait_str]) => {
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
sugg_sp,
|
||||
format!(
|
||||
"if there were a type named `Example` that implemented `{trait_str}`, \
|
||||
you could use the fully-qualified path",
|
||||
),
|
||||
format!("<Example as {trait_str}>::{name}"),
|
||||
format!("<Example as {trait_str}>::"),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
([], traits) => {
|
||||
err.span_suggestions(
|
||||
span,
|
||||
err.span_suggestions_with_style(
|
||||
sugg_sp,
|
||||
format!(
|
||||
"if there were a type named `Example` that implemented one of the \
|
||||
traits with associated {kind_str} `{name}`, you could use the \
|
||||
traits with associated {kind_str} `{ident}`, you could use the \
|
||||
fully-qualified path",
|
||||
),
|
||||
traits.iter().map(|trait_str| format!("<Example as {trait_str}>::{name}")),
|
||||
traits.iter().map(|trait_str| format!("<Example as {trait_str}>::")),
|
||||
Applicability::HasPlaceholders,
|
||||
SuggestionStyle::ShowAlways,
|
||||
);
|
||||
}
|
||||
([type_str], []) => {
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
sugg_sp,
|
||||
format!(
|
||||
"if there were a trait named `Example` with associated {kind_str} `{name}` \
|
||||
"if there were a trait named `Example` with associated {kind_str} `{ident}` \
|
||||
implemented for `{type_str}`, you could use the fully-qualified path",
|
||||
),
|
||||
format!("<{type_str} as Example>::{name}"),
|
||||
format!("<{type_str} as Example>::"),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
(types, []) => {
|
||||
err.span_suggestions(
|
||||
span,
|
||||
err.span_suggestions_with_style(
|
||||
sugg_sp,
|
||||
format!(
|
||||
"if there were a trait named `Example` with associated {kind_str} `{name}` \
|
||||
"if there were a trait named `Example` with associated {kind_str} `{ident}` \
|
||||
implemented for one of the types, you could use the fully-qualified \
|
||||
path",
|
||||
),
|
||||
types
|
||||
.into_iter()
|
||||
.map(|type_str| format!("<{type_str} as Example>::{name}")),
|
||||
.map(|type_str| format!("<{type_str} as Example>::")),
|
||||
Applicability::HasPlaceholders,
|
||||
SuggestionStyle::ShowAlways,
|
||||
);
|
||||
}
|
||||
(types, traits) => {
|
||||
let mut suggestions = vec![];
|
||||
for type_str in types {
|
||||
for trait_str in traits {
|
||||
suggestions.push(format!("<{type_str} as {trait_str}>::{name}"));
|
||||
suggestions.push(format!("<{type_str} as {trait_str}>::"));
|
||||
}
|
||||
}
|
||||
err.span_suggestions(
|
||||
span,
|
||||
err.span_suggestions_with_style(
|
||||
sugg_sp,
|
||||
"use fully-qualified syntax",
|
||||
suggestions,
|
||||
Applicability::MachineApplicable,
|
||||
SuggestionStyle::ShowAlways,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -505,7 +677,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
err.emit()
|
||||
}
|
||||
|
||||
pub(crate) fn complain_about_ambiguous_inherent_assoc(
|
||||
pub(crate) fn report_ambiguous_inherent_assoc_item(
|
||||
&self,
|
||||
name: Ident,
|
||||
candidates: Vec<DefId>,
|
||||
|
|
@ -518,12 +690,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
"multiple applicable items in scope"
|
||||
);
|
||||
err.span_label(name.span, format!("multiple `{name}` found"));
|
||||
self.note_ambiguous_inherent_assoc_ty(&mut err, candidates, span);
|
||||
self.note_ambiguous_inherent_assoc_item(&mut err, candidates, span);
|
||||
err.emit()
|
||||
}
|
||||
|
||||
// FIXME(fmease): Heavily adapted from `rustc_hir_typeck::method::suggest`. Deduplicate.
|
||||
fn note_ambiguous_inherent_assoc_ty(
|
||||
fn note_ambiguous_inherent_assoc_item(
|
||||
&self,
|
||||
err: &mut Diag<'_>,
|
||||
candidates: Vec<DefId>,
|
||||
|
|
@ -566,7 +738,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
|
||||
// FIXME(inherent_associated_types): Find similarly named associated types and suggest them.
|
||||
pub(crate) fn complain_about_inherent_assoc_not_found(
|
||||
pub(crate) fn report_unresolved_inherent_assoc_item(
|
||||
&self,
|
||||
name: Ident,
|
||||
self_ty: Ty<'tcx>,
|
||||
|
|
@ -1046,7 +1218,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn report_prohibit_generics_error<'a>(
|
||||
pub fn report_prohibited_generic_args<'a>(
|
||||
&self,
|
||||
segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
|
||||
args_visitors: impl Iterator<Item = &'a hir::GenericArg<'a>> + Clone,
|
||||
|
|
@ -1128,7 +1300,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
err.emit()
|
||||
}
|
||||
|
||||
pub fn report_trait_object_addition_traits_error(
|
||||
pub fn report_trait_object_addition_traits(
|
||||
&self,
|
||||
regular_traits: &Vec<(ty::PolyTraitPredicate<'tcx>, SmallVec<[Span; 1]>)>,
|
||||
) -> ErrorGuaranteed {
|
||||
|
|
@ -1171,7 +1343,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
err.emit()
|
||||
}
|
||||
|
||||
pub fn report_trait_object_with_no_traits_error(
|
||||
pub fn report_trait_object_with_no_traits(
|
||||
&self,
|
||||
span: Span,
|
||||
user_written_clauses: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// In case there is an associated type with the same name
|
||||
// Add the suggestion to this error
|
||||
if let Some(mut sugg) =
|
||||
tcx.dcx().steal_non_err(self_ty.span, StashKey::AssociatedTypeSuggestion)
|
||||
self.dcx().steal_non_err(self_ty.span, StashKey::AssociatedTypeSuggestion)
|
||||
&& let Suggestions::Enabled(ref mut s1) = diag.suggestions
|
||||
&& let Suggestions::Enabled(ref mut s2) = sugg.suggestions
|
||||
{
|
||||
|
|
|
|||
|
|
@ -38,22 +38,20 @@ use rustc_middle::middle::stability::AllowUnstable;
|
|||
use rustc_middle::mir::interpret::LitToConstInput;
|
||||
use rustc_middle::ty::print::PrintPolyTraitRefExt as _;
|
||||
use rustc_middle::ty::{
|
||||
self, AssocTag, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty,
|
||||
TyCtxt, TypeVisitableExt, TypingMode, Upcast, fold_regions,
|
||||
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt,
|
||||
TypeVisitableExt, TypingMode, Upcast, fold_regions,
|
||||
};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
|
||||
use rustc_span::{DUMMY_SP, Ident, Span, kw, sym};
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::wf::object_region_bounds;
|
||||
use rustc_trait_selection::traits::{self, ObligationCtxt};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use self::errors::assoc_tag_str;
|
||||
use crate::check::check_abi_fn_ptr;
|
||||
use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, NoVariantNamed};
|
||||
use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation};
|
||||
use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint};
|
||||
use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
|
||||
use crate::middle::resolve_bound_vars as rbv;
|
||||
|
|
@ -150,7 +148,7 @@ pub trait HirTyLowerer<'tcx> {
|
|||
assoc_ident: Ident,
|
||||
) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]>;
|
||||
|
||||
/// Lower an associated type/const (from a trait) to a projection.
|
||||
/// Lower a path to an associated item (of a trait) to a projection.
|
||||
///
|
||||
/// This method has to be defined by the concrete lowering context because
|
||||
/// dealing with higher-ranked trait references depends on its capabilities:
|
||||
|
|
@ -162,13 +160,12 @@ pub trait HirTyLowerer<'tcx> {
|
|||
///
|
||||
/// The canonical example of this is associated type `T::P` where `T` is a type
|
||||
/// param constrained by `T: for<'a> Trait<'a>` and where `Trait` defines `P`.
|
||||
fn lower_assoc_shared(
|
||||
fn lower_assoc_item_path(
|
||||
&self,
|
||||
span: Span,
|
||||
item_def_id: DefId,
|
||||
item_segment: &hir::PathSegment<'tcx>,
|
||||
poly_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
assoc_tag: ty::AssocTag,
|
||||
) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed>;
|
||||
|
||||
fn lower_fn_sig(
|
||||
|
|
@ -245,39 +242,46 @@ pub enum FeedConstTy<'a, 'tcx> {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum LowerAssocMode {
|
||||
Type { permit_variants: bool },
|
||||
enum LowerTypeRelativePathMode {
|
||||
Type(PermitVariants),
|
||||
Const,
|
||||
}
|
||||
|
||||
impl LowerAssocMode {
|
||||
impl LowerTypeRelativePathMode {
|
||||
fn assoc_tag(self) -> ty::AssocTag {
|
||||
match self {
|
||||
LowerAssocMode::Type { .. } => ty::AssocTag::Type,
|
||||
LowerAssocMode::Const => ty::AssocTag::Const,
|
||||
Self::Type(_) => ty::AssocTag::Type,
|
||||
Self::Const => ty::AssocTag::Const,
|
||||
}
|
||||
}
|
||||
|
||||
fn def_kind(self) -> DefKind {
|
||||
match self {
|
||||
LowerAssocMode::Type { .. } => DefKind::AssocTy,
|
||||
LowerAssocMode::Const => DefKind::AssocConst,
|
||||
Self::Type(_) => DefKind::AssocTy,
|
||||
Self::Const => DefKind::AssocConst,
|
||||
}
|
||||
}
|
||||
|
||||
fn permit_variants(self) -> bool {
|
||||
fn permit_variants(self) -> PermitVariants {
|
||||
match self {
|
||||
LowerAssocMode::Type { permit_variants } => permit_variants,
|
||||
Self::Type(permit_variants) => permit_variants,
|
||||
// FIXME(mgca): Support paths like `Option::<T>::None` or `Option::<T>::Some` which
|
||||
// resolve to const ctors/fn items respectively.
|
||||
LowerAssocMode::Const => false,
|
||||
Self::Const => PermitVariants::No,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether to permit a path to resolve to an enum variant.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum LoweredAssoc<'tcx> {
|
||||
Term(DefId, GenericArgsRef<'tcx>),
|
||||
pub enum PermitVariants {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum TypeRelativePath<'tcx> {
|
||||
AssocItem(DefId, GenericArgsRef<'tcx>),
|
||||
Variant { adt: Ty<'tcx>, variant_did: DefId },
|
||||
}
|
||||
|
||||
|
|
@ -745,7 +749,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
trait_ref.path.segments.split_last().unwrap().1.iter(),
|
||||
GenericsArgsErrExtend::None,
|
||||
);
|
||||
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false);
|
||||
self.report_internal_fn_trait(span, trait_def_id, trait_segment, false);
|
||||
|
||||
let (generic_args, arg_count) = self.lower_generic_args_of_path(
|
||||
trait_ref.path.span,
|
||||
|
|
@ -920,7 +924,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
trait_segment: &hir::PathSegment<'tcx>,
|
||||
is_impl: bool,
|
||||
) -> ty::TraitRef<'tcx> {
|
||||
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
|
||||
self.report_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
|
||||
|
||||
let (generic_args, _) =
|
||||
self.lower_generic_args_of_path(span, trait_def_id, &[], trait_segment, Some(self_ty));
|
||||
|
|
@ -933,7 +937,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
fn probe_trait_that_defines_assoc_item(
|
||||
&self,
|
||||
trait_def_id: DefId,
|
||||
assoc_tag: AssocTag,
|
||||
assoc_tag: ty::AssocTag,
|
||||
assoc_ident: Ident,
|
||||
) -> bool {
|
||||
self.tcx()
|
||||
|
|
@ -976,7 +980,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
&self,
|
||||
ty_param_def_id: LocalDefId,
|
||||
ty_param_span: Span,
|
||||
assoc_tag: AssocTag,
|
||||
assoc_tag: ty::AssocTag,
|
||||
assoc_ident: Ident,
|
||||
span: Span,
|
||||
) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed> {
|
||||
|
|
@ -1011,7 +1015,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
&self,
|
||||
all_candidates: impl Fn() -> I,
|
||||
qself: AssocItemQSelf,
|
||||
assoc_tag: AssocTag,
|
||||
assoc_tag: ty::AssocTag,
|
||||
assoc_ident: Ident,
|
||||
span: Span,
|
||||
constraint: Option<&hir::AssocItemConstraint<'tcx>>,
|
||||
|
|
@ -1026,15 +1030,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
});
|
||||
|
||||
let Some(bound) = matching_candidates.next() else {
|
||||
let reported = self.complain_about_assoc_item_not_found(
|
||||
return Err(self.report_unresolved_assoc_item(
|
||||
all_candidates,
|
||||
qself,
|
||||
assoc_tag,
|
||||
assoc_ident,
|
||||
span,
|
||||
constraint,
|
||||
);
|
||||
return Err(reported);
|
||||
));
|
||||
};
|
||||
debug!(?bound);
|
||||
|
||||
|
|
@ -1127,7 +1130,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
Ok(bound)
|
||||
}
|
||||
|
||||
/// Lower a [type-relative] path referring to an associated type or to an enum variant.
|
||||
/// Lower a [type-relative](hir::QPath::TypeRelative) path in type position to a type.
|
||||
///
|
||||
/// If the path refers to an enum variant and `permit_variants` holds,
|
||||
/// the returned type is simply the provided self type `qself_ty`.
|
||||
|
|
@ -1148,61 +1151,63 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
/// described in the previous paragraph and their modeling of projections would likely be
|
||||
/// very similar in nature.
|
||||
///
|
||||
/// [type-relative]: hir::QPath::TypeRelative
|
||||
/// [#22519]: https://github.com/rust-lang/rust/issues/22519
|
||||
/// [iat]: https://github.com/rust-lang/rust/issues/8995#issuecomment-1569208403
|
||||
//
|
||||
// NOTE: When this function starts resolving `Trait::AssocTy` successfully
|
||||
// it should also start reporting the `BARE_TRAIT_OBJECTS` lint.
|
||||
#[instrument(level = "debug", skip_all, ret)]
|
||||
pub fn lower_assoc_path_ty(
|
||||
pub fn lower_type_relative_ty_path(
|
||||
&self,
|
||||
hir_ref_id: HirId,
|
||||
self_ty: Ty<'tcx>,
|
||||
hir_self_ty: &'tcx hir::Ty<'tcx>,
|
||||
segment: &'tcx hir::PathSegment<'tcx>,
|
||||
qpath_hir_id: HirId,
|
||||
span: Span,
|
||||
qself_ty: Ty<'tcx>,
|
||||
qself: &'tcx hir::Ty<'tcx>,
|
||||
assoc_segment: &'tcx hir::PathSegment<'tcx>,
|
||||
permit_variants: bool,
|
||||
permit_variants: PermitVariants,
|
||||
) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
|
||||
let tcx = self.tcx();
|
||||
match self.lower_assoc_path_shared(
|
||||
hir_ref_id,
|
||||
match self.lower_type_relative_path(
|
||||
self_ty,
|
||||
hir_self_ty,
|
||||
segment,
|
||||
qpath_hir_id,
|
||||
span,
|
||||
qself_ty,
|
||||
qself,
|
||||
assoc_segment,
|
||||
LowerAssocMode::Type { permit_variants },
|
||||
LowerTypeRelativePathMode::Type(permit_variants),
|
||||
)? {
|
||||
LoweredAssoc::Term(def_id, args) => {
|
||||
TypeRelativePath::AssocItem(def_id, args) => {
|
||||
let alias_ty = ty::AliasTy::new_from_args(tcx, def_id, args);
|
||||
let ty = Ty::new_alias(tcx, alias_ty.kind(tcx), alias_ty);
|
||||
Ok((ty, tcx.def_kind(def_id), def_id))
|
||||
}
|
||||
LoweredAssoc::Variant { adt, variant_did } => Ok((adt, DefKind::Variant, variant_did)),
|
||||
TypeRelativePath::Variant { adt, variant_did } => {
|
||||
Ok((adt, DefKind::Variant, variant_did))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Lower a [type-relative][hir::QPath::TypeRelative] path to a (type-level) constant.
|
||||
#[instrument(level = "debug", skip_all, ret)]
|
||||
fn lower_assoc_path_const(
|
||||
fn lower_type_relative_const_path(
|
||||
&self,
|
||||
hir_ref_id: HirId,
|
||||
self_ty: Ty<'tcx>,
|
||||
hir_self_ty: &'tcx hir::Ty<'tcx>,
|
||||
segment: &'tcx hir::PathSegment<'tcx>,
|
||||
qpath_hir_id: HirId,
|
||||
span: Span,
|
||||
qself_ty: Ty<'tcx>,
|
||||
qself: &'tcx hir::Ty<'tcx>,
|
||||
assoc_segment: &'tcx hir::PathSegment<'tcx>,
|
||||
) -> Result<Const<'tcx>, ErrorGuaranteed> {
|
||||
let tcx = self.tcx();
|
||||
let (def_id, args) = match self.lower_assoc_path_shared(
|
||||
hir_ref_id,
|
||||
let (def_id, args) = match self.lower_type_relative_path(
|
||||
self_ty,
|
||||
hir_self_ty,
|
||||
segment,
|
||||
qpath_hir_id,
|
||||
span,
|
||||
qself_ty,
|
||||
qself,
|
||||
assoc_segment,
|
||||
LowerAssocMode::Const,
|
||||
LowerTypeRelativePathMode::Const,
|
||||
)? {
|
||||
LoweredAssoc::Term(def_id, args) => {
|
||||
TypeRelativePath::AssocItem(def_id, args) => {
|
||||
if !tcx.associated_item(def_id).is_type_const_capable(tcx) {
|
||||
let mut err = tcx.dcx().struct_span_err(
|
||||
let mut err = self.dcx().struct_span_err(
|
||||
span,
|
||||
"use of trait associated const without `#[type_const]`",
|
||||
);
|
||||
|
|
@ -1213,75 +1218,134 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
// FIXME(mgca): implement support for this once ready to support all adt ctor expressions,
|
||||
// not just const ctors
|
||||
LoweredAssoc::Variant { .. } => {
|
||||
TypeRelativePath::Variant { .. } => {
|
||||
span_bug!(span, "unexpected variant res for type associated const path")
|
||||
}
|
||||
};
|
||||
Ok(Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(def_id, args)))
|
||||
}
|
||||
|
||||
/// Lower a [type-relative][hir::QPath::TypeRelative] (and type-level) path.
|
||||
#[instrument(level = "debug", skip_all, ret)]
|
||||
fn lower_assoc_path_shared(
|
||||
fn lower_type_relative_path(
|
||||
&self,
|
||||
hir_ref_id: HirId,
|
||||
self_ty: Ty<'tcx>,
|
||||
hir_self_ty: &'tcx hir::Ty<'tcx>,
|
||||
segment: &'tcx hir::PathSegment<'tcx>,
|
||||
qpath_hir_id: HirId,
|
||||
span: Span,
|
||||
qself_ty: Ty<'tcx>,
|
||||
qself: &'tcx hir::Ty<'tcx>,
|
||||
assoc_segment: &'tcx hir::PathSegment<'tcx>,
|
||||
mode: LowerAssocMode,
|
||||
) -> Result<LoweredAssoc<'tcx>, ErrorGuaranteed> {
|
||||
debug!(%qself_ty, ?assoc_segment.ident);
|
||||
mode: LowerTypeRelativePathMode,
|
||||
) -> Result<TypeRelativePath<'tcx>, ErrorGuaranteed> {
|
||||
debug!(%self_ty, ?segment.ident);
|
||||
let tcx = self.tcx();
|
||||
|
||||
let assoc_ident = assoc_segment.ident;
|
||||
|
||||
// Check if we have an enum variant or an inherent associated type.
|
||||
let mut variant_resolution = None;
|
||||
if let Some(adt_def) = self.probe_adt(span, qself_ty) {
|
||||
let mut variant_def_id = None;
|
||||
if let Some(adt_def) = self.probe_adt(span, self_ty) {
|
||||
if adt_def.is_enum() {
|
||||
let variant_def = adt_def
|
||||
.variants()
|
||||
.iter()
|
||||
.find(|vd| tcx.hygienic_eq(assoc_ident, vd.ident(tcx), adt_def.did()));
|
||||
.find(|vd| tcx.hygienic_eq(segment.ident, vd.ident(tcx), adt_def.did()));
|
||||
if let Some(variant_def) = variant_def {
|
||||
if mode.permit_variants() {
|
||||
tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
|
||||
if let PermitVariants::Yes = mode.permit_variants() {
|
||||
tcx.check_stability(variant_def.def_id, Some(qpath_hir_id), span, None);
|
||||
let _ = self.prohibit_generic_args(
|
||||
slice::from_ref(assoc_segment).iter(),
|
||||
GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def },
|
||||
slice::from_ref(segment).iter(),
|
||||
GenericsArgsErrExtend::EnumVariant {
|
||||
qself: hir_self_ty,
|
||||
assoc_segment: segment,
|
||||
adt_def,
|
||||
},
|
||||
);
|
||||
return Ok(LoweredAssoc::Variant {
|
||||
adt: qself_ty,
|
||||
return Ok(TypeRelativePath::Variant {
|
||||
adt: self_ty,
|
||||
variant_did: variant_def.def_id,
|
||||
});
|
||||
} else {
|
||||
variant_resolution = Some(variant_def.def_id);
|
||||
variant_def_id = Some(variant_def.def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(inherent_associated_types, #106719): Support self types other than ADTs.
|
||||
if let Some((did, args)) = self.probe_inherent_assoc_shared(
|
||||
assoc_segment,
|
||||
if let Some((did, args)) = self.probe_inherent_assoc_item(
|
||||
segment,
|
||||
adt_def.did(),
|
||||
qself_ty,
|
||||
hir_ref_id,
|
||||
self_ty,
|
||||
qpath_hir_id,
|
||||
span,
|
||||
mode.assoc_tag(),
|
||||
)? {
|
||||
return Ok(LoweredAssoc::Term(did, args));
|
||||
return Ok(TypeRelativePath::AssocItem(did, args));
|
||||
}
|
||||
}
|
||||
|
||||
let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
|
||||
path.res
|
||||
} else {
|
||||
Res::Err
|
||||
let (item_def_id, bound) = self.resolve_type_relative_path(
|
||||
self_ty,
|
||||
hir_self_ty,
|
||||
mode.assoc_tag(),
|
||||
segment,
|
||||
qpath_hir_id,
|
||||
span,
|
||||
variant_def_id,
|
||||
)?;
|
||||
|
||||
let (item_def_id, args) = self.lower_assoc_item_path(span, item_def_id, segment, bound)?;
|
||||
|
||||
if let Some(variant_def_id) = variant_def_id {
|
||||
tcx.node_span_lint(AMBIGUOUS_ASSOCIATED_ITEMS, qpath_hir_id, span, |lint| {
|
||||
lint.primary_message("ambiguous associated item");
|
||||
let mut could_refer_to = |kind: DefKind, def_id, also| {
|
||||
let note_msg = format!(
|
||||
"`{}` could{} refer to the {} defined here",
|
||||
segment.ident,
|
||||
also,
|
||||
tcx.def_kind_descr(kind, def_id)
|
||||
);
|
||||
lint.span_note(tcx.def_span(def_id), note_msg);
|
||||
};
|
||||
|
||||
could_refer_to(DefKind::Variant, variant_def_id, "");
|
||||
could_refer_to(mode.def_kind(), item_def_id, " also");
|
||||
|
||||
lint.span_suggestion(
|
||||
span,
|
||||
"use fully-qualified syntax",
|
||||
format!(
|
||||
"<{} as {}>::{}",
|
||||
self_ty,
|
||||
tcx.item_name(bound.def_id()),
|
||||
segment.ident
|
||||
),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Ok(TypeRelativePath::AssocItem(item_def_id, args))
|
||||
}
|
||||
|
||||
/// Resolve a [type-relative](hir::QPath::TypeRelative) (and type-level) path.
|
||||
fn resolve_type_relative_path(
|
||||
&self,
|
||||
self_ty: Ty<'tcx>,
|
||||
hir_self_ty: &'tcx hir::Ty<'tcx>,
|
||||
assoc_tag: ty::AssocTag,
|
||||
segment: &'tcx hir::PathSegment<'tcx>,
|
||||
qpath_hir_id: HirId,
|
||||
span: Span,
|
||||
variant_def_id: Option<DefId>,
|
||||
) -> Result<(DefId, ty::PolyTraitRef<'tcx>), ErrorGuaranteed> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
let self_ty_res = match hir_self_ty.kind {
|
||||
hir::TyKind::Path(hir::QPath::Resolved(_, path)) => path.res,
|
||||
_ => Res::Err,
|
||||
};
|
||||
|
||||
// Find the type of the associated item, and the trait where the associated
|
||||
// item is declared.
|
||||
let bound = match (qself_ty.kind(), qself_res) {
|
||||
// Find the type of the assoc item, and the trait where the associated item is declared.
|
||||
let bound = match (self_ty.kind(), self_ty_res) {
|
||||
(_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => {
|
||||
// `Self` in an impl of a trait -- we have a concrete self type and a
|
||||
// trait reference.
|
||||
|
|
@ -1292,14 +1356,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
self.probe_single_bound_for_assoc_item(
|
||||
|| {
|
||||
traits::supertraits(
|
||||
tcx,
|
||||
ty::Binder::dummy(trait_ref.instantiate_identity()),
|
||||
)
|
||||
let trait_ref = ty::Binder::dummy(trait_ref.instantiate_identity());
|
||||
traits::supertraits(tcx, trait_ref)
|
||||
},
|
||||
AssocItemQSelf::SelfTyAlias,
|
||||
mode.assoc_tag(),
|
||||
assoc_ident,
|
||||
assoc_tag,
|
||||
segment.ident,
|
||||
span,
|
||||
None,
|
||||
)?
|
||||
|
|
@ -1309,167 +1371,33 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did),
|
||||
) => self.probe_single_ty_param_bound_for_assoc_item(
|
||||
param_did.expect_local(),
|
||||
qself.span,
|
||||
mode.assoc_tag(),
|
||||
assoc_ident,
|
||||
hir_self_ty.span,
|
||||
assoc_tag,
|
||||
segment.ident,
|
||||
span,
|
||||
)?,
|
||||
_ => {
|
||||
let kind_str = assoc_tag_str(mode.assoc_tag());
|
||||
let reported = if variant_resolution.is_some() {
|
||||
// Variant in type position
|
||||
let msg = format!("expected {kind_str}, found variant `{assoc_ident}`");
|
||||
self.dcx().span_err(span, msg)
|
||||
} else if qself_ty.is_enum() {
|
||||
let mut err = self.dcx().create_err(NoVariantNamed {
|
||||
span: assoc_ident.span,
|
||||
ident: assoc_ident,
|
||||
ty: qself_ty,
|
||||
});
|
||||
|
||||
let adt_def = qself_ty.ty_adt_def().expect("enum is not an ADT");
|
||||
if let Some(variant_name) = find_best_match_for_name(
|
||||
&adt_def
|
||||
.variants()
|
||||
.iter()
|
||||
.map(|variant| variant.name)
|
||||
.collect::<Vec<Symbol>>(),
|
||||
assoc_ident.name,
|
||||
None,
|
||||
) && let Some(variant) =
|
||||
adt_def.variants().iter().find(|s| s.name == variant_name)
|
||||
{
|
||||
let mut suggestion = vec![(assoc_ident.span, variant_name.to_string())];
|
||||
if let hir::Node::Stmt(&hir::Stmt {
|
||||
kind: hir::StmtKind::Semi(expr), ..
|
||||
})
|
||||
| hir::Node::Expr(expr) = tcx.parent_hir_node(hir_ref_id)
|
||||
&& let hir::ExprKind::Struct(..) = expr.kind
|
||||
{
|
||||
match variant.ctor {
|
||||
None => {
|
||||
// struct
|
||||
suggestion = vec![(
|
||||
assoc_ident.span.with_hi(expr.span.hi()),
|
||||
if variant.fields.is_empty() {
|
||||
format!("{variant_name} {{}}")
|
||||
} else {
|
||||
format!(
|
||||
"{variant_name} {{ {} }}",
|
||||
variant
|
||||
.fields
|
||||
.iter()
|
||||
.map(|f| format!("{}: /* value */", f.name))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
)
|
||||
},
|
||||
)];
|
||||
}
|
||||
Some((hir::def::CtorKind::Fn, def_id)) => {
|
||||
// tuple
|
||||
let fn_sig = tcx.fn_sig(def_id).instantiate_identity();
|
||||
let inputs = fn_sig.inputs().skip_binder();
|
||||
suggestion = vec![(
|
||||
assoc_ident.span.with_hi(expr.span.hi()),
|
||||
format!(
|
||||
"{variant_name}({})",
|
||||
inputs
|
||||
.iter()
|
||||
.map(|i| format!("/* {i} */"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
),
|
||||
)];
|
||||
}
|
||||
Some((hir::def::CtorKind::Const, _)) => {
|
||||
// unit
|
||||
suggestion = vec![(
|
||||
assoc_ident.span.with_hi(expr.span.hi()),
|
||||
variant_name.to_string(),
|
||||
)];
|
||||
}
|
||||
}
|
||||
}
|
||||
err.multipart_suggestion_verbose(
|
||||
"there is a variant with a similar name",
|
||||
suggestion,
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
} else {
|
||||
err.span_label(
|
||||
assoc_ident.span,
|
||||
format!("variant not found in `{qself_ty}`"),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(sp) = tcx.hir_span_if_local(adt_def.did()) {
|
||||
err.span_label(sp, format!("variant `{assoc_ident}` not found here"));
|
||||
}
|
||||
|
||||
err.emit()
|
||||
} else if let Err(reported) = qself_ty.error_reported() {
|
||||
reported
|
||||
} else {
|
||||
self.maybe_report_similar_assoc_fn(span, qself_ty, qself)?;
|
||||
|
||||
let traits: Vec<_> =
|
||||
self.probe_traits_that_match_assoc_ty(qself_ty, assoc_ident);
|
||||
|
||||
// Don't print `ty::Error` to the user.
|
||||
self.report_ambiguous_assoc(
|
||||
span,
|
||||
&[qself_ty.to_string()],
|
||||
&traits,
|
||||
assoc_ident.name,
|
||||
mode.assoc_tag(),
|
||||
)
|
||||
};
|
||||
return Err(reported);
|
||||
return Err(self.report_unresolved_type_relative_path(
|
||||
self_ty,
|
||||
hir_self_ty,
|
||||
assoc_tag,
|
||||
segment.ident,
|
||||
qpath_hir_id,
|
||||
span,
|
||||
variant_def_id,
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let trait_did = bound.def_id();
|
||||
let assoc_item = self
|
||||
.probe_assoc_item(assoc_ident, mode.assoc_tag(), hir_ref_id, span, trait_did)
|
||||
.probe_assoc_item(segment.ident, assoc_tag, qpath_hir_id, span, bound.def_id())
|
||||
.expect("failed to find associated item");
|
||||
let (def_id, args) = self.lower_assoc_shared(
|
||||
span,
|
||||
assoc_item.def_id,
|
||||
assoc_segment,
|
||||
bound,
|
||||
mode.assoc_tag(),
|
||||
)?;
|
||||
let result = LoweredAssoc::Term(def_id, args);
|
||||
|
||||
if let Some(variant_def_id) = variant_resolution {
|
||||
tcx.node_span_lint(AMBIGUOUS_ASSOCIATED_ITEMS, hir_ref_id, span, |lint| {
|
||||
lint.primary_message("ambiguous associated item");
|
||||
let mut could_refer_to = |kind: DefKind, def_id, also| {
|
||||
let note_msg = format!(
|
||||
"`{}` could{} refer to the {} defined here",
|
||||
assoc_ident,
|
||||
also,
|
||||
tcx.def_kind_descr(kind, def_id)
|
||||
);
|
||||
lint.span_note(tcx.def_span(def_id), note_msg);
|
||||
};
|
||||
|
||||
could_refer_to(DefKind::Variant, variant_def_id, "");
|
||||
could_refer_to(mode.def_kind(), assoc_item.def_id, " also");
|
||||
|
||||
lint.span_suggestion(
|
||||
span,
|
||||
"use fully-qualified syntax",
|
||||
format!("<{} as {}>::{}", qself_ty, tcx.item_name(trait_did), assoc_ident),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
});
|
||||
}
|
||||
Ok(result)
|
||||
Ok((assoc_item.def_id, bound))
|
||||
}
|
||||
|
||||
fn probe_inherent_assoc_shared(
|
||||
/// Search for inherent associated items for use at the type level.
|
||||
fn probe_inherent_assoc_item(
|
||||
&self,
|
||||
segment: &hir::PathSegment<'tcx>,
|
||||
adt_did: DefId,
|
||||
|
|
@ -1624,7 +1552,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
.collect();
|
||||
|
||||
match &applicable_candidates[..] {
|
||||
&[] => Err(self.complain_about_inherent_assoc_not_found(
|
||||
&[] => Err(self.report_unresolved_inherent_assoc_item(
|
||||
name,
|
||||
self_ty,
|
||||
candidates,
|
||||
|
|
@ -1635,7 +1563,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
&[applicable_candidate] => Ok(applicable_candidate),
|
||||
|
||||
&[_, ..] => Err(self.complain_about_ambiguous_inherent_assoc(
|
||||
&[_, ..] => Err(self.report_ambiguous_inherent_assoc_item(
|
||||
name,
|
||||
applicable_candidates.into_iter().map(|(_, (candidate, _))| candidate).collect(),
|
||||
span,
|
||||
|
|
@ -1763,9 +1691,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
.collect()
|
||||
}
|
||||
|
||||
/// Lower a qualified path to a type.
|
||||
/// Lower a [resolved][hir::QPath::Resolved] associated type path to a projection.
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
fn lower_qpath_ty(
|
||||
fn lower_resolved_assoc_ty_path(
|
||||
&self,
|
||||
span: Span,
|
||||
opt_self_ty: Option<Ty<'tcx>>,
|
||||
|
|
@ -1773,7 +1701,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
trait_segment: Option<&hir::PathSegment<'tcx>>,
|
||||
item_segment: &hir::PathSegment<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
match self.lower_qpath_shared(
|
||||
match self.lower_resolved_assoc_item_path(
|
||||
span,
|
||||
opt_self_ty,
|
||||
item_def_id,
|
||||
|
|
@ -1788,9 +1716,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
}
|
||||
|
||||
/// Lower a qualified path to a const.
|
||||
/// Lower a [resolved][hir::QPath::Resolved] associated const path to a (type-level) constant.
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
fn lower_qpath_const(
|
||||
fn lower_resolved_assoc_const_path(
|
||||
&self,
|
||||
span: Span,
|
||||
opt_self_ty: Option<Ty<'tcx>>,
|
||||
|
|
@ -1798,7 +1726,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
trait_segment: Option<&hir::PathSegment<'tcx>>,
|
||||
item_segment: &hir::PathSegment<'tcx>,
|
||||
) -> Const<'tcx> {
|
||||
match self.lower_qpath_shared(
|
||||
match self.lower_resolved_assoc_item_path(
|
||||
span,
|
||||
opt_self_ty,
|
||||
item_def_id,
|
||||
|
|
@ -1814,8 +1742,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
}
|
||||
|
||||
/// Lower a [resolved][hir::QPath::Resolved] (type-level) associated item path.
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
fn lower_qpath_shared(
|
||||
fn lower_resolved_assoc_item_path(
|
||||
&self,
|
||||
span: Span,
|
||||
opt_self_ty: Option<Ty<'tcx>>,
|
||||
|
|
@ -1830,7 +1759,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
debug!(?trait_def_id);
|
||||
|
||||
let Some(self_ty) = opt_self_ty else {
|
||||
return Err(self.error_missing_qpath_self_ty(
|
||||
return Err(self.report_missing_self_ty_for_resolved_path(
|
||||
trait_def_id,
|
||||
span,
|
||||
item_segment,
|
||||
|
|
@ -1849,57 +1778,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
Ok((item_def_id, item_args))
|
||||
}
|
||||
|
||||
fn error_missing_qpath_self_ty(
|
||||
&self,
|
||||
trait_def_id: DefId,
|
||||
span: Span,
|
||||
item_segment: &hir::PathSegment<'tcx>,
|
||||
assoc_tag: ty::AssocTag,
|
||||
) -> ErrorGuaranteed {
|
||||
let tcx = self.tcx();
|
||||
let path_str = tcx.def_path_str(trait_def_id);
|
||||
|
||||
let def_id = self.item_def_id();
|
||||
debug!(item_def_id = ?def_id);
|
||||
|
||||
// FIXME: document why/how this is different from `tcx.local_parent(def_id)`
|
||||
let parent_def_id = tcx.hir_get_parent_item(tcx.local_def_id_to_hir_id(def_id)).to_def_id();
|
||||
debug!(?parent_def_id);
|
||||
|
||||
// If the trait in segment is the same as the trait defining the item,
|
||||
// use the `<Self as ..>` syntax in the error.
|
||||
let is_part_of_self_trait_constraints = def_id.to_def_id() == trait_def_id;
|
||||
let is_part_of_fn_in_self_trait = parent_def_id == trait_def_id;
|
||||
|
||||
let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
|
||||
vec!["Self".to_string()]
|
||||
} else {
|
||||
// Find all the types that have an `impl` for the trait.
|
||||
tcx.all_impls(trait_def_id)
|
||||
.filter_map(|impl_def_id| tcx.impl_trait_header(impl_def_id))
|
||||
.filter(|header| {
|
||||
// Consider only accessible traits
|
||||
tcx.visibility(trait_def_id).is_accessible_from(self.item_def_id(), tcx)
|
||||
&& header.polarity != ty::ImplPolarity::Negative
|
||||
})
|
||||
.map(|header| header.trait_ref.instantiate_identity().self_ty())
|
||||
// We don't care about blanket impls.
|
||||
.filter(|self_ty| !self_ty.has_non_region_param())
|
||||
.map(|self_ty| tcx.erase_regions(self_ty).to_string())
|
||||
.collect()
|
||||
};
|
||||
// FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that
|
||||
// references the trait. Relevant for the first case in
|
||||
// `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs`
|
||||
self.report_ambiguous_assoc(
|
||||
span,
|
||||
&type_names,
|
||||
&[path_str],
|
||||
item_segment.ident.name,
|
||||
assoc_tag,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn prohibit_generic_args<'a>(
|
||||
&self,
|
||||
segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
|
||||
|
|
@ -1908,7 +1786,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let args_visitors = segments.clone().flat_map(|segment| segment.args().args);
|
||||
let mut result = Ok(());
|
||||
if let Some(_) = args_visitors.clone().next() {
|
||||
result = Err(self.report_prohibit_generics_error(
|
||||
result = Err(self.report_prohibited_generic_args(
|
||||
segments.clone(),
|
||||
args_visitors,
|
||||
err_extend,
|
||||
|
|
@ -2069,14 +1947,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
generic_segments
|
||||
}
|
||||
|
||||
/// Lower a type `Path` to a type.
|
||||
/// Lower a [resolved][hir::QPath::Resolved] path to a type.
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
pub fn lower_path(
|
||||
pub fn lower_resolved_ty_path(
|
||||
&self,
|
||||
opt_self_ty: Option<Ty<'tcx>>,
|
||||
path: &hir::Path<'tcx>,
|
||||
hir_id: HirId,
|
||||
permit_variants: bool,
|
||||
permit_variants: PermitVariants,
|
||||
) -> Ty<'tcx> {
|
||||
debug!(?path.res, ?opt_self_ty, ?path.segments);
|
||||
let tcx = self.tcx();
|
||||
|
|
@ -2107,7 +1985,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
);
|
||||
self.lower_path_segment(span, did, path.segments.last().unwrap())
|
||||
}
|
||||
Res::Def(kind @ DefKind::Variant, def_id) if permit_variants => {
|
||||
Res::Def(kind @ DefKind::Variant, def_id)
|
||||
if let PermitVariants::Yes = permit_variants =>
|
||||
{
|
||||
// Lower "variant type" as if it were a real type.
|
||||
// The resulting `Ty` is type of the variant's enum for now.
|
||||
assert_eq!(opt_self_ty, None);
|
||||
|
|
@ -2202,7 +2082,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
} else {
|
||||
None
|
||||
};
|
||||
self.lower_qpath_ty(
|
||||
self.lower_resolved_assoc_ty_path(
|
||||
span,
|
||||
opt_self_ty,
|
||||
def_id,
|
||||
|
|
@ -2298,7 +2178,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
}
|
||||
|
||||
/// Convert a [`hir::ConstArg`] to a [`ty::Const`](Const).
|
||||
/// Lower a [`hir::ConstArg`] to a (type-level) [`ty::Const`](Const).
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn lower_const_arg(
|
||||
&self,
|
||||
|
|
@ -2323,7 +2203,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
if tcx.features().generic_const_parameter_types()
|
||||
&& (anon_const_type.has_free_regions() || anon_const_type.has_erased_regions())
|
||||
{
|
||||
let e = tcx.dcx().span_err(
|
||||
let e = self.dcx().span_err(
|
||||
const_arg.span(),
|
||||
"anonymous constants with lifetimes in their type are not yet supported",
|
||||
);
|
||||
|
|
@ -2334,7 +2214,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// use this type to feed the `type_of` and query results must not contain inference
|
||||
// variables otherwise we will ICE.
|
||||
if anon_const_type.has_non_region_infer() {
|
||||
let e = tcx.dcx().span_err(
|
||||
let e = self.dcx().span_err(
|
||||
const_arg.span(),
|
||||
"anonymous constants with inferred types are not yet supported",
|
||||
);
|
||||
|
|
@ -2344,7 +2224,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// We error when the type contains unsubstituted generics since we do not currently
|
||||
// give the anon const any of the generics from the parent.
|
||||
if anon_const_type.has_non_region_param() {
|
||||
let e = tcx.dcx().span_err(
|
||||
let e = self.dcx().span_err(
|
||||
const_arg.span(),
|
||||
"anonymous constants referencing generics are not yet supported",
|
||||
);
|
||||
|
|
@ -2363,13 +2243,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
hir::ConstArgKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
|
||||
debug!(?maybe_qself, ?path);
|
||||
let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself));
|
||||
self.lower_const_path_resolved(opt_self_ty, path, hir_id)
|
||||
self.lower_resolved_const_path(opt_self_ty, path, hir_id)
|
||||
}
|
||||
hir::ConstArgKind::Path(hir::QPath::TypeRelative(qself, segment)) => {
|
||||
debug!(?qself, ?segment);
|
||||
let ty = self.lower_ty(qself);
|
||||
self.lower_assoc_path_const(hir_id, const_arg.span(), ty, qself, segment)
|
||||
.unwrap_or_else(|guar| Const::new_error(tcx, guar))
|
||||
hir::ConstArgKind::Path(hir::QPath::TypeRelative(hir_self_ty, segment)) => {
|
||||
debug!(?hir_self_ty, ?segment);
|
||||
let self_ty = self.lower_ty(hir_self_ty);
|
||||
self.lower_type_relative_const_path(
|
||||
self_ty,
|
||||
hir_self_ty,
|
||||
segment,
|
||||
hir_id,
|
||||
const_arg.span(),
|
||||
)
|
||||
.unwrap_or_else(|guar| Const::new_error(tcx, guar))
|
||||
}
|
||||
hir::ConstArgKind::Path(qpath @ hir::QPath::LangItem(..)) => {
|
||||
ty::Const::new_error_with_message(
|
||||
|
|
@ -2383,7 +2269,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
}
|
||||
|
||||
fn lower_const_path_resolved(
|
||||
/// Lower a [resolved][hir::QPath::Resolved] path to a (type-level) constant.
|
||||
fn lower_resolved_const_path(
|
||||
&self,
|
||||
opt_self_ty: Option<Ty<'tcx>>,
|
||||
path: &hir::Path<'tcx>,
|
||||
|
|
@ -2420,7 +2307,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
} else {
|
||||
None
|
||||
};
|
||||
self.lower_qpath_const(
|
||||
self.lower_resolved_assoc_const_path(
|
||||
span,
|
||||
opt_self_ty,
|
||||
did,
|
||||
|
|
@ -2630,7 +2517,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
|
||||
debug!(?maybe_qself, ?path);
|
||||
let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself));
|
||||
self.lower_path(opt_self_ty, path, hir_ty.hir_id, false)
|
||||
self.lower_resolved_ty_path(opt_self_ty, path, hir_ty.hir_id, PermitVariants::No)
|
||||
}
|
||||
&hir::TyKind::OpaqueDef(opaque_ty) => {
|
||||
// If this is an RPITIT and we are using the new RPITIT lowering scheme, we
|
||||
|
|
@ -2684,12 +2571,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let guar = self.dcx().emit_err(BadReturnTypeNotation { span: hir_ty.span });
|
||||
Ty::new_error(tcx, guar)
|
||||
}
|
||||
hir::TyKind::Path(hir::QPath::TypeRelative(qself, segment)) => {
|
||||
debug!(?qself, ?segment);
|
||||
let ty = self.lower_ty(qself);
|
||||
self.lower_assoc_path_ty(hir_ty.hir_id, hir_ty.span, ty, qself, segment, false)
|
||||
.map(|(ty, _, _)| ty)
|
||||
.unwrap_or_else(|guar| Ty::new_error(tcx, guar))
|
||||
hir::TyKind::Path(hir::QPath::TypeRelative(hir_self_ty, segment)) => {
|
||||
debug!(?hir_self_ty, ?segment);
|
||||
let self_ty = self.lower_ty(hir_self_ty);
|
||||
self.lower_type_relative_ty_path(
|
||||
self_ty,
|
||||
hir_self_ty,
|
||||
segment,
|
||||
hir_ty.hir_id,
|
||||
hir_ty.span,
|
||||
PermitVariants::No,
|
||||
)
|
||||
.map(|(ty, _, _)| ty)
|
||||
.unwrap_or_else(|guar| Ty::new_error(tcx, guar))
|
||||
}
|
||||
&hir::TyKind::Path(hir::QPath::LangItem(lang_item, span)) => {
|
||||
let def_id = tcx.require_lang_item(lang_item, Some(span));
|
||||
|
|
|
|||
|
|
@ -1854,17 +1854,16 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
fcx.err_ctxt().report_mismatched_types(cause, fcx.param_env, expected, found, ty_err);
|
||||
|
||||
let due_to_block = matches!(fcx.tcx.hir_node(block_or_return_id), hir::Node::Block(..));
|
||||
|
||||
let parent_id = fcx.tcx.parent_hir_id(block_or_return_id);
|
||||
let parent = fcx.tcx.hir_node(parent_id);
|
||||
let parent = fcx.tcx.parent_hir_node(block_or_return_id);
|
||||
if let Some(expr) = expression
|
||||
&& let hir::Node::Expr(&hir::Expr {
|
||||
kind: hir::ExprKind::Closure(&hir::Closure { body, .. }),
|
||||
..
|
||||
}) = parent
|
||||
&& !matches!(fcx.tcx.hir_body(body).value.kind, hir::ExprKind::Block(..))
|
||||
{
|
||||
fcx.suggest_missing_semicolon(&mut err, expr, expected, true);
|
||||
let needs_block =
|
||||
!matches!(fcx.tcx.hir_body(body).value.kind, hir::ExprKind::Block(..));
|
||||
fcx.suggest_missing_semicolon(&mut err, expr, expected, needs_block, true);
|
||||
}
|
||||
// Verify that this is a tail expression of a function, otherwise the
|
||||
// label pointing out the cause for the type coercion will be wrong
|
||||
|
|
@ -1872,7 +1871,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
if let Some(expr) = expression
|
||||
&& due_to_block
|
||||
{
|
||||
fcx.suggest_missing_semicolon(&mut err, expr, expected, false);
|
||||
fcx.suggest_missing_semicolon(&mut err, expr, expected, false, false);
|
||||
let pointing_at_return_type = fcx.suggest_mismatched_types_on_tail(
|
||||
&mut err,
|
||||
expr,
|
||||
|
|
|
|||
|
|
@ -911,7 +911,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self,
|
||||
&cause,
|
||||
|mut err| {
|
||||
self.suggest_missing_semicolon(&mut err, expr, e_ty, false);
|
||||
self.suggest_missing_semicolon(&mut err, expr, e_ty, false, false);
|
||||
self.suggest_mismatched_types_on_tail(
|
||||
&mut err, expr, ty, e_ty, target_id,
|
||||
);
|
||||
|
|
@ -1900,62 +1900,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// We defer checking whether the element type is `Copy` as it is possible to have
|
||||
// an inference variable as a repeat count and it seems unlikely that `Copy` would
|
||||
// have inference side effects required for type checking to succeed.
|
||||
if tcx.features().generic_arg_infer() {
|
||||
self.deferred_repeat_expr_checks.borrow_mut().push((element, element_ty, count));
|
||||
// If the length is 0, we don't create any elements, so we don't copy any.
|
||||
// If the length is 1, we don't copy that one element, we move it. Only check
|
||||
// for `Copy` if the length is larger, or unevaluated.
|
||||
} else if count.try_to_target_usize(self.tcx).is_none_or(|x| x > 1) {
|
||||
self.enforce_repeat_element_needs_copy_bound(element, element_ty);
|
||||
}
|
||||
self.deferred_repeat_expr_checks.borrow_mut().push((element, element_ty, count));
|
||||
|
||||
let ty = Ty::new_array_with_const_len(tcx, t, count);
|
||||
self.register_wf_obligation(ty.into(), expr.span, ObligationCauseCode::WellFormed(None));
|
||||
ty
|
||||
}
|
||||
|
||||
/// Requires that `element_ty` is `Copy` (unless it's a const expression itself).
|
||||
pub(super) fn enforce_repeat_element_needs_copy_bound(
|
||||
&self,
|
||||
element: &hir::Expr<'_>,
|
||||
element_ty: Ty<'tcx>,
|
||||
) {
|
||||
let tcx = self.tcx;
|
||||
// Actual constants as the repeat element get inserted repeatedly instead of getting copied via Copy.
|
||||
match &element.kind {
|
||||
hir::ExprKind::ConstBlock(..) => return,
|
||||
hir::ExprKind::Path(qpath) => {
|
||||
let res = self.typeck_results.borrow().qpath_res(qpath, element.hir_id);
|
||||
if let Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::AnonConst, _) = res
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
// If someone calls a const fn or constructs a const value, they can extract that
|
||||
// out into a separate constant (or a const block in the future), so we check that
|
||||
// to tell them that in the diagnostic. Does not affect typeck.
|
||||
let is_constable = match element.kind {
|
||||
hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() {
|
||||
ty::FnDef(def_id, _) if tcx.is_stable_const_fn(def_id) => traits::IsConstable::Fn,
|
||||
_ => traits::IsConstable::No,
|
||||
},
|
||||
hir::ExprKind::Path(qpath) => {
|
||||
match self.typeck_results.borrow().qpath_res(&qpath, element.hir_id) {
|
||||
Res::Def(DefKind::Ctor(_, CtorKind::Const), _) => traits::IsConstable::Ctor,
|
||||
_ => traits::IsConstable::No,
|
||||
}
|
||||
}
|
||||
_ => traits::IsConstable::No,
|
||||
};
|
||||
|
||||
let lang_item = self.tcx.require_lang_item(LangItem::Copy, None);
|
||||
let code =
|
||||
traits::ObligationCauseCode::RepeatElementCopy { is_constable, elt_span: element.span };
|
||||
self.require_type_meets(element_ty, element.span, code, lang_item);
|
||||
}
|
||||
|
||||
fn check_expr_tuple(
|
||||
&self,
|
||||
elts: &'tcx [hir::Expr<'tcx>],
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ use itertools::Itertools;
|
|||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, a_or_an, listify, pluralize};
|
||||
use rustc_hir::def::{CtorOf, DefKind, Res};
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::{ExprKind, HirId, Node, QPath};
|
||||
use rustc_hir::{ExprKind, HirId, LangItem, Node, QPath};
|
||||
use rustc_hir_analysis::check::potentially_plural_count;
|
||||
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
|
||||
use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, PermitVariants};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TypeTrace};
|
||||
use rustc_middle::ty::adjustment::AllowTwoPhase;
|
||||
|
|
@ -104,24 +104,96 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
pub(in super::super) fn check_repeat_exprs(&self) {
|
||||
let mut deferred_repeat_expr_checks = self.deferred_repeat_expr_checks.borrow_mut();
|
||||
debug!("FnCtxt::check_repeat_exprs: {} deferred checks", deferred_repeat_expr_checks.len());
|
||||
for (element, element_ty, count) in deferred_repeat_expr_checks.drain(..) {
|
||||
// We want to emit an error if the const is not structurally resolveable as otherwise
|
||||
// we can find up conservatively proving `Copy` which may infer the repeat expr count
|
||||
// to something that never required `Copy` in the first place.
|
||||
let count =
|
||||
self.structurally_resolve_const(element.span, self.normalize(element.span, count));
|
||||
|
||||
// Avoid run on "`NotCopy: Copy` is not implemented" errors when the repeat expr count
|
||||
// is erroneous/unknown. The user might wind up specifying a repeat count of 0/1.
|
||||
if count.references_error() {
|
||||
continue;
|
||||
}
|
||||
let deferred_repeat_expr_checks = deferred_repeat_expr_checks
|
||||
.drain(..)
|
||||
.flat_map(|(element, element_ty, count)| {
|
||||
// Actual constants as the repeat element are inserted repeatedly instead
|
||||
// of being copied via `Copy`, so we don't need to attempt to structurally
|
||||
// resolve the repeat count which may unnecessarily error.
|
||||
match &element.kind {
|
||||
hir::ExprKind::ConstBlock(..) => return None,
|
||||
hir::ExprKind::Path(qpath) => {
|
||||
let res = self.typeck_results.borrow().qpath_res(qpath, element.hir_id);
|
||||
if let Res::Def(DefKind::Const | DefKind::AssocConst, _) = res {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// If the length is 0, we don't create any elements, so we don't copy any.
|
||||
// If the length is 1, we don't copy that one element, we move it. Only check
|
||||
// for `Copy` if the length is larger.
|
||||
if count.try_to_target_usize(self.tcx).is_none_or(|x| x > 1) {
|
||||
self.enforce_repeat_element_needs_copy_bound(element, element_ty);
|
||||
// We want to emit an error if the const is not structurally resolveable
|
||||
// as otherwise we can wind up conservatively proving `Copy` which may
|
||||
// infer the repeat expr count to something that never required `Copy` in
|
||||
// the first place.
|
||||
let count = self
|
||||
.structurally_resolve_const(element.span, self.normalize(element.span, count));
|
||||
|
||||
// Avoid run on "`NotCopy: Copy` is not implemented" errors when the
|
||||
// repeat expr count is erroneous/unknown. The user might wind up
|
||||
// specifying a repeat count of 0/1.
|
||||
if count.references_error() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some((element, element_ty, count))
|
||||
})
|
||||
// We collect to force the side effects of structurally resolving the repeat
|
||||
// count to happen in one go, to avoid side effects from proving `Copy`
|
||||
// affecting whether repeat counts are known or not. If we did not do this we
|
||||
// would get results that depend on the order that we evaluate each repeat
|
||||
// expr's `Copy` check.
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let enforce_copy_bound = |element: &hir::Expr<'_>, element_ty| {
|
||||
// If someone calls a const fn or constructs a const value, they can extract that
|
||||
// out into a separate constant (or a const block in the future), so we check that
|
||||
// to tell them that in the diagnostic. Does not affect typeck.
|
||||
let is_constable = match element.kind {
|
||||
hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() {
|
||||
ty::FnDef(def_id, _) if self.tcx.is_stable_const_fn(def_id) => {
|
||||
traits::IsConstable::Fn
|
||||
}
|
||||
_ => traits::IsConstable::No,
|
||||
},
|
||||
hir::ExprKind::Path(qpath) => {
|
||||
match self.typeck_results.borrow().qpath_res(&qpath, element.hir_id) {
|
||||
Res::Def(DefKind::Ctor(_, CtorKind::Const), _) => traits::IsConstable::Ctor,
|
||||
_ => traits::IsConstable::No,
|
||||
}
|
||||
}
|
||||
_ => traits::IsConstable::No,
|
||||
};
|
||||
|
||||
let lang_item = self.tcx.require_lang_item(LangItem::Copy, None);
|
||||
let code = traits::ObligationCauseCode::RepeatElementCopy {
|
||||
is_constable,
|
||||
elt_span: element.span,
|
||||
};
|
||||
self.require_type_meets(element_ty, element.span, code, lang_item);
|
||||
};
|
||||
|
||||
for (element, element_ty, count) in deferred_repeat_expr_checks {
|
||||
match count.kind() {
|
||||
ty::ConstKind::Value(val) => {
|
||||
if val.try_to_target_usize(self.tcx).is_none_or(|count| count > 1) {
|
||||
enforce_copy_bound(element, element_ty)
|
||||
} else {
|
||||
// If the length is 0 or 1 we don't actually copy the element, we either don't create it
|
||||
// or we just use the one value.
|
||||
}
|
||||
}
|
||||
|
||||
// If the length is a generic parameter or some rigid alias then conservatively
|
||||
// require `element_ty: Copy` as it may wind up being `>1` after monomorphization.
|
||||
ty::ConstKind::Param(_)
|
||||
| ty::ConstKind::Expr(_)
|
||||
| ty::ConstKind::Placeholder(_)
|
||||
| ty::ConstKind::Unevaluated(_) => enforce_copy_bound(element, element_ty),
|
||||
|
||||
ty::ConstKind::Bound(_, _) | ty::ConstKind::Infer(_) | ty::ConstKind::Error(_) => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2105,15 +2177,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
match *qpath {
|
||||
QPath::Resolved(ref maybe_qself, path) => {
|
||||
let self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself).raw);
|
||||
let ty = self.lowerer().lower_path(self_ty, path, hir_id, true);
|
||||
let ty = self.lowerer().lower_resolved_ty_path(
|
||||
self_ty,
|
||||
path,
|
||||
hir_id,
|
||||
PermitVariants::Yes,
|
||||
);
|
||||
(path.res, LoweredTy::from_raw(self, path_span, ty))
|
||||
}
|
||||
QPath::TypeRelative(qself, segment) => {
|
||||
let ty = self.lower_ty(qself);
|
||||
QPath::TypeRelative(hir_self_ty, segment) => {
|
||||
let self_ty = self.lower_ty(hir_self_ty);
|
||||
|
||||
let result = self
|
||||
.lowerer()
|
||||
.lower_assoc_path_ty(hir_id, path_span, ty.raw, qself, segment, true);
|
||||
let result = self.lowerer().lower_type_relative_ty_path(
|
||||
self_ty.raw,
|
||||
hir_self_ty,
|
||||
segment,
|
||||
hir_id,
|
||||
path_span,
|
||||
PermitVariants::Yes,
|
||||
);
|
||||
let ty = result
|
||||
.map(|(ty, _, _)| ty)
|
||||
.unwrap_or_else(|guar| Ty::new_error(self.tcx(), guar));
|
||||
|
|
|
|||
|
|
@ -308,17 +308,16 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
|
|||
))
|
||||
}
|
||||
|
||||
fn lower_assoc_shared(
|
||||
fn lower_assoc_item_path(
|
||||
&self,
|
||||
span: Span,
|
||||
item_def_id: DefId,
|
||||
item_segment: &rustc_hir::PathSegment<'tcx>,
|
||||
poly_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
_assoc_tag: ty::AssocTag,
|
||||
) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> {
|
||||
let trait_ref = self.instantiate_binder_with_fresh_vars(
|
||||
span,
|
||||
// FIXME(mgca): this should be assoc const if that is the `kind`
|
||||
// FIXME(mgca): `item_def_id` can be an AssocConst; rename this variant.
|
||||
infer::BoundRegionConversionTime::AssocTypeProjection(item_def_id),
|
||||
poly_trait_ref,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -764,6 +764,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
expression: &'tcx hir::Expr<'tcx>,
|
||||
expected: Ty<'tcx>,
|
||||
needs_block: bool,
|
||||
parent_is_closure: bool,
|
||||
) {
|
||||
if expected.is_unit() {
|
||||
// `BlockTailExpression` only relevant if the tail expr would be
|
||||
|
|
@ -799,6 +800,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
}
|
||||
ExprKind::Path(..) | ExprKind::Lit(_)
|
||||
if parent_is_closure
|
||||
&& !expression.span.in_external_macro(self.tcx.sess.source_map()) =>
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
expression.span.shrink_to_lo(),
|
||||
"consider ignoring the value",
|
||||
"_ = ",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -196,13 +196,16 @@ fn typeck_with_inspect<'tcx>(
|
|||
fcx.write_ty(id, expected_type);
|
||||
};
|
||||
|
||||
// Whether to check repeat exprs before/after inference fallback is somewhat arbitrary of a decision
|
||||
// as neither option is strictly more permissive than the other. However, we opt to check repeat exprs
|
||||
// first as errors from not having inferred array lengths yet seem less confusing than errors from inference
|
||||
// fallback arbitrarily inferring something incompatible with `Copy` inference side effects.
|
||||
// Whether to check repeat exprs before/after inference fallback is somewhat
|
||||
// arbitrary of a decision as neither option is strictly more permissive than
|
||||
// the other. However, we opt to check repeat exprs first as errors from not
|
||||
// having inferred array lengths yet seem less confusing than errors from inference
|
||||
// fallback arbitrarily inferring something incompatible with `Copy` inference
|
||||
// side effects.
|
||||
//
|
||||
// This should also be forwards compatible with moving repeat expr checks to a custom goal kind or using
|
||||
// marker traits in the future.
|
||||
// FIXME(#140855): This should also be forwards compatible with moving
|
||||
// repeat expr checks to a custom goal kind or using marker traits in
|
||||
// the future.
|
||||
fcx.check_repeat_exprs();
|
||||
|
||||
fcx.type_inference_fallback();
|
||||
|
|
|
|||
|
|
@ -291,6 +291,14 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
|||
probe::ObjectPick => {
|
||||
let trait_def_id = pick.item.container_id(self.tcx);
|
||||
|
||||
// If the trait is not object safe (specifically, we care about when
|
||||
// the receiver is not valid), then there's a chance that we will not
|
||||
// actually be able to recover the object by derefing the receiver like
|
||||
// we should if it were valid.
|
||||
if !self.tcx.is_dyn_compatible(trait_def_id) {
|
||||
return ty::GenericArgs::extend_with_error(self.tcx, trait_def_id, &[]);
|
||||
}
|
||||
|
||||
// This shouldn't happen for non-region error kinds, but may occur
|
||||
// when we have error regions. Specifically, since we canonicalize
|
||||
// during method steps, we may successfully deref when we assemble
|
||||
|
|
|
|||
|
|
@ -17,8 +17,7 @@ use tracing::debug;
|
|||
|
||||
use crate::infer::InferCtxt;
|
||||
use crate::infer::canonical::{
|
||||
Canonical, CanonicalQueryInput, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind,
|
||||
OriginalQueryValues,
|
||||
Canonical, CanonicalQueryInput, CanonicalTyVarKind, CanonicalVarKind, OriginalQueryValues,
|
||||
};
|
||||
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
|
|
@ -174,10 +173,8 @@ impl CanonicalizeMode for CanonicalizeQueryResponse {
|
|||
match r.kind() {
|
||||
ty::ReLateParam(_) | ty::ReErased | ty::ReStatic | ty::ReEarlyParam(..) => r,
|
||||
|
||||
ty::RePlaceholder(placeholder) => canonicalizer.canonical_var_for_region(
|
||||
CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderRegion(placeholder) },
|
||||
r,
|
||||
),
|
||||
ty::RePlaceholder(placeholder) => canonicalizer
|
||||
.canonical_var_for_region(CanonicalVarKind::PlaceholderRegion(placeholder), r),
|
||||
|
||||
ty::ReVar(vid) => {
|
||||
let universe = infcx
|
||||
|
|
@ -186,10 +183,7 @@ impl CanonicalizeMode for CanonicalizeQueryResponse {
|
|||
.unwrap_region_constraints()
|
||||
.probe_value(vid)
|
||||
.unwrap_err();
|
||||
canonicalizer.canonical_var_for_region(
|
||||
CanonicalVarInfo { kind: CanonicalVarKind::Region(universe) },
|
||||
r,
|
||||
)
|
||||
canonicalizer.canonical_var_for_region(CanonicalVarKind::Region(universe), r)
|
||||
}
|
||||
|
||||
_ => {
|
||||
|
|
@ -294,7 +288,7 @@ struct Canonicalizer<'cx, 'tcx> {
|
|||
/// Set to `None` to disable the resolution of inference variables.
|
||||
infcx: Option<&'cx InferCtxt<'tcx>>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
variables: SmallVec<[CanonicalVarInfo<'tcx>; 8]>,
|
||||
variables: SmallVec<[CanonicalVarKind<'tcx>; 8]>,
|
||||
query_state: &'cx mut OriginalQueryValues<'tcx>,
|
||||
// Note that indices is only used once `var_values` is big enough to be
|
||||
// heap-allocated.
|
||||
|
|
@ -368,9 +362,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
|
|||
ui = ty::UniverseIndex::ROOT;
|
||||
}
|
||||
self.canonicalize_ty_var(
|
||||
CanonicalVarInfo {
|
||||
kind: CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
|
||||
},
|
||||
CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
|
||||
t,
|
||||
)
|
||||
}
|
||||
|
|
@ -382,10 +374,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
|
|||
if nt != t {
|
||||
return self.fold_ty(nt);
|
||||
} else {
|
||||
self.canonicalize_ty_var(
|
||||
CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Int) },
|
||||
t,
|
||||
)
|
||||
self.canonicalize_ty_var(CanonicalVarKind::Ty(CanonicalTyVarKind::Int), t)
|
||||
}
|
||||
}
|
||||
ty::Infer(ty::FloatVar(vid)) => {
|
||||
|
|
@ -393,10 +382,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
|
|||
if nt != t {
|
||||
return self.fold_ty(nt);
|
||||
} else {
|
||||
self.canonicalize_ty_var(
|
||||
CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Float) },
|
||||
t,
|
||||
)
|
||||
self.canonicalize_ty_var(CanonicalVarKind::Ty(CanonicalTyVarKind::Float), t)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -408,10 +394,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
|
|||
if !self.canonicalize_mode.preserve_universes() {
|
||||
placeholder.universe = ty::UniverseIndex::ROOT;
|
||||
}
|
||||
self.canonicalize_ty_var(
|
||||
CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderTy(placeholder) },
|
||||
t,
|
||||
)
|
||||
self.canonicalize_ty_var(CanonicalVarKind::PlaceholderTy(placeholder), t)
|
||||
}
|
||||
|
||||
ty::Bound(debruijn, _) => {
|
||||
|
|
@ -483,10 +466,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
|
|||
// FIXME: perf problem described in #55921.
|
||||
ui = ty::UniverseIndex::ROOT;
|
||||
}
|
||||
return self.canonicalize_const_var(
|
||||
CanonicalVarInfo { kind: CanonicalVarKind::Const(ui) },
|
||||
ct,
|
||||
);
|
||||
return self.canonicalize_const_var(CanonicalVarKind::Const(ui), ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -501,10 +481,8 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
ty::ConstKind::Placeholder(placeholder) => {
|
||||
return self.canonicalize_const_var(
|
||||
CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderConst(placeholder) },
|
||||
ct,
|
||||
);
|
||||
return self
|
||||
.canonicalize_const_var(CanonicalVarKind::PlaceholderConst(placeholder), ct);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
@ -595,7 +573,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
|||
debug_assert!(!out_value.has_infer() && !out_value.has_placeholders());
|
||||
|
||||
let canonical_variables =
|
||||
tcx.mk_canonical_var_infos(&canonicalizer.universe_canonicalized_variables());
|
||||
tcx.mk_canonical_var_kinds(&canonicalizer.universe_canonicalized_variables());
|
||||
|
||||
let max_universe = canonical_variables
|
||||
.iter()
|
||||
|
|
@ -610,18 +588,22 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
|||
/// or returns an existing variable if `kind` has already been
|
||||
/// seen. `kind` is expected to be an unbound variable (or
|
||||
/// potentially a free region).
|
||||
fn canonical_var(&mut self, info: CanonicalVarInfo<'tcx>, kind: GenericArg<'tcx>) -> BoundVar {
|
||||
fn canonical_var(
|
||||
&mut self,
|
||||
var_kind: CanonicalVarKind<'tcx>,
|
||||
value: GenericArg<'tcx>,
|
||||
) -> BoundVar {
|
||||
let Canonicalizer { variables, query_state, indices, .. } = self;
|
||||
|
||||
let var_values = &mut query_state.var_values;
|
||||
|
||||
let universe = info.universe();
|
||||
let universe = var_kind.universe();
|
||||
if universe != ty::UniverseIndex::ROOT {
|
||||
assert!(self.canonicalize_mode.preserve_universes());
|
||||
|
||||
// Insert universe into the universe map. To preserve the order of the
|
||||
// universes in the value being canonicalized, we don't update the
|
||||
// universe in `info` until we have finished canonicalizing.
|
||||
// universe in `var_kind` until we have finished canonicalizing.
|
||||
match query_state.universe_map.binary_search(&universe) {
|
||||
Err(idx) => query_state.universe_map.insert(idx, universe),
|
||||
Ok(_) => {}
|
||||
|
|
@ -636,14 +618,14 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
|||
if !var_values.spilled() {
|
||||
// `var_values` is stack-allocated. `indices` isn't used yet. Do a
|
||||
// direct linear search of `var_values`.
|
||||
if let Some(idx) = var_values.iter().position(|&k| k == kind) {
|
||||
if let Some(idx) = var_values.iter().position(|&v| v == value) {
|
||||
// `kind` is already present in `var_values`.
|
||||
BoundVar::new(idx)
|
||||
} else {
|
||||
// `kind` isn't present in `var_values`. Append it. Likewise
|
||||
// for `info` and `variables`.
|
||||
variables.push(info);
|
||||
var_values.push(kind);
|
||||
// for `var_kind` and `variables`.
|
||||
variables.push(var_kind);
|
||||
var_values.push(value);
|
||||
assert_eq!(variables.len(), var_values.len());
|
||||
|
||||
// If `var_values` has become big enough to be heap-allocated,
|
||||
|
|
@ -653,7 +635,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
|||
*indices = var_values
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, &kind)| (kind, BoundVar::new(i)))
|
||||
.map(|(i, &value)| (value, BoundVar::new(i)))
|
||||
.collect();
|
||||
}
|
||||
// The cv is the index of the appended element.
|
||||
|
|
@ -661,9 +643,9 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
|||
}
|
||||
} else {
|
||||
// `var_values` is large. Do a hashmap search via `indices`.
|
||||
*indices.entry(kind).or_insert_with(|| {
|
||||
variables.push(info);
|
||||
var_values.push(kind);
|
||||
*indices.entry(value).or_insert_with(|| {
|
||||
variables.push(var_kind);
|
||||
var_values.push(value);
|
||||
assert_eq!(variables.len(), var_values.len());
|
||||
BoundVar::new(variables.len() - 1)
|
||||
})
|
||||
|
|
@ -673,7 +655,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
|||
/// Replaces the universe indexes used in `var_values` with their index in
|
||||
/// `query_state.universe_map`. This minimizes the maximum universe used in
|
||||
/// the canonicalized value.
|
||||
fn universe_canonicalized_variables(self) -> SmallVec<[CanonicalVarInfo<'tcx>; 8]> {
|
||||
fn universe_canonicalized_variables(self) -> SmallVec<[CanonicalVarKind<'tcx>; 8]> {
|
||||
if self.query_state.universe_map.len() == 1 {
|
||||
return self.variables;
|
||||
}
|
||||
|
|
@ -688,37 +670,33 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
|||
|
||||
self.variables
|
||||
.iter()
|
||||
.map(|v| CanonicalVarInfo {
|
||||
kind: match v.kind {
|
||||
CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => {
|
||||
return *v;
|
||||
}
|
||||
CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => {
|
||||
CanonicalVarKind::Ty(CanonicalTyVarKind::General(reverse_universe_map[&u]))
|
||||
}
|
||||
CanonicalVarKind::Region(u) => {
|
||||
CanonicalVarKind::Region(reverse_universe_map[&u])
|
||||
}
|
||||
CanonicalVarKind::Const(u) => CanonicalVarKind::Const(reverse_universe_map[&u]),
|
||||
CanonicalVarKind::PlaceholderTy(placeholder) => {
|
||||
CanonicalVarKind::PlaceholderTy(ty::Placeholder {
|
||||
universe: reverse_universe_map[&placeholder.universe],
|
||||
..placeholder
|
||||
})
|
||||
}
|
||||
CanonicalVarKind::PlaceholderRegion(placeholder) => {
|
||||
CanonicalVarKind::PlaceholderRegion(ty::Placeholder {
|
||||
universe: reverse_universe_map[&placeholder.universe],
|
||||
..placeholder
|
||||
})
|
||||
}
|
||||
CanonicalVarKind::PlaceholderConst(placeholder) => {
|
||||
CanonicalVarKind::PlaceholderConst(ty::Placeholder {
|
||||
universe: reverse_universe_map[&placeholder.universe],
|
||||
..placeholder
|
||||
})
|
||||
}
|
||||
},
|
||||
.map(|&kind| match kind {
|
||||
CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => {
|
||||
return kind;
|
||||
}
|
||||
CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => {
|
||||
CanonicalVarKind::Ty(CanonicalTyVarKind::General(reverse_universe_map[&u]))
|
||||
}
|
||||
CanonicalVarKind::Region(u) => CanonicalVarKind::Region(reverse_universe_map[&u]),
|
||||
CanonicalVarKind::Const(u) => CanonicalVarKind::Const(reverse_universe_map[&u]),
|
||||
CanonicalVarKind::PlaceholderTy(placeholder) => {
|
||||
CanonicalVarKind::PlaceholderTy(ty::Placeholder {
|
||||
universe: reverse_universe_map[&placeholder.universe],
|
||||
..placeholder
|
||||
})
|
||||
}
|
||||
CanonicalVarKind::PlaceholderRegion(placeholder) => {
|
||||
CanonicalVarKind::PlaceholderRegion(ty::Placeholder {
|
||||
universe: reverse_universe_map[&placeholder.universe],
|
||||
..placeholder
|
||||
})
|
||||
}
|
||||
CanonicalVarKind::PlaceholderConst(placeholder) => {
|
||||
CanonicalVarKind::PlaceholderConst(ty::Placeholder {
|
||||
universe: reverse_universe_map[&placeholder.universe],
|
||||
..placeholder
|
||||
})
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
|
@ -740,20 +718,17 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
|||
&mut self,
|
||||
r: ty::Region<'tcx>,
|
||||
) -> ty::Region<'tcx> {
|
||||
self.canonical_var_for_region(
|
||||
CanonicalVarInfo { kind: CanonicalVarKind::Region(ty::UniverseIndex::ROOT) },
|
||||
r,
|
||||
)
|
||||
self.canonical_var_for_region(CanonicalVarKind::Region(ty::UniverseIndex::ROOT), r)
|
||||
}
|
||||
|
||||
/// Creates a canonical variable (with the given `info`)
|
||||
/// representing the region `r`; return a region referencing it.
|
||||
fn canonical_var_for_region(
|
||||
&mut self,
|
||||
info: CanonicalVarInfo<'tcx>,
|
||||
var_kind: CanonicalVarKind<'tcx>,
|
||||
r: ty::Region<'tcx>,
|
||||
) -> ty::Region<'tcx> {
|
||||
let var = self.canonical_var(info, r.into());
|
||||
let var = self.canonical_var(var_kind, r.into());
|
||||
let br = ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon };
|
||||
ty::Region::new_bound(self.cx(), self.binder_index, br)
|
||||
}
|
||||
|
|
@ -762,9 +737,13 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
|||
/// if `ty_var` is bound to anything; if so, canonicalize
|
||||
/// *that*. Otherwise, create a new canonical variable for
|
||||
/// `ty_var`.
|
||||
fn canonicalize_ty_var(&mut self, info: CanonicalVarInfo<'tcx>, ty_var: Ty<'tcx>) -> Ty<'tcx> {
|
||||
fn canonicalize_ty_var(
|
||||
&mut self,
|
||||
var_kind: CanonicalVarKind<'tcx>,
|
||||
ty_var: Ty<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
debug_assert!(!self.infcx.is_some_and(|infcx| ty_var != infcx.shallow_resolve(ty_var)));
|
||||
let var = self.canonical_var(info, ty_var.into());
|
||||
let var = self.canonical_var(var_kind, ty_var.into());
|
||||
Ty::new_bound(self.tcx, self.binder_index, var.into())
|
||||
}
|
||||
|
||||
|
|
@ -774,13 +753,13 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
|||
/// `const_var`.
|
||||
fn canonicalize_const_var(
|
||||
&mut self,
|
||||
info: CanonicalVarInfo<'tcx>,
|
||||
const_var: ty::Const<'tcx>,
|
||||
var_kind: CanonicalVarKind<'tcx>,
|
||||
ct_var: ty::Const<'tcx>,
|
||||
) -> ty::Const<'tcx> {
|
||||
debug_assert!(
|
||||
!self.infcx.is_some_and(|infcx| const_var != infcx.shallow_resolve_const(const_var))
|
||||
!self.infcx.is_some_and(|infcx| ct_var != infcx.shallow_resolve_const(ct_var))
|
||||
);
|
||||
let var = self.canonical_var(info, const_var.into());
|
||||
let var = self.canonical_var(var_kind, ct_var.into());
|
||||
ty::Const::new_bound(self.tcx, self.binder_index, var)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,14 +81,14 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
fn instantiate_canonical_vars(
|
||||
&self,
|
||||
span: Span,
|
||||
variables: &List<CanonicalVarInfo<'tcx>>,
|
||||
variables: &List<CanonicalVarKind<'tcx>>,
|
||||
universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
|
||||
) -> CanonicalVarValues<'tcx> {
|
||||
CanonicalVarValues {
|
||||
var_values: self.tcx.mk_args_from_iter(
|
||||
variables
|
||||
.iter()
|
||||
.map(|info| self.instantiate_canonical_var(span, info, &universe_map)),
|
||||
.map(|kind| self.instantiate_canonical_var(span, kind, &universe_map)),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
@ -104,10 +104,10 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
pub fn instantiate_canonical_var(
|
||||
&self,
|
||||
span: Span,
|
||||
cv_info: CanonicalVarInfo<'tcx>,
|
||||
kind: CanonicalVarKind<'tcx>,
|
||||
universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
|
||||
) -> GenericArg<'tcx> {
|
||||
match cv_info.kind {
|
||||
match kind {
|
||||
CanonicalVarKind::Ty(ty_kind) => {
|
||||
let ty = match ty_kind {
|
||||
CanonicalTyVarKind::General(ui) => {
|
||||
|
|
|
|||
|
|
@ -445,17 +445,17 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
// a fresh inference variable.
|
||||
let result_args = CanonicalVarValues {
|
||||
var_values: self.tcx.mk_args_from_iter(
|
||||
query_response.variables.iter().enumerate().map(|(index, info)| {
|
||||
if info.universe() != ty::UniverseIndex::ROOT {
|
||||
query_response.variables.iter().enumerate().map(|(index, var_kind)| {
|
||||
if var_kind.universe() != ty::UniverseIndex::ROOT {
|
||||
// A variable from inside a binder of the query. While ideally these shouldn't
|
||||
// exist at all, we have to deal with them for now.
|
||||
self.instantiate_canonical_var(cause.span, info, |u| {
|
||||
self.instantiate_canonical_var(cause.span, var_kind, |u| {
|
||||
universe_map[u.as_usize()]
|
||||
})
|
||||
} else if info.is_existential() {
|
||||
} else if var_kind.is_existential() {
|
||||
match opt_values[BoundVar::new(index)] {
|
||||
Some(k) => k,
|
||||
None => self.instantiate_canonical_var(cause.span, info, |u| {
|
||||
None => self.instantiate_canonical_var(cause.span, var_kind, |u| {
|
||||
universe_map[u.as_usize()]
|
||||
}),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -837,6 +837,7 @@ lint_unexpected_cfg_name_similar_name = there is a config with a similar name
|
|||
lint_unexpected_cfg_name_similar_name_different_values = there is a config with a similar name and different values
|
||||
lint_unexpected_cfg_name_similar_name_no_value = there is a config with a similar name and no value
|
||||
lint_unexpected_cfg_name_similar_name_value = there is a config with a similar name and value
|
||||
lint_unexpected_cfg_name_version_syntax = there is a similar config predicate: `version("..")`
|
||||
lint_unexpected_cfg_name_with_similar_value = found config with similar value
|
||||
|
||||
lint_unexpected_cfg_value = unexpected `cfg` condition value: {$has_value ->
|
||||
|
|
|
|||
|
|
@ -140,6 +140,14 @@ pub(super) fn unexpected_cfg_name(
|
|||
|
||||
let code_sugg = if is_feature_cfg && is_from_cargo {
|
||||
lints::unexpected_cfg_name::CodeSuggestion::DefineFeatures
|
||||
// Suggest correct `version("..")` predicate syntax
|
||||
} else if let Some((_value, value_span)) = value
|
||||
&& name == sym::version
|
||||
{
|
||||
lints::unexpected_cfg_name::CodeSuggestion::VersionSyntax {
|
||||
between_name_and_value: name_span.between(value_span),
|
||||
after_value: value_span.shrink_to_hi(),
|
||||
}
|
||||
// Suggest the most probable if we found one
|
||||
} else if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) {
|
||||
is_feature_cfg |= best_match == sym::feature;
|
||||
|
|
|
|||
|
|
@ -2299,6 +2299,16 @@ pub(crate) mod unexpected_cfg_name {
|
|||
pub(crate) enum CodeSuggestion {
|
||||
#[help(lint_unexpected_cfg_define_features)]
|
||||
DefineFeatures,
|
||||
#[multipart_suggestion(
|
||||
lint_unexpected_cfg_name_version_syntax,
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
VersionSyntax {
|
||||
#[suggestion_part(code = "(")]
|
||||
between_name_and_value: Span,
|
||||
#[suggestion_part(code = ")")]
|
||||
after_value: Span,
|
||||
},
|
||||
#[suggestion(
|
||||
lint_unexpected_cfg_name_similar_name_value,
|
||||
applicability = "maybe-incorrect",
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ declare_lint_pass! {
|
|||
/// that are used by other parts of the compiler.
|
||||
HardwiredLints => [
|
||||
// tidy-alphabetical-start
|
||||
AARCH64_SOFTFLOAT_NEON,
|
||||
ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
|
||||
AMBIGUOUS_ASSOCIATED_ITEMS,
|
||||
AMBIGUOUS_GLOB_IMPORTS,
|
||||
|
|
@ -5043,14 +5044,14 @@ declare_lint! {
|
|||
///
|
||||
/// ```text
|
||||
/// error: this function function definition is affected by the wasm ABI transition: it passes an argument of non-scalar type `MyType`
|
||||
/// --> $DIR/wasm_c_abi_transition.rs:17:1
|
||||
/// |
|
||||
/// | pub extern "C" fn my_fun(_x: MyType) {}
|
||||
/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
/// |
|
||||
/// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
/// = note: for more information, see issue #138762 <https://github.com/rust-lang/rust/issues/138762>
|
||||
/// = help: the "C" ABI Rust uses on wasm32-unknown-unknown will change to align with the standard "C" ABI for this target
|
||||
/// --> $DIR/wasm_c_abi_transition.rs:17:1
|
||||
/// |
|
||||
/// | pub extern "C" fn my_fun(_x: MyType) {}
|
||||
/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
/// |
|
||||
/// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
/// = note: for more information, see issue #138762 <https://github.com/rust-lang/rust/issues/138762>
|
||||
/// = help: the "C" ABI Rust uses on wasm32-unknown-unknown will change to align with the standard "C" ABI for this target
|
||||
/// ```
|
||||
///
|
||||
/// ### Explanation
|
||||
|
|
@ -5067,3 +5068,44 @@ declare_lint! {
|
|||
reference: "issue #138762 <https://github.com/rust-lang/rust/issues/138762>",
|
||||
};
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `aarch64_softfloat_neon` lint detects usage of `#[target_feature(enable = "neon")]` on
|
||||
/// softfloat aarch64 targets. Enabling this target feature causes LLVM to alter the ABI of
|
||||
/// function calls, making this attribute unsound to use.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,ignore (needs aarch64-unknown-none-softfloat)
|
||||
/// #[target_feature(enable = "neon")]
|
||||
/// fn with_neon() {}
|
||||
/// ```
|
||||
///
|
||||
/// This will produce:
|
||||
///
|
||||
/// ```text
|
||||
/// error: enabling the `neon` target feature on the current target is unsound due to ABI issues
|
||||
/// --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:11:18
|
||||
/// |
|
||||
/// | #[target_feature(enable = "neon")]
|
||||
/// | ^^^^^^^^^^^^^^^
|
||||
/// |
|
||||
/// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
/// = note: for more information, see issue #134375 <https://github.com/rust-lang/rust/issues/134375>
|
||||
/// ```
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// If a function like `with_neon` above ends up containing calls to LLVM builtins, those will
|
||||
/// not use the correct ABI. This is caused by a lack of support in LLVM for mixing code with
|
||||
/// and without the `neon` target feature. The target feature should never have been stabilized
|
||||
/// on this target due to this issue, but the problem was not known at the time of
|
||||
/// stabilization.
|
||||
pub AARCH64_SOFTFLOAT_NEON,
|
||||
Warn,
|
||||
"detects code that could be affected by ABI issues on aarch64 softfloat targets",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
|
||||
reference: "issue #134375 <https://github.com/rust-lang/rust/issues/134375>",
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -425,6 +425,7 @@ provide! { tcx, def_id, other, cdata,
|
|||
doc_link_traits_in_scope => {
|
||||
tcx.arena.alloc_from_iter(cdata.get_doc_link_traits_in_scope(def_id.index))
|
||||
}
|
||||
anon_const_kind => { table }
|
||||
}
|
||||
|
||||
pub(in crate::rmeta) fn provide(providers: &mut Providers) {
|
||||
|
|
|
|||
|
|
@ -1569,6 +1569,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
<- tcx.explicit_implied_const_bounds(def_id).skip_binder());
|
||||
}
|
||||
}
|
||||
if let DefKind::AnonConst = def_kind {
|
||||
record!(self.tables.anon_const_kind[def_id] <- self.tcx.anon_const_kind(def_id));
|
||||
}
|
||||
if tcx.impl_method_has_trait_impl_trait_tys(def_id)
|
||||
&& let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -480,6 +480,7 @@ define_tables! {
|
|||
doc_link_traits_in_scope: Table<DefIndex, LazyArray<DefId>>,
|
||||
assumed_wf_types_for_rpitit: Table<DefIndex, LazyArray<(Ty<'static>, Span)>>,
|
||||
opaque_ty_origin: Table<DefIndex, LazyValue<hir::OpaqueTyOrigin<DefId>>>,
|
||||
anon_const_kind: Table<DefIndex, LazyValue<ty::AnonConstKind>>,
|
||||
}
|
||||
|
||||
#[derive(TyEncodable, TyDecodable)]
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ use rustc_data_structures::fx::FxHashMap;
|
|||
use rustc_data_structures::sync::Lock;
|
||||
use rustc_macros::{HashStable, TypeFoldable, TypeVisitable};
|
||||
pub use rustc_type_ir as ir;
|
||||
pub use rustc_type_ir::{CanonicalTyVarKind, CanonicalVarKind};
|
||||
pub use rustc_type_ir::CanonicalTyVarKind;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::mir::ConstraintCategory;
|
||||
|
|
@ -35,9 +35,9 @@ use crate::ty::{self, GenericArg, List, Ty, TyCtxt, TypeFlags, TypeVisitableExt}
|
|||
|
||||
pub type CanonicalQueryInput<'tcx, V> = ir::CanonicalQueryInput<TyCtxt<'tcx>, V>;
|
||||
pub type Canonical<'tcx, V> = ir::Canonical<TyCtxt<'tcx>, V>;
|
||||
pub type CanonicalVarInfo<'tcx> = ir::CanonicalVarInfo<TyCtxt<'tcx>>;
|
||||
pub type CanonicalVarKind<'tcx> = ir::CanonicalVarKind<TyCtxt<'tcx>>;
|
||||
pub type CanonicalVarValues<'tcx> = ir::CanonicalVarValues<TyCtxt<'tcx>>;
|
||||
pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo<'tcx>>;
|
||||
pub type CanonicalVarKinds<'tcx> = &'tcx List<CanonicalVarKind<'tcx>>;
|
||||
|
||||
/// When we canonicalize a value to form a query, we wind up replacing
|
||||
/// various parts of it with canonical variables. This struct stores
|
||||
|
|
|
|||
|
|
@ -96,49 +96,46 @@ bitflags::bitflags! {
|
|||
/// `#[cold]`: a hint to LLVM that this function, when called, is never on
|
||||
/// the hot path.
|
||||
const COLD = 1 << 0;
|
||||
/// `#[rustc_allocator]`: a hint to LLVM that the pointer returned from this
|
||||
/// function is never null and the function has no side effects other than allocating.
|
||||
const ALLOCATOR = 1 << 1;
|
||||
/// An indicator that function will never unwind. Will become obsolete
|
||||
/// once C-unwind is fully stabilized.
|
||||
const NEVER_UNWIND = 1 << 3;
|
||||
/// `#[rustc_nounwind]`: An indicator that function will never unwind.
|
||||
const NEVER_UNWIND = 1 << 1;
|
||||
/// `#[naked]`: an indicator to LLVM that no function prologue/epilogue
|
||||
/// should be generated.
|
||||
const NAKED = 1 << 4;
|
||||
const NAKED = 1 << 2;
|
||||
/// `#[no_mangle]`: an indicator that the function's name should be the same
|
||||
/// as its symbol.
|
||||
const NO_MANGLE = 1 << 5;
|
||||
const NO_MANGLE = 1 << 3;
|
||||
/// `#[rustc_std_internal_symbol]`: an indicator that this symbol is a
|
||||
/// "weird symbol" for the standard library in that it has slightly
|
||||
/// different linkage, visibility, and reachability rules.
|
||||
const RUSTC_STD_INTERNAL_SYMBOL = 1 << 6;
|
||||
const RUSTC_STD_INTERNAL_SYMBOL = 1 << 4;
|
||||
/// `#[thread_local]`: indicates a static is actually a thread local
|
||||
/// piece of memory
|
||||
const THREAD_LOCAL = 1 << 8;
|
||||
/// `#[used]`: indicates that LLVM can't eliminate this function (but the
|
||||
const THREAD_LOCAL = 1 << 5;
|
||||
/// `#[used(compiler)]`: indicates that LLVM can't eliminate this function (but the
|
||||
/// linker can!).
|
||||
const USED = 1 << 9;
|
||||
/// `#[track_caller]`: allow access to the caller location
|
||||
const TRACK_CALLER = 1 << 10;
|
||||
/// #[ffi_pure]: applies clang's `pure` attribute to a foreign function
|
||||
/// declaration.
|
||||
const FFI_PURE = 1 << 11;
|
||||
/// #[ffi_const]: applies clang's `const` attribute to a foreign function
|
||||
/// declaration.
|
||||
const FFI_CONST = 1 << 12;
|
||||
// (Bit 13 was used for `#[cmse_nonsecure_entry]`, but is now unused.)
|
||||
// (Bit 14 was used for `#[coverage(off)]`, but is now unused.)
|
||||
const USED_COMPILER = 1 << 6;
|
||||
/// `#[used(linker)]`:
|
||||
/// indicates that neither LLVM nor the linker will eliminate this function.
|
||||
const USED_LINKER = 1 << 15;
|
||||
const USED_LINKER = 1 << 7;
|
||||
/// `#[track_caller]`: allow access to the caller location
|
||||
const TRACK_CALLER = 1 << 8;
|
||||
/// #[ffi_pure]: applies clang's `pure` attribute to a foreign function
|
||||
/// declaration.
|
||||
const FFI_PURE = 1 << 9;
|
||||
/// #[ffi_const]: applies clang's `const` attribute to a foreign function
|
||||
/// declaration.
|
||||
const FFI_CONST = 1 << 10;
|
||||
/// `#[rustc_allocator]`: a hint to LLVM that the pointer returned from this
|
||||
/// function is never null and the function has no side effects other than allocating.
|
||||
const ALLOCATOR = 1 << 11;
|
||||
/// `#[rustc_deallocator]`: a hint to LLVM that the function only deallocates memory.
|
||||
const DEALLOCATOR = 1 << 16;
|
||||
const DEALLOCATOR = 1 << 12;
|
||||
/// `#[rustc_reallocator]`: a hint to LLVM that the function only reallocates memory.
|
||||
const REALLOCATOR = 1 << 17;
|
||||
const REALLOCATOR = 1 << 13;
|
||||
/// `#[rustc_allocator_zeroed]`: a hint to LLVM that the function only allocates zeroed memory.
|
||||
const ALLOCATOR_ZEROED = 1 << 18;
|
||||
const ALLOCATOR_ZEROED = 1 << 14;
|
||||
/// `#[no_builtins]`: indicates that disable implicit builtin knowledge of functions for the function.
|
||||
const NO_BUILTINS = 1 << 19;
|
||||
const NO_BUILTINS = 1 << 15;
|
||||
}
|
||||
}
|
||||
rustc_data_structures::external_bitflags_debug! { CodegenFnAttrFlags }
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use rustc_span::ErrorGuaranteed;
|
|||
|
||||
use crate::query::CyclePlaceholder;
|
||||
use crate::ty::adjustment::CoerceUnsizedInfo;
|
||||
use crate::ty::{self, Ty};
|
||||
use crate::ty::{self, Ty, TyCtxt};
|
||||
use crate::{mir, traits};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
|
|
@ -207,6 +207,11 @@ impl EraseType for ty::Binder<'_, ty::FnSig<'_>> {
|
|||
type Result = [u8; size_of::<ty::Binder<'static, ty::FnSig<'static>>>()];
|
||||
}
|
||||
|
||||
impl EraseType for ty::Binder<'_, ty::CoroutineWitnessTypes<TyCtxt<'_>>> {
|
||||
type Result =
|
||||
[u8; size_of::<ty::Binder<'static, ty::CoroutineWitnessTypes<TyCtxt<'static>>>>()];
|
||||
}
|
||||
|
||||
impl EraseType for ty::Binder<'_, &'_ ty::List<Ty<'_>>> {
|
||||
type Result = [u8; size_of::<ty::Binder<'static, &'static ty::List<Ty<'static>>>>()];
|
||||
}
|
||||
|
|
@ -311,6 +316,7 @@ trivial! {
|
|||
rustc_middle::ty::Asyncness,
|
||||
rustc_middle::ty::AsyncDestructor,
|
||||
rustc_middle::ty::BoundVariableKind,
|
||||
rustc_middle::ty::AnonConstKind,
|
||||
rustc_middle::ty::DeducedParamAttrs,
|
||||
rustc_middle::ty::Destructor,
|
||||
rustc_middle::ty::fast_reject::SimplifiedType,
|
||||
|
|
|
|||
|
|
@ -922,6 +922,12 @@ rustc_queries! {
|
|||
separate_provide_extern
|
||||
}
|
||||
|
||||
query coroutine_hidden_types(
|
||||
def_id: DefId
|
||||
) -> ty::EarlyBinder<'tcx, ty::Binder<'tcx, ty::CoroutineWitnessTypes<TyCtxt<'tcx>>>> {
|
||||
desc { "looking up the hidden types stored across await points in a coroutine" }
|
||||
}
|
||||
|
||||
/// Gets a map with the variances of every item in the local crate.
|
||||
///
|
||||
/// <div class="warning">
|
||||
|
|
@ -2586,6 +2592,11 @@ rustc_queries! {
|
|||
desc { "estimating codegen size of `{}`", key }
|
||||
cache_on_disk_if { true }
|
||||
}
|
||||
|
||||
query anon_const_kind(def_id: DefId) -> ty::AnonConstKind {
|
||||
desc { |tcx| "looking up anon const kind of `{}`", tcx.def_path_str(def_id) }
|
||||
separate_provide_extern
|
||||
}
|
||||
}
|
||||
|
||||
rustc_with_all_queries! { define_callbacks! }
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use rustc_span::source_map::Spanned;
|
|||
use rustc_span::{Span, SpanDecoder, SpanEncoder};
|
||||
|
||||
use crate::arena::ArenaAllocatable;
|
||||
use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
|
||||
use crate::infer::canonical::{CanonicalVarKind, CanonicalVarKinds};
|
||||
use crate::mir::interpret::{AllocId, ConstAllocation, CtfeProvenance};
|
||||
use crate::mir::mono::MonoItem;
|
||||
use crate::mir::{self};
|
||||
|
|
@ -310,11 +310,11 @@ impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Region<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for CanonicalVarInfos<'tcx> {
|
||||
impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for CanonicalVarKinds<'tcx> {
|
||||
fn decode(decoder: &mut D) -> Self {
|
||||
let len = decoder.read_usize();
|
||||
decoder.interner().mk_canonical_var_infos_from_iter(
|
||||
(0..len).map::<CanonicalVarInfo<'tcx>, _>(|_| Decodable::decode(decoder)),
|
||||
(0..len).map::<CanonicalVarKind<'tcx>, _>(|_| Decodable::decode(decoder)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::borrow::Cow;
|
|||
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_error_messages::MultiSpan;
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
|
||||
use rustc_type_ir::walk::TypeWalker;
|
||||
use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo};
|
||||
|
||||
|
|
@ -259,3 +259,16 @@ impl<'tcx> Const<'tcx> {
|
|||
TypeWalker::new(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||
pub enum AnonConstKind {
|
||||
/// `feature(generic_const_exprs)` anon consts are allowed to use arbitrary generic parameters in scope
|
||||
GCE,
|
||||
/// stable `min_const_generics` anon consts are not allowed to use any generic parameters
|
||||
MCG,
|
||||
/// anon consts used as the length of a repeat expr are syntactically allowed to use generic parameters
|
||||
/// but must not depend on the actual instantiation. See #76200 for more information
|
||||
RepeatExprCount,
|
||||
/// anon consts outside of the type system, e.g. enum discriminants
|
||||
NonTypeSystem,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ use tracing::{debug, instrument};
|
|||
|
||||
use crate::arena::Arena;
|
||||
use crate::dep_graph::{DepGraph, DepKindStruct};
|
||||
use crate::infer::canonical::{CanonicalParamEnvCache, CanonicalVarInfo, CanonicalVarInfos};
|
||||
use crate::infer::canonical::{CanonicalParamEnvCache, CanonicalVarKind, CanonicalVarKinds};
|
||||
use crate::lint::lint_level;
|
||||
use crate::metadata::ModChild;
|
||||
use crate::middle::codegen_fn_attrs::{CodegenFnAttrs, TargetFeature};
|
||||
|
|
@ -107,9 +107,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
self.mk_predefined_opaques_in_body(data)
|
||||
}
|
||||
type LocalDefIds = &'tcx ty::List<LocalDefId>;
|
||||
type CanonicalVars = CanonicalVarInfos<'tcx>;
|
||||
fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars {
|
||||
self.mk_canonical_var_infos(infos)
|
||||
type CanonicalVarKinds = CanonicalVarKinds<'tcx>;
|
||||
fn mk_canonical_var_kinds(
|
||||
self,
|
||||
kinds: &[ty::CanonicalVarKind<Self>],
|
||||
) -> Self::CanonicalVarKinds {
|
||||
self.mk_canonical_var_kinds(kinds)
|
||||
}
|
||||
|
||||
type ExternalConstraints = ExternalConstraints<'tcx>;
|
||||
|
|
@ -340,7 +343,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
fn coroutine_hidden_types(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, ty::Binder<'tcx, &'tcx ty::List<Ty<'tcx>>>> {
|
||||
) -> ty::EarlyBinder<'tcx, ty::Binder<'tcx, ty::CoroutineWitnessTypes<TyCtxt<'tcx>>>> {
|
||||
self.coroutine_hidden_types(def_id)
|
||||
}
|
||||
|
||||
|
|
@ -833,7 +836,7 @@ pub struct CtxtInterners<'tcx> {
|
|||
const_lists: InternedSet<'tcx, List<ty::Const<'tcx>>>,
|
||||
args: InternedSet<'tcx, GenericArgs<'tcx>>,
|
||||
type_lists: InternedSet<'tcx, List<Ty<'tcx>>>,
|
||||
canonical_var_infos: InternedSet<'tcx, List<CanonicalVarInfo<'tcx>>>,
|
||||
canonical_var_kinds: InternedSet<'tcx, List<CanonicalVarKind<'tcx>>>,
|
||||
region: InternedSet<'tcx, RegionKind<'tcx>>,
|
||||
poly_existential_predicates: InternedSet<'tcx, List<PolyExistentialPredicate<'tcx>>>,
|
||||
predicate: InternedSet<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>,
|
||||
|
|
@ -872,7 +875,7 @@ impl<'tcx> CtxtInterners<'tcx> {
|
|||
type_lists: InternedSet::with_capacity(N * 4),
|
||||
region: InternedSet::with_capacity(N * 4),
|
||||
poly_existential_predicates: InternedSet::with_capacity(N / 4),
|
||||
canonical_var_infos: InternedSet::with_capacity(N / 2),
|
||||
canonical_var_kinds: InternedSet::with_capacity(N / 2),
|
||||
predicate: InternedSet::with_capacity(N),
|
||||
clauses: InternedSet::with_capacity(N),
|
||||
projs: InternedSet::with_capacity(N * 4),
|
||||
|
|
@ -2675,7 +2678,7 @@ slice_interners!(
|
|||
const_lists: pub mk_const_list(Const<'tcx>),
|
||||
args: pub mk_args(GenericArg<'tcx>),
|
||||
type_lists: pub mk_type_list(Ty<'tcx>),
|
||||
canonical_var_infos: pub mk_canonical_var_infos(CanonicalVarInfo<'tcx>),
|
||||
canonical_var_kinds: pub mk_canonical_var_kinds(CanonicalVarKind<'tcx>),
|
||||
poly_existential_predicates: intern_poly_existential_predicates(PolyExistentialPredicate<'tcx>),
|
||||
projs: pub mk_projs(ProjectionKind),
|
||||
place_elems: pub mk_place_elems(PlaceElem<'tcx>),
|
||||
|
|
@ -3055,9 +3058,9 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
pub fn mk_canonical_var_infos_from_iter<I, T>(self, iter: I) -> T::Output
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
T: CollectAndApply<CanonicalVarInfo<'tcx>, &'tcx List<CanonicalVarInfo<'tcx>>>,
|
||||
T: CollectAndApply<CanonicalVarKind<'tcx>, &'tcx List<CanonicalVarKind<'tcx>>>,
|
||||
{
|
||||
T::collect_and_apply(iter, |xs| self.mk_canonical_var_infos(xs))
|
||||
T::collect_and_apply(iter, |xs| self.mk_canonical_var_kinds(xs))
|
||||
}
|
||||
|
||||
pub fn mk_place_elems_from_iter<I, T>(self, iter: I) -> T::Output
|
||||
|
|
|
|||
|
|
@ -74,8 +74,8 @@ pub use self::closure::{
|
|||
place_to_string_for_capture,
|
||||
};
|
||||
pub use self::consts::{
|
||||
Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, ValTree, ValTreeKind,
|
||||
Value,
|
||||
AnonConstKind, Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst,
|
||||
ValTree, ValTreeKind, Value,
|
||||
};
|
||||
pub use self::context::{
|
||||
CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt,
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ trivially_parameterized_over_tcx! {
|
|||
ty::AsyncDestructor,
|
||||
ty::AssocItemContainer,
|
||||
ty::Asyncness,
|
||||
ty::AnonConstKind,
|
||||
ty::DeducedParamAttrs,
|
||||
ty::Destructor,
|
||||
ty::Generics,
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ use crate::query::Providers;
|
|||
use crate::ty::layout::{FloatExt, IntegerExt};
|
||||
use crate::ty::{
|
||||
self, Asyncness, FallibleTypeFolder, GenericArgKind, GenericArgsRef, Ty, TyCtxt, TypeFoldable,
|
||||
TypeFolder, TypeSuperFoldable, TypeVisitableExt, Upcast, fold_regions,
|
||||
TypeFolder, TypeSuperFoldable, TypeVisitableExt, Upcast,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
|
@ -737,40 +737,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Return the set of types that should be taken into account when checking
|
||||
/// trait bounds on a coroutine's internal state. This properly replaces
|
||||
/// `ReErased` with new existential bound lifetimes.
|
||||
pub fn coroutine_hidden_types(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, ty::Binder<'tcx, &'tcx ty::List<Ty<'tcx>>>> {
|
||||
let coroutine_layout = self.mir_coroutine_witnesses(def_id);
|
||||
let mut vars = vec![];
|
||||
let bound_tys = self.mk_type_list_from_iter(
|
||||
coroutine_layout
|
||||
.as_ref()
|
||||
.map_or_else(|| [].iter(), |l| l.field_tys.iter())
|
||||
.filter(|decl| !decl.ignore_for_traits)
|
||||
.map(|decl| {
|
||||
let ty = fold_regions(self, decl.ty, |re, debruijn| {
|
||||
assert_eq!(re, self.lifetimes.re_erased);
|
||||
let var = ty::BoundVar::from_usize(vars.len());
|
||||
vars.push(ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon));
|
||||
ty::Region::new_bound(
|
||||
self,
|
||||
debruijn,
|
||||
ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon },
|
||||
)
|
||||
});
|
||||
ty
|
||||
}),
|
||||
);
|
||||
ty::EarlyBinder::bind(ty::Binder::bind_with_vars(
|
||||
bound_tys,
|
||||
self.mk_bound_variable_kinds(&vars),
|
||||
))
|
||||
}
|
||||
|
||||
/// Expands the given impl trait type, stopping if the type is recursive.
|
||||
#[instrument(skip(self), level = "debug", ret)]
|
||||
pub fn try_expand_impl_trait_type(
|
||||
|
|
|
|||
|
|
@ -382,6 +382,9 @@ fn extend_type_not_partial_eq<'tcx>(
|
|||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
|
||||
match ty.kind() {
|
||||
ty::Dynamic(..) => return ControlFlow::Break(()),
|
||||
// Unsafe binders never implement `PartialEq`, so avoid walking into them
|
||||
// which would require instantiating its binder with placeholders too.
|
||||
ty::UnsafeBinder(..) => return ControlFlow::Break(()),
|
||||
ty::FnPtr(..) => return ControlFlow::Continue(()),
|
||||
ty::Adt(def, _args) => {
|
||||
let ty_def_id = def.did();
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ impl<'a, 'tcx> UnnecessaryTransmuteChecker<'a, 'tcx> {
|
|||
function: &Operand<'tcx>,
|
||||
arg: String,
|
||||
span: Span,
|
||||
is_in_const: bool,
|
||||
) -> Option<Error> {
|
||||
let fn_sig = function.ty(self.body, self.tcx).fn_sig(self.tcx).skip_binder();
|
||||
let [input] = fn_sig.inputs() else { return None };
|
||||
|
|
@ -97,8 +98,14 @@ impl<'a, 'tcx> UnnecessaryTransmuteChecker<'a, 'tcx> {
|
|||
)),
|
||||
// uNN → fNN
|
||||
(Uint(_), Float(ty)) => err(format!("{}::from_bits({arg})", ty.name_str())),
|
||||
// bool → { x8 }
|
||||
(Bool, Int(..) | Uint(..)) => err(format!("({arg}) as {}", fn_sig.output())),
|
||||
// bool → { x8 } in const context since `From::from` is not const yet
|
||||
// FIXME: is it possible to know when the parentheses arent necessary?
|
||||
// FIXME(const_traits): Remove this when From::from is constified?
|
||||
(Bool, Int(..) | Uint(..)) if is_in_const => {
|
||||
err(format!("({arg}) as {}", fn_sig.output()))
|
||||
}
|
||||
// " using `x8::from`
|
||||
(Bool, Int(..) | Uint(..)) => err(format!("{}::from({arg})", fn_sig.output())),
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
|
@ -114,7 +121,13 @@ impl<'tcx> Visitor<'tcx> for UnnecessaryTransmuteChecker<'_, 'tcx> {
|
|||
&& self.tcx.is_intrinsic(func_def_id, sym::transmute)
|
||||
&& let span = self.body.source_info(location).span
|
||||
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(arg)
|
||||
&& let Some(lint) = self.is_unnecessary_transmute(func, snippet, span)
|
||||
&& let def_id = self.body.source.def_id()
|
||||
&& let Some(lint) = self.is_unnecessary_transmute(
|
||||
func,
|
||||
snippet,
|
||||
span,
|
||||
self.tcx.hir_body_const_context(def_id.expect_local()).is_some(),
|
||||
)
|
||||
&& let Some(hir_id) = terminator.source_info.scope.lint_root(&self.body.source_scopes)
|
||||
{
|
||||
self.tcx.emit_node_span_lint(UNNECESSARY_TRANSMUTES, hir_id, span, lint);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use rustc_middle::mir::{
|
|||
BasicBlock, BasicBlockData, Body, Local, LocalDecl, MirSource, Operand, Place, Rvalue,
|
||||
SourceInfo, Statement, StatementKind, Terminator, TerminatorKind,
|
||||
};
|
||||
use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt, TypeVisitableExt};
|
||||
|
||||
use super::*;
|
||||
use crate::patch::MirPatch;
|
||||
|
|
@ -121,9 +121,10 @@ pub(super) fn build_async_drop_shim<'tcx>(
|
|||
parent_args.as_coroutine().resume_ty(),
|
||||
)));
|
||||
body.phase = MirPhase::Runtime(RuntimePhase::Initial);
|
||||
if !needs_async_drop {
|
||||
if !needs_async_drop || drop_ty.references_error() {
|
||||
// Returning noop body for types without `need async drop`
|
||||
// (or sync Drop in case of !`need async drop` && `need drop`)
|
||||
// (or sync Drop in case of !`need async drop` && `need drop`).
|
||||
// And also for error types.
|
||||
return body;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ use rustc_type_ir::data_structures::{HashMap, ensure_sufficient_stack};
|
|||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::solve::{Goal, QueryInput};
|
||||
use rustc_type_ir::{
|
||||
self as ty, Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, InferCtxtLike,
|
||||
Interner, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
|
||||
self as ty, Canonical, CanonicalTyVarKind, CanonicalVarKind, InferCtxtLike, Interner,
|
||||
TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
|
||||
};
|
||||
|
||||
use crate::delegate::SolverDelegate;
|
||||
|
|
@ -50,7 +50,7 @@ pub struct Canonicalizer<'a, D: SolverDelegate<Interner = I>, I: Interner> {
|
|||
|
||||
// Mutable fields.
|
||||
variables: &'a mut Vec<I::GenericArg>,
|
||||
primitive_var_infos: Vec<CanonicalVarInfo<I>>,
|
||||
var_kinds: Vec<CanonicalVarKind<I>>,
|
||||
variable_lookup_table: HashMap<I::GenericArg, usize>,
|
||||
binder_index: ty::DebruijnIndex,
|
||||
|
||||
|
|
@ -73,7 +73,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|||
|
||||
variables,
|
||||
variable_lookup_table: Default::default(),
|
||||
primitive_var_infos: Vec::new(),
|
||||
var_kinds: Vec::new(),
|
||||
binder_index: ty::INNERMOST,
|
||||
|
||||
cache: Default::default(),
|
||||
|
|
@ -106,7 +106,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|||
|
||||
variables,
|
||||
variable_lookup_table: Default::default(),
|
||||
primitive_var_infos: Vec::new(),
|
||||
var_kinds: Vec::new(),
|
||||
binder_index: ty::INNERMOST,
|
||||
|
||||
cache: Default::default(),
|
||||
|
|
@ -123,7 +123,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|||
// We're able to reuse the `variable_lookup_table` as whether or not
|
||||
// it already contains an entry for `'static` does not matter.
|
||||
variable_lookup_table: env_canonicalizer.variable_lookup_table,
|
||||
primitive_var_infos: env_canonicalizer.primitive_var_infos,
|
||||
var_kinds: env_canonicalizer.var_kinds,
|
||||
binder_index: ty::INNERMOST,
|
||||
|
||||
// We do not reuse the cache as it may contain entries whose canonicalized
|
||||
|
|
@ -149,7 +149,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|||
fn get_or_insert_bound_var(
|
||||
&mut self,
|
||||
arg: impl Into<I::GenericArg>,
|
||||
canonical_var_info: CanonicalVarInfo<I>,
|
||||
kind: CanonicalVarKind<I>,
|
||||
) -> ty::BoundVar {
|
||||
// FIXME: 16 is made up and arbitrary. We should look at some
|
||||
// perf data here.
|
||||
|
|
@ -162,14 +162,14 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|||
*self.variable_lookup_table.entry(arg).or_insert_with(|| {
|
||||
let var = self.variables.len();
|
||||
self.variables.push(arg);
|
||||
self.primitive_var_infos.push(canonical_var_info);
|
||||
self.var_kinds.push(kind);
|
||||
var
|
||||
})
|
||||
} else {
|
||||
self.variables.iter().position(|&v| v == arg).unwrap_or_else(|| {
|
||||
let var = self.variables.len();
|
||||
self.variables.push(arg);
|
||||
self.primitive_var_infos.push(canonical_var_info);
|
||||
self.var_kinds.push(kind);
|
||||
var
|
||||
})
|
||||
};
|
||||
|
|
@ -177,8 +177,8 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|||
ty::BoundVar::from(idx)
|
||||
}
|
||||
|
||||
fn finalize(self) -> (ty::UniverseIndex, I::CanonicalVars) {
|
||||
let mut var_infos = self.primitive_var_infos;
|
||||
fn finalize(self) -> (ty::UniverseIndex, I::CanonicalVarKinds) {
|
||||
let mut var_kinds = self.var_kinds;
|
||||
// See the rustc-dev-guide section about how we deal with universes
|
||||
// during canonicalization in the new solver.
|
||||
match self.canonicalize_mode {
|
||||
|
|
@ -192,25 +192,25 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|||
// information for placeholders and inference variables created inside
|
||||
// of the query.
|
||||
CanonicalizeMode::Response { max_input_universe } => {
|
||||
for var in var_infos.iter_mut() {
|
||||
for var in var_kinds.iter_mut() {
|
||||
let uv = var.universe();
|
||||
let new_uv = ty::UniverseIndex::from(
|
||||
uv.index().saturating_sub(max_input_universe.index()),
|
||||
);
|
||||
*var = var.with_updated_universe(new_uv);
|
||||
}
|
||||
let max_universe = var_infos
|
||||
let max_universe = var_kinds
|
||||
.iter()
|
||||
.map(|info| info.universe())
|
||||
.map(|kind| kind.universe())
|
||||
.max()
|
||||
.unwrap_or(ty::UniverseIndex::ROOT);
|
||||
|
||||
let var_infos = self.delegate.cx().mk_canonical_var_infos(&var_infos);
|
||||
return (max_universe, var_infos);
|
||||
let var_kinds = self.delegate.cx().mk_canonical_var_kinds(&var_kinds);
|
||||
return (max_universe, var_kinds);
|
||||
}
|
||||
}
|
||||
|
||||
// Given a `var_infos` with existentials `En` and universals `Un` in
|
||||
// Given a `var_kinds` with existentials `En` and universals `Un` in
|
||||
// universes `n`, this algorithm compresses them in place so that:
|
||||
//
|
||||
// - the new universe indices are as small as possible
|
||||
|
|
@ -219,12 +219,12 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|||
// 2. put a placeholder in the same universe as an existential which cannot name it
|
||||
//
|
||||
// Let's walk through an example:
|
||||
// - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 0
|
||||
// - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 1
|
||||
// - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 1, next_orig_uv: 2
|
||||
// - var_infos: [E0, U1, E5, U1, E1, E6, U6], curr_compressed_uv: 1, next_orig_uv: 5
|
||||
// - var_infos: [E0, U1, E2, U1, E1, E6, U6], curr_compressed_uv: 2, next_orig_uv: 6
|
||||
// - var_infos: [E0, U1, E1, U1, E1, E3, U3], curr_compressed_uv: 2, next_orig_uv: -
|
||||
// - var_kinds: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 0
|
||||
// - var_kinds: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 1
|
||||
// - var_kinds: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 1, next_orig_uv: 2
|
||||
// - var_kinds: [E0, U1, E5, U1, E1, E6, U6], curr_compressed_uv: 1, next_orig_uv: 5
|
||||
// - var_kinds: [E0, U1, E2, U1, E1, E6, U6], curr_compressed_uv: 2, next_orig_uv: 6
|
||||
// - var_kinds: [E0, U1, E1, U1, E1, E3, U3], curr_compressed_uv: 2, next_orig_uv: -
|
||||
//
|
||||
// This algorithm runs in `O(mn)` where `n` is the number of different universes and
|
||||
// `m` the number of variables. This should be fine as both are expected to be small.
|
||||
|
|
@ -232,7 +232,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|||
let mut existential_in_new_uv = None;
|
||||
let mut next_orig_uv = Some(ty::UniverseIndex::ROOT);
|
||||
while let Some(orig_uv) = next_orig_uv.take() {
|
||||
let mut update_uv = |var: &mut CanonicalVarInfo<I>, orig_uv, is_existential| {
|
||||
let mut update_uv = |var: &mut CanonicalVarKind<I>, orig_uv, is_existential| {
|
||||
let uv = var.universe();
|
||||
match uv.cmp(&orig_uv) {
|
||||
Ordering::Less => (), // Already updated
|
||||
|
|
@ -284,7 +284,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|||
// Whenever we compress the universe of a placeholder, no existential with
|
||||
// an already compressed universe can name that placeholder.
|
||||
for is_existential in [false, true] {
|
||||
for var in var_infos.iter_mut() {
|
||||
for var in var_kinds.iter_mut() {
|
||||
// We simply put all regions from the input into the highest
|
||||
// compressed universe, so we only deal with them at the end.
|
||||
if !var.is_region() {
|
||||
|
|
@ -298,7 +298,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|||
|
||||
// We put all regions into a separate universe.
|
||||
let mut first_region = true;
|
||||
for var in var_infos.iter_mut() {
|
||||
for var in var_kinds.iter_mut() {
|
||||
if var.is_region() {
|
||||
if first_region {
|
||||
first_region = false;
|
||||
|
|
@ -309,8 +309,8 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|||
}
|
||||
}
|
||||
|
||||
let var_infos = self.delegate.cx().mk_canonical_var_infos(&var_infos);
|
||||
(curr_compressed_uv, var_infos)
|
||||
let var_kinds = self.delegate.cx().mk_canonical_var_kinds(&var_kinds);
|
||||
(curr_compressed_uv, var_kinds)
|
||||
}
|
||||
|
||||
fn cached_fold_ty(&mut self, t: I::Ty) -> I::Ty {
|
||||
|
|
@ -391,7 +391,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|||
}
|
||||
};
|
||||
|
||||
let var = self.get_or_insert_bound_var(t, CanonicalVarInfo { kind });
|
||||
let var = self.get_or_insert_bound_var(t, kind);
|
||||
|
||||
Ty::new_anon_bound(self.cx(), self.binder_index, var)
|
||||
}
|
||||
|
|
@ -475,7 +475,7 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
|
|||
}
|
||||
};
|
||||
|
||||
let var = self.get_or_insert_bound_var(r, CanonicalVarInfo { kind });
|
||||
let var = self.get_or_insert_bound_var(r, kind);
|
||||
|
||||
Region::new_anon_bound(self.cx(), self.binder_index, var)
|
||||
}
|
||||
|
|
@ -525,7 +525,7 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
|
|||
| ty::ConstKind::Expr(_) => return c.super_fold_with(self),
|
||||
};
|
||||
|
||||
let var = self.get_or_insert_bound_var(c, CanonicalVarInfo { kind });
|
||||
let var = self.get_or_insert_bound_var(c, kind);
|
||||
|
||||
Const::new_anon_bound(self.cx(), self.binder_index, var)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized {
|
|||
|
||||
fn instantiate_canonical_var_with_infer(
|
||||
&self,
|
||||
cv_info: ty::CanonicalVarInfo<Self::Interner>,
|
||||
kind: ty::CanonicalVarKind<Self::Interner>,
|
||||
span: <Self::Interner as Interner>::Span,
|
||||
universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
|
||||
) -> <Self::Interner as Interner>::GenericArg;
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ where
|
|||
.cx()
|
||||
.coroutine_hidden_types(def_id)
|
||||
.instantiate(cx, args)
|
||||
.map_bound(|tys| tys.to_vec())),
|
||||
.map_bound(|bound| bound.types.to_vec())),
|
||||
|
||||
ty::UnsafeBinder(bound_ty) => Ok(bound_ty.map_bound(|ty| vec![ty])),
|
||||
|
||||
|
|
@ -249,7 +249,7 @@ where
|
|||
.cx()
|
||||
.coroutine_hidden_types(def_id)
|
||||
.instantiate(ecx.cx(), args)
|
||||
.map_bound(|tys| tys.to_vec())),
|
||||
.map_bound(|bound| bound.types.to_vec())),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -327,7 +327,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<I: Intern
|
|||
// always be called once. It additionally implements `Fn`/`FnMut`
|
||||
// only if it has no upvars referencing the closure-env lifetime,
|
||||
// and if the closure kind permits it.
|
||||
if closure_kind != ty::ClosureKind::FnOnce && args.has_self_borrows() {
|
||||
if goal_kind != ty::ClosureKind::FnOnce && args.has_self_borrows() {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -360,15 +360,15 @@ where
|
|||
}
|
||||
|
||||
let var_values = delegate.cx().mk_args_from_iter(
|
||||
response.variables.iter().enumerate().map(|(index, info)| {
|
||||
if info.universe() != ty::UniverseIndex::ROOT {
|
||||
response.variables.iter().enumerate().map(|(index, var_kind)| {
|
||||
if var_kind.universe() != ty::UniverseIndex::ROOT {
|
||||
// A variable from inside a binder of the query. While ideally these shouldn't
|
||||
// exist at all (see the FIXME at the start of this method), we have to deal with
|
||||
// them for now.
|
||||
delegate.instantiate_canonical_var_with_infer(info, span, |idx| {
|
||||
delegate.instantiate_canonical_var_with_infer(var_kind, span, |idx| {
|
||||
prev_universe + idx.index()
|
||||
})
|
||||
} else if info.is_existential() {
|
||||
} else if var_kind.is_existential() {
|
||||
// As an optimization we sometimes avoid creating a new inference variable here.
|
||||
//
|
||||
// All new inference variables we create start out in the current universe of the caller.
|
||||
|
|
@ -379,12 +379,13 @@ where
|
|||
if let Some(v) = opt_values[ty::BoundVar::from_usize(index)] {
|
||||
v
|
||||
} else {
|
||||
delegate.instantiate_canonical_var_with_infer(info, span, |_| prev_universe)
|
||||
delegate
|
||||
.instantiate_canonical_var_with_infer(var_kind, span, |_| prev_universe)
|
||||
}
|
||||
} else {
|
||||
// For placeholders which were already part of the input, we simply map this
|
||||
// universal bound variable back the placeholder of the input.
|
||||
original_values[info.expect_placeholder_index()]
|
||||
original_values[var_kind.expect_placeholder_index()]
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ where
|
|||
|
||||
/// The variable info for the `var_values`, only used to make an ambiguous response
|
||||
/// with no constraints.
|
||||
variables: I::CanonicalVars,
|
||||
variables: I::CanonicalVarKinds,
|
||||
|
||||
/// What kind of goal we're currently computing, see the enum definition
|
||||
/// for more info.
|
||||
|
|
|
|||
|
|
@ -354,7 +354,7 @@ where
|
|||
fn response_no_constraints_raw<I: Interner>(
|
||||
cx: I,
|
||||
max_universe: ty::UniverseIndex,
|
||||
variables: I::CanonicalVars,
|
||||
variables: I::CanonicalVarKinds,
|
||||
certainty: Certainty,
|
||||
) -> CanonicalResponse<I> {
|
||||
ty::Canonical {
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ use rustc_session::lint::builtin::{
|
|||
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES,
|
||||
};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::{BytePos, DUMMY_SP, Span, Symbol, edition, kw, sym};
|
||||
use rustc_span::{BytePos, DUMMY_SP, Span, Symbol, edition, sym};
|
||||
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
||||
use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs};
|
||||
use rustc_trait_selection::traits::ObligationCtxt;
|
||||
|
|
@ -936,7 +936,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
let span = meta.name_value_literal_span().unwrap_or_else(|| meta.span());
|
||||
let attr_str =
|
||||
&format!("`#[doc(alias{})]`", if is_list { "(\"...\")" } else { " = \"...\"" });
|
||||
if doc_alias == kw::Empty {
|
||||
if doc_alias == sym::empty {
|
||||
tcx.dcx().emit_err(errors::DocAliasEmpty { span, attr_str });
|
||||
return;
|
||||
}
|
||||
|
|
@ -1068,7 +1068,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
}
|
||||
|
||||
let doc_keyword = match meta.value_str() {
|
||||
Some(value) if value != kw::Empty => value,
|
||||
Some(value) if value != sym::empty => value,
|
||||
_ => return self.doc_attr_str_error(meta, "keyword"),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -707,7 +707,7 @@ fn has_allow_dead_code_or_lang_attr(
|
|||
// #[used], #[no_mangle], #[export_name], etc also keeps the item alive
|
||||
// forcefully, e.g., for placing it in a specific section.
|
||||
cg_attrs.contains_extern_indicator()
|
||||
|| cg_attrs.flags.contains(CodegenFnAttrFlags::USED)
|
||||
|| cg_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER)
|
||||
|| cg_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -427,7 +427,7 @@ fn has_custom_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
|
|||
// FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by
|
||||
// `linked_symbols` in cg_ssa. They won't be exported in binary or cdylib due to their
|
||||
// `SymbolExportLevel::Rust` export level but may end up being exported in dylibs.
|
||||
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED)
|
||||
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER)
|
||||
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use rustc_data_structures::fx::FxIndexMap;
|
|||
use rustc_data_structures::unord::UnordSet;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::{DUMMY_SP, InnerSpan, Span, Symbol, kw, sym};
|
||||
use rustc_span::{DUMMY_SP, InnerSpan, Span, Symbol, sym};
|
||||
use thin_vec::ThinVec;
|
||||
use tracing::{debug, trace};
|
||||
|
||||
|
|
@ -157,7 +157,7 @@ pub fn unindent_doc_fragments(docs: &mut [DocFragment]) {
|
|||
};
|
||||
|
||||
for fragment in docs {
|
||||
if fragment.doc == kw::Empty {
|
||||
if fragment.doc == sym::empty {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -177,7 +177,7 @@ pub fn unindent_doc_fragments(docs: &mut [DocFragment]) {
|
|||
///
|
||||
/// Note: remove the trailing newline where appropriate
|
||||
pub fn add_doc_fragment(out: &mut String, frag: &DocFragment) {
|
||||
if frag.doc == kw::Empty {
|
||||
if frag.doc == sym::empty {
|
||||
out.push('\n');
|
||||
return;
|
||||
}
|
||||
|
|
@ -514,20 +514,30 @@ pub fn span_of_fragments(fragments: &[DocFragment]) -> Option<Span> {
|
|||
/// This method does not always work, because markdown bytes don't necessarily match source bytes,
|
||||
/// like if escapes are used in the string. In this case, it returns `None`.
|
||||
///
|
||||
/// This method will return `Some` only if:
|
||||
/// `markdown` is typically the entire documentation for an item,
|
||||
/// after combining fragments.
|
||||
///
|
||||
/// This method will return `Some` only if one of the following is true:
|
||||
///
|
||||
/// - The doc is made entirely from sugared doc comments, which cannot contain escapes
|
||||
/// - The doc is entirely from a single doc fragment, with a string literal, exactly equal
|
||||
/// - The doc is entirely from a single doc fragment with a string literal exactly equal to `markdown`.
|
||||
/// - The doc comes from `include_str!`
|
||||
/// - The doc includes exactly one substring matching `markdown[md_range]` which is contained in a single doc fragment.
|
||||
///
|
||||
/// This function is defined in the compiler so it can be used by
|
||||
/// both `rustdoc` and `clippy`.
|
||||
pub fn source_span_for_markdown_range(
|
||||
tcx: TyCtxt<'_>,
|
||||
markdown: &str,
|
||||
md_range: &Range<usize>,
|
||||
fragments: &[DocFragment],
|
||||
) -> Option<Span> {
|
||||
use rustc_span::BytePos;
|
||||
|
||||
let map = tcx.sess.source_map();
|
||||
if let &[fragment] = &fragments
|
||||
&& fragment.kind == DocFragmentKind::RawDoc
|
||||
&& let Ok(snippet) = tcx.sess.source_map().span_to_snippet(fragment.span)
|
||||
&& let Ok(snippet) = map.span_to_snippet(fragment.span)
|
||||
&& snippet.trim_end() == markdown.trim_end()
|
||||
&& let Ok(md_range_lo) = u32::try_from(md_range.start)
|
||||
&& let Ok(md_range_hi) = u32::try_from(md_range.end)
|
||||
|
|
@ -544,10 +554,43 @@ pub fn source_span_for_markdown_range(
|
|||
let is_all_sugared_doc = fragments.iter().all(|frag| frag.kind == DocFragmentKind::SugaredDoc);
|
||||
|
||||
if !is_all_sugared_doc {
|
||||
// This case ignores the markdown outside of the range so that it can
|
||||
// work in cases where the markdown is made from several different
|
||||
// doc fragments, but the target range does not span across multiple
|
||||
// fragments.
|
||||
let mut match_data = None;
|
||||
let pat = &markdown[md_range.clone()];
|
||||
// This heirustic doesn't make sense with a zero-sized range.
|
||||
if pat.is_empty() {
|
||||
return None;
|
||||
}
|
||||
for (i, fragment) in fragments.iter().enumerate() {
|
||||
if let Ok(snippet) = map.span_to_snippet(fragment.span)
|
||||
&& let Some(match_start) = snippet.find(pat)
|
||||
{
|
||||
// If there is either a match in a previous fragment, or
|
||||
// multiple matches in this fragment, there is ambiguity.
|
||||
if match_data.is_none() && !snippet[match_start + 1..].contains(pat) {
|
||||
match_data = Some((i, match_start));
|
||||
} else {
|
||||
// Heirustic produced ambiguity, return nothing.
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some((i, match_start)) = match_data {
|
||||
let sp = fragments[i].span;
|
||||
// we need to calculate the span start,
|
||||
// then use that in our calulations for the span end
|
||||
let lo = sp.lo() + BytePos(match_start as u32);
|
||||
return Some(
|
||||
sp.with_lo(lo).with_hi(lo + BytePos((md_range.end - md_range.start) as u32)),
|
||||
);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
let snippet = tcx.sess.source_map().span_to_snippet(span_of_fragments(fragments)?).ok()?;
|
||||
let snippet = map.span_to_snippet(span_of_fragments(fragments)?).ok()?;
|
||||
|
||||
let starting_line = markdown[..md_range.start].matches('\n').count();
|
||||
let ending_line = starting_line + markdown[md_range.start..md_range.end].matches('\n').count();
|
||||
|
|
|
|||
|
|
@ -34,17 +34,8 @@ symbols! {
|
|||
// unnamed method parameters, crate root module, error recovery etc.
|
||||
// Matching predicates: `is_special`/`is_reserved`
|
||||
//
|
||||
// Notes about `kw::Empty`:
|
||||
// - Its use can blur the lines between "empty symbol" and "no symbol".
|
||||
// Using `Option<Symbol>` is preferable, where possible, because that
|
||||
// is unambiguous.
|
||||
// - For dummy symbols that are never used and absolutely must be
|
||||
// present, it's better to use `sym::dummy` than `kw::Empty`, because
|
||||
// it's clearer that it's intended as a dummy value, and more likely
|
||||
// to be detected if it accidentally does get used.
|
||||
// tidy-alphabetical-start
|
||||
DollarCrate: "$crate",
|
||||
Empty: "",
|
||||
PathRoot: "{{root}}",
|
||||
Underscore: "_",
|
||||
// tidy-alphabetical-end
|
||||
|
|
@ -398,7 +389,6 @@ symbols! {
|
|||
Wrapping,
|
||||
Yield,
|
||||
_DECLS,
|
||||
_Self,
|
||||
__D,
|
||||
__H,
|
||||
__S,
|
||||
|
|
@ -864,7 +854,7 @@ symbols! {
|
|||
drop_types_in_const,
|
||||
dropck_eyepatch,
|
||||
dropck_parametricity,
|
||||
dummy: "<!dummy!>", // use this instead of `kw::Empty` for symbols that won't be used
|
||||
dummy: "<!dummy!>", // use this instead of `sym::empty` for symbols that won't be used
|
||||
dummy_cgu_name,
|
||||
dylib,
|
||||
dyn_compatible_for_dispatch,
|
||||
|
|
@ -883,6 +873,14 @@ symbols! {
|
|||
emit_enum_variant_arg,
|
||||
emit_struct,
|
||||
emit_struct_field,
|
||||
// Notes about `sym::empty`:
|
||||
// - It should only be used when it genuinely means "empty symbol". Use
|
||||
// `Option<Symbol>` when "no symbol" is a possibility.
|
||||
// - For dummy symbols that are never used and absolutely must be
|
||||
// present, it's better to use `sym::dummy` than `sym::empty`, because
|
||||
// it's clearer that it's intended as a dummy value, and more likely
|
||||
// to be detected if it accidentally does get used.
|
||||
empty: "",
|
||||
emscripten_wasm_eh,
|
||||
enable,
|
||||
encode,
|
||||
|
|
@ -2362,7 +2360,7 @@ impl Ident {
|
|||
#[inline]
|
||||
/// Constructs a new identifier from a symbol and a span.
|
||||
pub fn new(name: Symbol, span: Span) -> Ident {
|
||||
debug_assert_ne!(name, kw::Empty);
|
||||
debug_assert_ne!(name, sym::empty);
|
||||
Ident { name, span }
|
||||
}
|
||||
|
||||
|
|
@ -2584,7 +2582,7 @@ impl Symbol {
|
|||
}
|
||||
|
||||
pub fn is_empty(self) -> bool {
|
||||
self == kw::Empty
|
||||
self == sym::empty
|
||||
}
|
||||
|
||||
/// This method is supposed to be used in error messages, so it's expected to be
|
||||
|
|
@ -2593,7 +2591,7 @@ impl Symbol {
|
|||
/// or edition, so we have to guess the rawness using the global edition.
|
||||
pub fn to_ident_string(self) -> String {
|
||||
// Avoid creating an empty identifier, because that asserts in debug builds.
|
||||
if self == kw::Empty { String::new() } else { Ident::with_dummy_span(self).to_string() }
|
||||
if self == sym::empty { String::new() } else { Ident::with_dummy_span(self).to_string() }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2773,7 +2771,7 @@ impl Symbol {
|
|||
|
||||
/// Returns `true` if this symbol can be a raw identifier.
|
||||
pub fn can_be_raw(self) -> bool {
|
||||
self != kw::Empty && self != kw::Underscore && !self.is_path_segment_keyword()
|
||||
self != sym::empty && self != kw::Underscore && !self.is_path_segment_keyword()
|
||||
}
|
||||
|
||||
/// Was this symbol predefined in the compiler's `symbols!` macro
|
||||
|
|
@ -2823,7 +2821,7 @@ impl Ident {
|
|||
/// Whether this would be the identifier for a tuple field like `self.0`, as
|
||||
/// opposed to a named field like `self.thing`.
|
||||
pub fn is_numeric(self) -> bool {
|
||||
!self.name.is_empty() && self.as_str().bytes().all(|b| b.is_ascii_digit())
|
||||
self.as_str().bytes().all(|b| b.is_ascii_digit())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ use rustc_middle::ty::{
|
|||
self, FloatTy, GenericArg, GenericArgKind, Instance, IntTy, ReifyReason, Ty, TyCtxt,
|
||||
TypeVisitable, TypeVisitableExt, UintTy,
|
||||
};
|
||||
use rustc_span::kw;
|
||||
use rustc_span::sym;
|
||||
|
||||
pub(super) fn mangle<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
|
@ -902,7 +902,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
|
|||
print_prefix,
|
||||
ns,
|
||||
disambiguated_data.disambiguator as u64,
|
||||
name.unwrap_or(kw::Empty).as_str(),
|
||||
name.unwrap_or(sym::empty).as_str(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use rustc_abi::Endian;
|
||||
|
||||
use crate::spec::{StackProbeType, Target, TargetMetadata, TargetOptions, base};
|
||||
use crate::spec::{FramePointer, StackProbeType, Target, TargetMetadata, TargetOptions, base};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
|
|
@ -16,6 +16,10 @@ pub(crate) fn target() -> Target {
|
|||
arch: "aarch64".into(),
|
||||
options: TargetOptions {
|
||||
features: "+v8a,+outline-atomics".into(),
|
||||
// the AAPCS64 expects use of non-leaf frame pointers per
|
||||
// https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer
|
||||
// and we tend to encounter interesting bugs in AArch64 unwinding code if we do not
|
||||
frame_pointer: FramePointer::NonLeaf,
|
||||
max_atomic_width: Some(128),
|
||||
stack_probes: StackProbeType::Inline,
|
||||
mcount: "\u{1}_mcount".into(),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use rustc_abi::Endian;
|
||||
|
||||
use crate::spec::{StackProbeType, Target, TargetMetadata, TargetOptions, base};
|
||||
use crate::spec::{FramePointer, StackProbeType, Target, TargetMetadata, TargetOptions, base};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
let mut base = base::linux_gnu::opts();
|
||||
|
|
@ -20,6 +20,10 @@ pub(crate) fn target() -> Target {
|
|||
options: TargetOptions {
|
||||
abi: "ilp32".into(),
|
||||
features: "+v8a,+outline-atomics".into(),
|
||||
// the AAPCS64 expects use of non-leaf frame pointers per
|
||||
// https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer
|
||||
// and we tend to encounter interesting bugs in AArch64 unwinding code if we do not
|
||||
frame_pointer: FramePointer::NonLeaf,
|
||||
stack_probes: StackProbeType::Inline,
|
||||
mcount: "\u{1}_mcount".into(),
|
||||
endian: Endian::Big,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
use crate::spec::{SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base};
|
||||
use crate::spec::{
|
||||
FramePointer, SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base,
|
||||
};
|
||||
|
||||
// See https://developer.android.com/ndk/guides/abis.html#arm64-v8a
|
||||
// for target ABI requirements.
|
||||
|
|
@ -20,6 +22,10 @@ pub(crate) fn target() -> Target {
|
|||
// As documented in https://developer.android.com/ndk/guides/cpu-features.html
|
||||
// the neon (ASIMD) and FP must exist on all android aarch64 targets.
|
||||
features: "+v8a,+neon,+fp-armv8".into(),
|
||||
// the AAPCS64 expects use of non-leaf frame pointers per
|
||||
// https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer
|
||||
// and we tend to encounter interesting bugs in AArch64 unwinding code if we do not
|
||||
frame_pointer: FramePointer::NonLeaf,
|
||||
stack_probes: StackProbeType::Inline,
|
||||
supported_sanitizers: SanitizerSet::CFI
|
||||
| SanitizerSet::HWADDRESS
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
use crate::spec::{SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base};
|
||||
use crate::spec::{
|
||||
FramePointer, SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base,
|
||||
};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
|
|
@ -14,6 +16,10 @@ pub(crate) fn target() -> Target {
|
|||
arch: "aarch64".into(),
|
||||
options: TargetOptions {
|
||||
features: "+v8a,+outline-atomics".into(),
|
||||
// the AAPCS64 expects use of non-leaf frame pointers per
|
||||
// https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer
|
||||
// and we tend to encounter interesting bugs in AArch64 unwinding code if we do not
|
||||
frame_pointer: FramePointer::NonLeaf,
|
||||
mcount: "\u{1}_mcount".into(),
|
||||
max_atomic_width: Some(128),
|
||||
stack_probes: StackProbeType::Inline,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::spec::{StackProbeType, Target, TargetMetadata, TargetOptions, base};
|
||||
use crate::spec::{FramePointer, StackProbeType, Target, TargetMetadata, TargetOptions, base};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
|
|
@ -15,6 +15,10 @@ pub(crate) fn target() -> Target {
|
|||
options: TargetOptions {
|
||||
abi: "ilp32".into(),
|
||||
features: "+v8a,+outline-atomics".into(),
|
||||
// the AAPCS64 expects use of non-leaf frame pointers per
|
||||
// https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer
|
||||
// and we tend to encounter interesting bugs in AArch64 unwinding code if we do not
|
||||
frame_pointer: FramePointer::NonLeaf,
|
||||
max_atomic_width: Some(128),
|
||||
stack_probes: StackProbeType::Inline,
|
||||
mcount: "\u{1}_mcount".into(),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
use crate::spec::{SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base};
|
||||
use crate::spec::{
|
||||
FramePointer, SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base,
|
||||
};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
let mut base = base::linux_musl::opts();
|
||||
|
|
@ -26,6 +28,12 @@ pub(crate) fn target() -> Target {
|
|||
pointer_width: 64,
|
||||
data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
|
||||
arch: "aarch64".into(),
|
||||
options: TargetOptions { mcount: "\u{1}_mcount".into(), ..base },
|
||||
options: TargetOptions {
|
||||
// the AAPCS64 expects use of non-leaf frame pointers per
|
||||
// https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer
|
||||
// and we tend to encounter interesting bugs in AArch64 unwinding code if we do not
|
||||
frame_pointer: FramePointer::NonLeaf,
|
||||
mcount: "\u{1}_mcount".into(), ..base
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
use crate::spec::{SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base};
|
||||
use crate::spec::{
|
||||
FramePointer, SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base,
|
||||
};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
let mut base = base::linux_ohos::opts();
|
||||
|
|
@ -16,6 +18,10 @@ pub(crate) fn target() -> Target {
|
|||
data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
|
||||
arch: "aarch64".into(),
|
||||
options: TargetOptions {
|
||||
// the AAPCS64 expects use of non-leaf frame pointers per
|
||||
// https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer
|
||||
// and we tend to encounter interesting bugs in AArch64 unwinding code if we do not
|
||||
frame_pointer: FramePointer::NonLeaf,
|
||||
mcount: "\u{1}_mcount".into(),
|
||||
stack_probes: StackProbeType::Inline,
|
||||
supported_sanitizers: SanitizerSet::ADDRESS
|
||||
|
|
|
|||
|
|
@ -980,14 +980,16 @@ impl Target {
|
|||
// the use of soft-float, so all we can do here is some crude hacks.
|
||||
match &*self.abi {
|
||||
"softfloat" => {
|
||||
// This is not fully correct, LLVM actually doesn't let us enforce the softfloat
|
||||
// ABI properly... see <https://github.com/rust-lang/rust/issues/134375>.
|
||||
// FIXME: should we forbid "neon" here? But that would be a breaking change.
|
||||
NOTHING
|
||||
// LLVM will use float registers when `fp-armv8` is available, e.g. for
|
||||
// calls to built-ins. The only way to ensure a consistent softfloat ABI
|
||||
// on aarch64 is to never enable `fp-armv8`, so we enforce that.
|
||||
// In Rust we tie `neon` and `fp-armv8` together, therefore `neon` is the
|
||||
// feature we have to mark as incompatible.
|
||||
FeatureConstraints { required: &[], incompatible: &["neon"] }
|
||||
}
|
||||
_ => {
|
||||
// Everything else is assumed to use a hardfloat ABI. neon and fp-armv8 must be enabled.
|
||||
// These are Rust feature names and we use "neon" to control both of them.
|
||||
// `FeatureConstraints` uses Rust feature names, hence only "neon" shows up.
|
||||
FeatureConstraints { required: &["neon"], incompatible: &[] }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -337,6 +337,8 @@ trait_selection_rustc_on_unimplemented_expected_one_predicate_in_not = expected
|
|||
.label = unexpected quantity of predicates here
|
||||
trait_selection_rustc_on_unimplemented_invalid_flag = invalid flag in `on`-clause
|
||||
.label = expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `{$invalid_flag}`
|
||||
trait_selection_rustc_on_unimplemented_invalid_name = invalid name in `on`-clause
|
||||
.label = expected one of `cause`, `from_desugaring`, `Self` or any generic parameter of the trait, not `{$invalid_name}`
|
||||
trait_selection_rustc_on_unimplemented_invalid_predicate = this predicate is invalid
|
||||
.label = expected one of `any`, `all` or `not` here, not `{$invalid_pred}`
|
||||
trait_selection_rustc_on_unimplemented_missing_value = this attribute must have a value
|
||||
|
|
|
|||
|
|
@ -841,16 +841,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
return None;
|
||||
};
|
||||
|
||||
let (closure_def_id, found_args, by_ref_captures) = match *self_ty.kind() {
|
||||
let (closure_def_id, found_args, has_self_borrows) = match *self_ty.kind() {
|
||||
ty::Closure(def_id, args) => {
|
||||
(def_id, args.as_closure().sig().map_bound(|sig| sig.inputs()[0]), None)
|
||||
(def_id, args.as_closure().sig().map_bound(|sig| sig.inputs()[0]), false)
|
||||
}
|
||||
ty::CoroutineClosure(def_id, args) => (
|
||||
def_id,
|
||||
args.as_coroutine_closure()
|
||||
.coroutine_closure_sig()
|
||||
.map_bound(|sig| sig.tupled_inputs_ty),
|
||||
Some(args.as_coroutine_closure().coroutine_captures_by_ref_ty()),
|
||||
!args.as_coroutine_closure().tupled_upvars_ty().is_ty_var()
|
||||
&& args.as_coroutine_closure().has_self_borrows(),
|
||||
),
|
||||
_ => return None,
|
||||
};
|
||||
|
|
@ -884,10 +885,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
// If the closure has captures, then perhaps the reason that the trait
|
||||
// is unimplemented is because async closures don't implement `Fn`/`FnMut`
|
||||
// if they have captures.
|
||||
if let Some(by_ref_captures) = by_ref_captures
|
||||
&& let ty::FnPtr(sig_tys, _) = by_ref_captures.kind()
|
||||
&& !sig_tys.skip_binder().output().is_unit()
|
||||
{
|
||||
if has_self_borrows && expected_kind != ty::ClosureKind::FnOnce {
|
||||
let mut err = self.dcx().create_err(AsyncClosureNotFn {
|
||||
span: self.tcx.def_span(closure_def_id),
|
||||
kind: expected_kind.as_str(),
|
||||
|
|
@ -1503,11 +1501,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
return None;
|
||||
};
|
||||
|
||||
let Ok(Some(ImplSource::UserDefined(impl_data))) = SelectionContext::new(self)
|
||||
.poly_select(&obligation.with(
|
||||
self.tcx,
|
||||
predicate.kind().rebind(proj.projection_term.trait_ref(self.tcx)),
|
||||
))
|
||||
let trait_ref = self.enter_forall_and_leak_universe(
|
||||
predicate.kind().rebind(proj.projection_term.trait_ref(self.tcx)),
|
||||
);
|
||||
let Ok(Some(ImplSource::UserDefined(impl_data))) =
|
||||
SelectionContext::new(self).select(&obligation.with(self.tcx, trait_ref))
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -429,7 +429,19 @@ impl<'tcx> OnUnimplementedDirective {
|
|||
.next()
|
||||
.ok_or_else(|| tcx.dcx().emit_err(InvalidOnClause::Empty { span }))?;
|
||||
|
||||
match OnUnimplementedCondition::parse(cond) {
|
||||
let generics: Vec<Symbol> = tcx
|
||||
.generics_of(item_def_id)
|
||||
.own_params
|
||||
.iter()
|
||||
.filter_map(|param| {
|
||||
if matches!(param.kind, GenericParamDefKind::Lifetime) {
|
||||
None
|
||||
} else {
|
||||
Some(param.name)
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
match OnUnimplementedCondition::parse(cond, &generics) {
|
||||
Ok(condition) => Some(condition),
|
||||
Err(e) => return Err(tcx.dcx().emit_err(e)),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,9 +26,12 @@ impl OnUnimplementedCondition {
|
|||
})
|
||||
}
|
||||
|
||||
pub(crate) fn parse(input: &MetaItemInner) -> Result<Self, InvalidOnClause> {
|
||||
pub(crate) fn parse(
|
||||
input: &MetaItemInner,
|
||||
generics: &[Symbol],
|
||||
) -> Result<Self, InvalidOnClause> {
|
||||
let span = input.span();
|
||||
let pred = Predicate::parse(input)?;
|
||||
let pred = Predicate::parse(input, generics)?;
|
||||
Ok(OnUnimplementedCondition { span, pred })
|
||||
}
|
||||
}
|
||||
|
|
@ -52,7 +55,7 @@ enum Predicate {
|
|||
}
|
||||
|
||||
impl Predicate {
|
||||
fn parse(input: &MetaItemInner) -> Result<Self, InvalidOnClause> {
|
||||
fn parse(input: &MetaItemInner, generics: &[Symbol]) -> Result<Self, InvalidOnClause> {
|
||||
let meta_item = match input {
|
||||
MetaItemInner::MetaItem(meta_item) => meta_item,
|
||||
MetaItemInner::Lit(lit) => {
|
||||
|
|
@ -69,10 +72,10 @@ impl Predicate {
|
|||
|
||||
match meta_item.kind {
|
||||
MetaItemKind::List(ref mis) => match predicate.name {
|
||||
sym::any => Ok(Predicate::Any(Predicate::parse_sequence(mis)?)),
|
||||
sym::all => Ok(Predicate::All(Predicate::parse_sequence(mis)?)),
|
||||
sym::any => Ok(Predicate::Any(Predicate::parse_sequence(mis, generics)?)),
|
||||
sym::all => Ok(Predicate::All(Predicate::parse_sequence(mis, generics)?)),
|
||||
sym::not => match &**mis {
|
||||
[one] => Ok(Predicate::Not(Box::new(Predicate::parse(one)?))),
|
||||
[one] => Ok(Predicate::Not(Box::new(Predicate::parse(one, generics)?))),
|
||||
[first, .., last] => Err(InvalidOnClause::ExpectedOnePredInNot {
|
||||
span: first.span().to(last.span()),
|
||||
}),
|
||||
|
|
@ -83,7 +86,7 @@ impl Predicate {
|
|||
}
|
||||
},
|
||||
MetaItemKind::NameValue(MetaItemLit { symbol, .. }) => {
|
||||
let name = Name::parse(predicate);
|
||||
let name = Name::parse(predicate, generics)?;
|
||||
let value = FilterFormatString::parse(symbol);
|
||||
let kv = NameValue { name, value };
|
||||
Ok(Predicate::Match(kv))
|
||||
|
|
@ -95,8 +98,11 @@ impl Predicate {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_sequence(sequence: &[MetaItemInner]) -> Result<Vec<Self>, InvalidOnClause> {
|
||||
sequence.iter().map(Predicate::parse).collect()
|
||||
fn parse_sequence(
|
||||
sequence: &[MetaItemInner],
|
||||
generics: &[Symbol],
|
||||
) -> Result<Vec<Self>, InvalidOnClause> {
|
||||
sequence.iter().map(|item| Predicate::parse(item, generics)).collect()
|
||||
}
|
||||
|
||||
fn eval(&self, eval: &mut impl FnMut(FlagOrNv<'_>) -> bool) -> bool {
|
||||
|
|
@ -156,14 +162,13 @@ enum Name {
|
|||
}
|
||||
|
||||
impl Name {
|
||||
fn parse(Ident { name, .. }: Ident) -> Self {
|
||||
fn parse(Ident { name, span }: Ident, generics: &[Symbol]) -> Result<Self, InvalidOnClause> {
|
||||
match name {
|
||||
sym::_Self | kw::SelfUpper => Name::SelfUpper,
|
||||
sym::from_desugaring => Name::FromDesugaring,
|
||||
sym::cause => Name::Cause,
|
||||
// FIXME(mejrs) Perhaps we should start checking that
|
||||
// this actually is a valid generic parameter?
|
||||
generic => Name::GenericArg(generic),
|
||||
kw::SelfUpper => Ok(Name::SelfUpper),
|
||||
sym::from_desugaring => Ok(Name::FromDesugaring),
|
||||
sym::cause => Ok(Name::Cause),
|
||||
generic if generics.contains(&generic) => Ok(Name::GenericArg(generic)),
|
||||
invalid_name => Err(InvalidOnClause::InvalidName { invalid_name, span }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ use std::fmt;
|
|||
use std::ops::Range;
|
||||
|
||||
use errors::*;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_middle::ty::print::TraitRefPrintSugared;
|
||||
use rustc_middle::ty::{GenericParamDefKind, TyCtxt};
|
||||
use rustc_parse_format::{
|
||||
Alignment, Argument, Count, FormatSpec, ParseError, ParseMode, Parser, Piece as RpfPiece,
|
||||
Position,
|
||||
|
|
@ -232,48 +232,16 @@ fn parse_arg<'tcx>(
|
|||
) -> FormatArg {
|
||||
let (Ctx::RustcOnUnimplemented { tcx, trait_def_id }
|
||||
| Ctx::DiagnosticOnUnimplemented { tcx, trait_def_id }) = ctx;
|
||||
let trait_name = tcx.item_ident(*trait_def_id);
|
||||
let generics = tcx.generics_of(trait_def_id);
|
||||
|
||||
let span = slice_span(input_span, arg.position_span.clone());
|
||||
|
||||
match arg.position {
|
||||
// Something like "hello {name}"
|
||||
Position::ArgumentNamed(name) => match (ctx, Symbol::intern(name)) {
|
||||
// accepted, but deprecated
|
||||
(Ctx::RustcOnUnimplemented { .. }, sym::_Self) => {
|
||||
warnings
|
||||
.push(FormatWarning::FutureIncompat { span, help: String::from("use {Self}") });
|
||||
FormatArg::SelfUpper
|
||||
}
|
||||
(
|
||||
Ctx::RustcOnUnimplemented { .. },
|
||||
sym::from_desugaring
|
||||
| sym::crate_local
|
||||
| sym::direct
|
||||
| sym::cause
|
||||
| sym::float
|
||||
| sym::integer_
|
||||
| sym::integral,
|
||||
) => {
|
||||
warnings.push(FormatWarning::FutureIncompat {
|
||||
span,
|
||||
help: String::from("don't use this in a format string"),
|
||||
});
|
||||
FormatArg::AsIs(String::new())
|
||||
}
|
||||
|
||||
// Only `#[rustc_on_unimplemented]` can use these
|
||||
(Ctx::RustcOnUnimplemented { .. }, sym::ItemContext) => FormatArg::ItemContext,
|
||||
(Ctx::RustcOnUnimplemented { .. }, sym::This) => FormatArg::This,
|
||||
(Ctx::RustcOnUnimplemented { .. }, sym::Trait) => FormatArg::Trait,
|
||||
// `{ThisTraitsName}`. Some attrs in std use this, but I'd like to change it to the more general `{This}`
|
||||
// because that'll be simpler to parse and extend in the future
|
||||
(Ctx::RustcOnUnimplemented { .. }, name) if name == trait_name.name => {
|
||||
warnings
|
||||
.push(FormatWarning::FutureIncompat { span, help: String::from("use {This}") });
|
||||
FormatArg::This
|
||||
}
|
||||
|
||||
// Any attribute can use these
|
||||
(
|
||||
Ctx::RustcOnUnimplemented { .. } | Ctx::DiagnosticOnUnimplemented { .. },
|
||||
|
|
@ -282,7 +250,10 @@ fn parse_arg<'tcx>(
|
|||
(
|
||||
Ctx::RustcOnUnimplemented { .. } | Ctx::DiagnosticOnUnimplemented { .. },
|
||||
generic_param,
|
||||
) if generics.own_params.iter().any(|param| param.name == generic_param) => {
|
||||
) if tcx.generics_of(trait_def_id).own_params.iter().any(|param| {
|
||||
!matches!(param.kind, GenericParamDefKind::Lifetime) && param.name == generic_param
|
||||
}) =>
|
||||
{
|
||||
FormatArg::GenericParam { generic_param }
|
||||
}
|
||||
|
||||
|
|
@ -375,39 +346,4 @@ pub mod errors {
|
|||
#[diag(trait_selection_missing_options_for_on_unimplemented_attr)]
|
||||
#[help]
|
||||
pub struct MissingOptionsForOnUnimplementedAttr;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(trait_selection_ignored_diagnostic_option)]
|
||||
pub struct IgnoredDiagnosticOption {
|
||||
pub option_name: &'static str,
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[label(trait_selection_other_label)]
|
||||
pub prev_span: Span,
|
||||
}
|
||||
|
||||
impl IgnoredDiagnosticOption {
|
||||
pub fn maybe_emit_warning<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
item_def_id: DefId,
|
||||
new: Option<Span>,
|
||||
old: Option<Span>,
|
||||
option_name: &'static str,
|
||||
) {
|
||||
if let (Some(new_item), Some(old_item)) = (new, old) {
|
||||
if let Some(item_def_id) = item_def_id.as_local() {
|
||||
tcx.emit_node_span_lint(
|
||||
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
tcx.local_def_id_to_hir_id(item_def_id),
|
||||
new_item,
|
||||
IgnoredDiagnosticOption {
|
||||
span: new_item,
|
||||
prev_span: old_item,
|
||||
option_name,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,6 +72,13 @@ pub enum InvalidOnClause {
|
|||
span: Span,
|
||||
invalid_flag: Symbol,
|
||||
},
|
||||
#[diag(trait_selection_rustc_on_unimplemented_invalid_name, code = E0232)]
|
||||
InvalidName {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
span: Span,
|
||||
invalid_name: Symbol,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use rustc_hir::LangItem;
|
|||
use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
|
||||
use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
|
||||
use rustc_infer::infer::canonical::{
|
||||
Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarInfo, CanonicalVarValues,
|
||||
Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarKind, CanonicalVarValues,
|
||||
};
|
||||
use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TyCtxtInferExt};
|
||||
use rustc_infer::traits::solve::Goal;
|
||||
|
|
@ -190,11 +190,11 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
|
|||
|
||||
fn instantiate_canonical_var_with_infer(
|
||||
&self,
|
||||
cv_info: CanonicalVarInfo<'tcx>,
|
||||
kind: CanonicalVarKind<'tcx>,
|
||||
span: Span,
|
||||
universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
|
||||
) -> ty::GenericArg<'tcx> {
|
||||
self.0.instantiate_canonical_var(span, cv_info, universe_map)
|
||||
self.0.instantiate_canonical_var(span, kind, universe_map)
|
||||
}
|
||||
|
||||
fn add_item_bounds_for_hidden_type(
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use rustc_infer::traits::solve::inspect::ProbeKind;
|
|||
use rustc_infer::traits::solve::{CandidateSource, Certainty, Goal};
|
||||
use rustc_infer::traits::{
|
||||
BuiltinImplSource, ImplSource, ImplSourceUserDefinedData, Obligation, ObligationCause,
|
||||
PolyTraitObligation, Selection, SelectionError, SelectionResult,
|
||||
Selection, SelectionError, SelectionResult, TraitObligation,
|
||||
};
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::{bug, span_bug};
|
||||
|
|
@ -17,7 +17,7 @@ use crate::solve::inspect::{self, ProofTreeInferCtxtExt};
|
|||
impl<'tcx> InferCtxt<'tcx> {
|
||||
fn select_in_new_trait_solver(
|
||||
&self,
|
||||
obligation: &PolyTraitObligation<'tcx>,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
) -> SelectionResult<'tcx, Selection<'tcx>> {
|
||||
assert!(self.next_trait_solver());
|
||||
|
||||
|
|
|
|||
|
|
@ -540,10 +540,13 @@ pub fn try_evaluate_const<'tcx>(
|
|||
| ty::ConstKind::Placeholder(_)
|
||||
| ty::ConstKind::Expr(_) => Err(EvaluateConstErr::HasGenericsOrInfers),
|
||||
ty::ConstKind::Unevaluated(uv) => {
|
||||
let opt_anon_const_kind =
|
||||
(tcx.def_kind(uv.def) == DefKind::AnonConst).then(|| tcx.anon_const_kind(uv.def));
|
||||
|
||||
// Postpone evaluation of constants that depend on generic parameters or
|
||||
// inference variables.
|
||||
//
|
||||
// We use `TypingMode::PostAnalysis` here which is not *technically* correct
|
||||
// We use `TypingMode::PostAnalysis` here which is not *technically* correct
|
||||
// to be revealing opaque types here as borrowcheck has not run yet. However,
|
||||
// CTFE itself uses `TypingMode::PostAnalysis` unconditionally even during
|
||||
// typeck and not doing so has a lot of (undesirable) fallout (#101478, #119821).
|
||||
|
|
@ -551,65 +554,95 @@ pub fn try_evaluate_const<'tcx>(
|
|||
//
|
||||
// FIXME: `const_eval_resolve_for_typeck` should probably just modify the env itself
|
||||
// instead of having this logic here
|
||||
let (args, typing_env) = if tcx.features().generic_const_exprs()
|
||||
&& uv.has_non_region_infer()
|
||||
{
|
||||
// `feature(generic_const_exprs)` causes anon consts to inherit all parent generics. This can cause
|
||||
// inference variables and generic parameters to show up in `ty::Const` even though the anon const
|
||||
// does not actually make use of them. We handle this case specially and attempt to evaluate anyway.
|
||||
match tcx.thir_abstract_const(uv.def) {
|
||||
Ok(Some(ct)) => {
|
||||
let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, uv.args));
|
||||
if let Err(e) = ct.error_reported() {
|
||||
return Err(EvaluateConstErr::EvaluationFailure(e));
|
||||
} else if ct.has_non_region_infer() || ct.has_non_region_param() {
|
||||
// If the anon const *does* actually use generic parameters or inference variables from
|
||||
// the generic arguments provided for it, then we should *not* attempt to evaluate it.
|
||||
return Err(EvaluateConstErr::HasGenericsOrInfers);
|
||||
} else {
|
||||
let args = replace_param_and_infer_args_with_placeholder(tcx, uv.args);
|
||||
let typing_env = infcx
|
||||
.typing_env(tcx.erase_regions(param_env))
|
||||
.with_post_analysis_normalized(tcx);
|
||||
(args, typing_env)
|
||||
let (args, typing_env) = match opt_anon_const_kind {
|
||||
// We handle `generic_const_exprs` separately as reasonable ways of handling constants in the type system
|
||||
// completely fall apart under `generic_const_exprs` and makes this whole function Really hard to reason
|
||||
// about if you have to consider gce whatsoever.
|
||||
Some(ty::AnonConstKind::GCE) => {
|
||||
if uv.has_non_region_infer() || uv.has_non_region_param() {
|
||||
// `feature(generic_const_exprs)` causes anon consts to inherit all parent generics. This can cause
|
||||
// inference variables and generic parameters to show up in `ty::Const` even though the anon const
|
||||
// does not actually make use of them. We handle this case specially and attempt to evaluate anyway.
|
||||
match tcx.thir_abstract_const(uv.def) {
|
||||
Ok(Some(ct)) => {
|
||||
let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, uv.args));
|
||||
if let Err(e) = ct.error_reported() {
|
||||
return Err(EvaluateConstErr::EvaluationFailure(e));
|
||||
} else if ct.has_non_region_infer() || ct.has_non_region_param() {
|
||||
// If the anon const *does* actually use generic parameters or inference variables from
|
||||
// the generic arguments provided for it, then we should *not* attempt to evaluate it.
|
||||
return Err(EvaluateConstErr::HasGenericsOrInfers);
|
||||
} else {
|
||||
let args =
|
||||
replace_param_and_infer_args_with_placeholder(tcx, uv.args);
|
||||
let typing_env = infcx
|
||||
.typing_env(tcx.erase_regions(param_env))
|
||||
.with_post_analysis_normalized(tcx);
|
||||
(args, typing_env)
|
||||
}
|
||||
}
|
||||
Err(_) | Ok(None) => {
|
||||
let args = GenericArgs::identity_for_item(tcx, uv.def);
|
||||
let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def);
|
||||
(args, typing_env)
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) | Ok(None) => {
|
||||
let args = GenericArgs::identity_for_item(tcx, uv.def);
|
||||
let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def);
|
||||
(args, typing_env)
|
||||
} else {
|
||||
let typing_env = infcx
|
||||
.typing_env(tcx.erase_regions(param_env))
|
||||
.with_post_analysis_normalized(tcx);
|
||||
(uv.args, typing_env)
|
||||
}
|
||||
}
|
||||
} else if tcx.def_kind(uv.def) == DefKind::AnonConst && uv.has_non_region_infer() {
|
||||
// FIXME: remove this when `const_evaluatable_unchecked` is a hard error.
|
||||
//
|
||||
// Diagnostics will sometimes replace the identity args of anon consts in
|
||||
// array repeat expr counts with inference variables so we have to handle this
|
||||
// even though it is not something we should ever actually encounter.
|
||||
//
|
||||
// Array repeat expr counts are allowed to syntactically use generic parameters
|
||||
// but must not actually depend on them in order to evalaute successfully. This means
|
||||
// that it is actually fine to evalaute them in their own environment rather than with
|
||||
// the actually provided generic arguments.
|
||||
tcx.dcx().delayed_bug(
|
||||
"Encountered anon const with inference variable args but no error reported",
|
||||
);
|
||||
Some(ty::AnonConstKind::RepeatExprCount) => {
|
||||
if uv.has_non_region_infer() {
|
||||
// Diagnostics will sometimes replace the identity args of anon consts in
|
||||
// array repeat expr counts with inference variables so we have to handle this
|
||||
// even though it is not something we should ever actually encounter.
|
||||
//
|
||||
// Array repeat expr counts are allowed to syntactically use generic parameters
|
||||
// but must not actually depend on them in order to evalaute successfully. This means
|
||||
// that it is actually fine to evalaute them in their own environment rather than with
|
||||
// the actually provided generic arguments.
|
||||
tcx.dcx().delayed_bug("AnonConst with infer args but no error reported");
|
||||
}
|
||||
|
||||
let args = GenericArgs::identity_for_item(tcx, uv.def);
|
||||
let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def);
|
||||
(args, typing_env)
|
||||
} else {
|
||||
// FIXME: This codepath is reachable under `associated_const_equality` and in the
|
||||
// future will be reachable by `min_generic_const_args`. We should handle inference
|
||||
// variables and generic parameters properly instead of doing nothing.
|
||||
let typing_env = infcx
|
||||
.typing_env(tcx.erase_regions(param_env))
|
||||
.with_post_analysis_normalized(tcx);
|
||||
(uv.args, typing_env)
|
||||
// The generic args of repeat expr counts under `min_const_generics` are not supposed to
|
||||
// affect evaluation of the constant as this would make it a "truly" generic const arg.
|
||||
// To prevent this we discard all the generic arguments and evalaute with identity args
|
||||
// and in its own environment instead of the current environment we are normalizing in.
|
||||
let args = GenericArgs::identity_for_item(tcx, uv.def);
|
||||
let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def);
|
||||
|
||||
(args, typing_env)
|
||||
}
|
||||
_ => {
|
||||
// We are only dealing with "truly" generic/uninferred constants here:
|
||||
// - GCEConsts have been handled separately
|
||||
// - Repeat expr count back compat consts have also been handled separately
|
||||
// So we are free to simply defer evaluation here.
|
||||
//
|
||||
// FIXME: This assumes that `args` are normalized which is not necessarily true
|
||||
//
|
||||
// Const patterns are converted to type system constants before being
|
||||
// evaluated. However, we don't care about them here as pattern evaluation
|
||||
// logic does not go through type system normalization. If it did this would
|
||||
// be a backwards compatibility problem as we do not enforce "syntactic" non-
|
||||
// usage of generic parameters like we do here.
|
||||
if uv.args.has_non_region_param() || uv.args.has_non_region_infer() {
|
||||
return Err(EvaluateConstErr::HasGenericsOrInfers);
|
||||
}
|
||||
|
||||
let typing_env = infcx
|
||||
.typing_env(tcx.erase_regions(param_env))
|
||||
.with_post_analysis_normalized(tcx);
|
||||
(uv.args, typing_env)
|
||||
}
|
||||
};
|
||||
let uv = ty::UnevaluatedConst::new(uv.def, args);
|
||||
|
||||
let uv = ty::UnevaluatedConst::new(uv.def, args);
|
||||
let erased_uv = tcx.erase_regions(uv);
|
||||
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
match tcx.const_eval_resolve_for_typeck(typing_env, erased_uv, DUMMY_SP) {
|
||||
Ok(Ok(val)) => Ok(ty::Const::new_value(
|
||||
|
|
|
|||
|
|
@ -378,6 +378,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>(
|
|||
term: projected_term,
|
||||
obligations: mut projected_obligations,
|
||||
})) => {
|
||||
debug!("opt_normalize_projection_type: progress");
|
||||
// if projection succeeded, then what we get out of this
|
||||
// is also non-normalized (consider: it was derived from
|
||||
// an impl, where-clause etc) and hence we must
|
||||
|
|
@ -408,6 +409,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>(
|
|||
Ok(Some(result.value))
|
||||
}
|
||||
Ok(Projected::NoProgress(projected_ty)) => {
|
||||
debug!("opt_normalize_projection_type: no progress");
|
||||
let result =
|
||||
Normalized { value: projected_ty, obligations: PredicateObligations::new() };
|
||||
infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone());
|
||||
|
|
@ -621,8 +623,17 @@ struct Progress<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> Progress<'tcx> {
|
||||
fn error(tcx: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Self {
|
||||
Progress { term: Ty::new_error(tcx, guar).into(), obligations: PredicateObligations::new() }
|
||||
fn error_for_term(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
alias_term: ty::AliasTerm<'tcx>,
|
||||
guar: ErrorGuaranteed,
|
||||
) -> Self {
|
||||
let err_term = if alias_term.kind(tcx).is_type() {
|
||||
Ty::new_error(tcx, guar).into()
|
||||
} else {
|
||||
ty::Const::new_error(tcx, guar).into()
|
||||
};
|
||||
Progress { term: err_term, obligations: PredicateObligations::new() }
|
||||
}
|
||||
|
||||
fn with_addl_obligations(mut self, mut obligations: PredicateObligations<'tcx>) -> Self {
|
||||
|
|
@ -650,7 +661,11 @@ fn project<'cx, 'tcx>(
|
|||
}
|
||||
|
||||
if let Err(guar) = obligation.predicate.error_reported() {
|
||||
return Ok(Projected::Progress(Progress::error(selcx.tcx(), guar)));
|
||||
return Ok(Projected::Progress(Progress::error_for_term(
|
||||
selcx.tcx(),
|
||||
obligation.predicate,
|
||||
guar,
|
||||
)));
|
||||
}
|
||||
|
||||
let mut candidates = ProjectionCandidateSet::None;
|
||||
|
|
@ -1965,7 +1980,13 @@ fn confirm_impl_candidate<'cx, 'tcx>(
|
|||
let param_env = obligation.param_env;
|
||||
let assoc_term = match specialization_graph::assoc_def(tcx, impl_def_id, assoc_item_id) {
|
||||
Ok(assoc_term) => assoc_term,
|
||||
Err(guar) => return Ok(Projected::Progress(Progress::error(tcx, guar))),
|
||||
Err(guar) => {
|
||||
return Ok(Projected::Progress(Progress::error_for_term(
|
||||
tcx,
|
||||
obligation.predicate,
|
||||
guar,
|
||||
)));
|
||||
}
|
||||
};
|
||||
|
||||
// This means that the impl is missing a definition for the
|
||||
|
|
|
|||
|
|
@ -265,9 +265,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
&mut self,
|
||||
obligation: &PolyTraitObligation<'tcx>,
|
||||
) -> SelectionResult<'tcx, Selection<'tcx>> {
|
||||
if self.infcx.next_trait_solver() {
|
||||
return self.infcx.select_in_new_trait_solver(obligation);
|
||||
}
|
||||
assert!(!self.infcx.next_trait_solver());
|
||||
|
||||
let candidate = match self.select_from_obligation(obligation) {
|
||||
Err(SelectionError::Overflow(OverflowError::Canonical)) => {
|
||||
|
|
@ -299,6 +297,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
) -> SelectionResult<'tcx, Selection<'tcx>> {
|
||||
if self.infcx.next_trait_solver() {
|
||||
return self.infcx.select_in_new_trait_solver(obligation);
|
||||
}
|
||||
|
||||
self.poly_select(&Obligation {
|
||||
cause: obligation.cause.clone(),
|
||||
param_env: obligation.param_env,
|
||||
|
|
@ -2866,7 +2868,7 @@ fn rebind_coroutine_witness_types<'tcx>(
|
|||
let shifted_coroutine_types =
|
||||
tcx.shift_bound_var_indices(bound_vars.len(), bound_coroutine_types.skip_binder());
|
||||
ty::Binder::bind_with_vars(
|
||||
ty::EarlyBinder::bind(shifted_coroutine_types.to_vec()).instantiate(tcx, args),
|
||||
ty::EarlyBinder::bind(shifted_coroutine_types.types.to_vec()).instantiate(tcx, args),
|
||||
tcx.mk_bound_variable_kinds_from_iter(
|
||||
bound_vars.iter().chain(bound_coroutine_types.bound_vars()),
|
||||
),
|
||||
|
|
|
|||
37
compiler/rustc_traits/src/coroutine_witnesses.rs
Normal file
37
compiler/rustc_traits/src/coroutine_witnesses.rs
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::ty::{self, TyCtxt, fold_regions};
|
||||
|
||||
/// Return the set of types that should be taken into account when checking
|
||||
/// trait bounds on a coroutine's internal state. This properly replaces
|
||||
/// `ReErased` with new existential bound lifetimes.
|
||||
pub(crate) fn coroutine_hidden_types<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, ty::Binder<'tcx, ty::CoroutineWitnessTypes<TyCtxt<'tcx>>>> {
|
||||
let coroutine_layout = tcx.mir_coroutine_witnesses(def_id);
|
||||
let mut vars = vec![];
|
||||
let bound_tys = tcx.mk_type_list_from_iter(
|
||||
coroutine_layout
|
||||
.as_ref()
|
||||
.map_or_else(|| [].iter(), |l| l.field_tys.iter())
|
||||
.filter(|decl| !decl.ignore_for_traits)
|
||||
.map(|decl| {
|
||||
let ty = fold_regions(tcx, decl.ty, |re, debruijn| {
|
||||
assert_eq!(re, tcx.lifetimes.re_erased);
|
||||
let var = ty::BoundVar::from_usize(vars.len());
|
||||
vars.push(ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon));
|
||||
ty::Region::new_bound(
|
||||
tcx,
|
||||
debruijn,
|
||||
ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon },
|
||||
)
|
||||
});
|
||||
ty
|
||||
}),
|
||||
);
|
||||
|
||||
ty::EarlyBinder::bind(ty::Binder::bind_with_vars(
|
||||
ty::CoroutineWitnessTypes { types: bound_tys },
|
||||
tcx.mk_bound_variable_kinds(&vars),
|
||||
))
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
// tidy-alphabetical-end
|
||||
|
||||
mod codegen;
|
||||
mod coroutine_witnesses;
|
||||
mod dropck_outlives;
|
||||
mod evaluate_obligation;
|
||||
mod implied_outlives_bounds;
|
||||
|
|
@ -24,4 +25,5 @@ pub fn provide(p: &mut Providers) {
|
|||
normalize_erasing_regions::provide(p);
|
||||
type_op::provide(p);
|
||||
p.codegen_select_candidate = codegen::codegen_select_candidate;
|
||||
p.coroutine_hidden_types = coroutine_witnesses::coroutine_hidden_types;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ pub struct CanonicalQueryInput<I: Interner, V> {
|
|||
pub struct Canonical<I: Interner, V> {
|
||||
pub value: V,
|
||||
pub max_universe: UniverseIndex,
|
||||
pub variables: I::CanonicalVars,
|
||||
pub variables: I::CanonicalVarKinds,
|
||||
}
|
||||
|
||||
impl<I: Interner, V> Canonical<I, V> {
|
||||
|
|
@ -89,63 +89,6 @@ impl<I: Interner, V: fmt::Display> fmt::Display for Canonical<I, V> {
|
|||
/// a copy of the canonical value in some other inference context,
|
||||
/// with fresh inference variables replacing the canonical values.
|
||||
#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
|
||||
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
|
||||
#[cfg_attr(
|
||||
feature = "nightly",
|
||||
derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
|
||||
)]
|
||||
pub struct CanonicalVarInfo<I: Interner> {
|
||||
pub kind: CanonicalVarKind<I>,
|
||||
}
|
||||
|
||||
impl<I: Interner> CanonicalVarInfo<I> {
|
||||
pub fn universe(self) -> UniverseIndex {
|
||||
self.kind.universe()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_updated_universe(self, ui: UniverseIndex) -> CanonicalVarInfo<I> {
|
||||
CanonicalVarInfo { kind: self.kind.with_updated_universe(ui) }
|
||||
}
|
||||
|
||||
pub fn is_existential(&self) -> bool {
|
||||
match self.kind {
|
||||
CanonicalVarKind::Ty(_) => true,
|
||||
CanonicalVarKind::PlaceholderTy(_) => false,
|
||||
CanonicalVarKind::Region(_) => true,
|
||||
CanonicalVarKind::PlaceholderRegion(..) => false,
|
||||
CanonicalVarKind::Const(_) => true,
|
||||
CanonicalVarKind::PlaceholderConst(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_region(&self) -> bool {
|
||||
match self.kind {
|
||||
CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => true,
|
||||
CanonicalVarKind::Ty(_)
|
||||
| CanonicalVarKind::PlaceholderTy(_)
|
||||
| CanonicalVarKind::Const(_)
|
||||
| CanonicalVarKind::PlaceholderConst(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_placeholder_index(self) -> usize {
|
||||
match self.kind {
|
||||
CanonicalVarKind::Ty(_) | CanonicalVarKind::Region(_) | CanonicalVarKind::Const(_) => {
|
||||
panic!("expected placeholder: {self:?}")
|
||||
}
|
||||
|
||||
CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.var().as_usize(),
|
||||
CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.var().as_usize(),
|
||||
CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.var().as_usize(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes the "kind" of the canonical variable. This is a "kind"
|
||||
/// in the type-theory sense of the term -- i.e., a "meta" type system
|
||||
/// that analyzes type-like values.
|
||||
#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
|
||||
#[cfg_attr(
|
||||
feature = "nightly",
|
||||
derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
|
||||
|
|
@ -214,6 +157,39 @@ impl<I: Interner> CanonicalVarKind<I> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_existential(self) -> bool {
|
||||
match self {
|
||||
CanonicalVarKind::Ty(_) => true,
|
||||
CanonicalVarKind::PlaceholderTy(_) => false,
|
||||
CanonicalVarKind::Region(_) => true,
|
||||
CanonicalVarKind::PlaceholderRegion(..) => false,
|
||||
CanonicalVarKind::Const(_) => true,
|
||||
CanonicalVarKind::PlaceholderConst(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_region(self) -> bool {
|
||||
match self {
|
||||
CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => true,
|
||||
CanonicalVarKind::Ty(_)
|
||||
| CanonicalVarKind::PlaceholderTy(_)
|
||||
| CanonicalVarKind::Const(_)
|
||||
| CanonicalVarKind::PlaceholderConst(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_placeholder_index(self) -> usize {
|
||||
match self {
|
||||
CanonicalVarKind::Ty(_) | CanonicalVarKind::Region(_) | CanonicalVarKind::Const(_) => {
|
||||
panic!("expected placeholder: {self:?}")
|
||||
}
|
||||
|
||||
CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.var().as_usize(),
|
||||
CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.var().as_usize(),
|
||||
CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.var().as_usize(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Rust actually has more than one category of type variables;
|
||||
|
|
@ -306,11 +282,11 @@ impl<I: Interner> CanonicalVarValues<I> {
|
|||
|
||||
// Given a list of canonical variables, construct a set of values which are
|
||||
// the identity response.
|
||||
pub fn make_identity(cx: I, infos: I::CanonicalVars) -> CanonicalVarValues<I> {
|
||||
pub fn make_identity(cx: I, infos: I::CanonicalVarKinds) -> CanonicalVarValues<I> {
|
||||
CanonicalVarValues {
|
||||
var_values: cx.mk_args_from_iter(infos.iter().enumerate().map(
|
||||
|(i, info)| -> I::GenericArg {
|
||||
match info.kind {
|
||||
|(i, kind)| -> I::GenericArg {
|
||||
match kind {
|
||||
CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => {
|
||||
Ty::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i))
|
||||
.into()
|
||||
|
|
|
|||
|
|
@ -64,13 +64,16 @@ pub trait Interner:
|
|||
+ TypeVisitable<Self>
|
||||
+ SliceLike<Item = Self::LocalDefId>;
|
||||
|
||||
type CanonicalVars: Copy
|
||||
type CanonicalVarKinds: Copy
|
||||
+ Debug
|
||||
+ Hash
|
||||
+ Eq
|
||||
+ SliceLike<Item = ty::CanonicalVarInfo<Self>>
|
||||
+ SliceLike<Item = ty::CanonicalVarKind<Self>>
|
||||
+ Default;
|
||||
fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars;
|
||||
fn mk_canonical_var_kinds(
|
||||
self,
|
||||
kinds: &[ty::CanonicalVarKind<Self>],
|
||||
) -> Self::CanonicalVarKinds;
|
||||
|
||||
type ExternalConstraints: Copy
|
||||
+ Debug
|
||||
|
|
@ -210,7 +213,7 @@ pub trait Interner:
|
|||
fn coroutine_hidden_types(
|
||||
self,
|
||||
def_id: Self::DefId,
|
||||
) -> ty::EarlyBinder<Self, ty::Binder<Self, Self::Tys>>;
|
||||
) -> ty::EarlyBinder<Self, ty::Binder<Self, ty::CoroutineWitnessTypes<Self>>>;
|
||||
|
||||
fn fn_sig(
|
||||
self,
|
||||
|
|
|
|||
|
|
@ -1163,3 +1163,13 @@ pub struct FnHeader<I: Interner> {
|
|||
pub safety: I::Safety,
|
||||
pub abi: I::Abi,
|
||||
}
|
||||
|
||||
#[derive_where(Clone, Copy, Debug, PartialEq, Eq, Hash; I: Interner)]
|
||||
#[cfg_attr(
|
||||
feature = "nightly",
|
||||
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
|
||||
)]
|
||||
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
|
||||
pub struct CoroutineWitnessTypes<I: Interner> {
|
||||
pub types: I::Tys,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -588,7 +588,7 @@ impl<T, const N: usize> [T; N] {
|
|||
/// Returns a mutable slice containing the entire array. Equivalent to
|
||||
/// `&mut s[..]`.
|
||||
#[stable(feature = "array_as_slice", since = "1.57.0")]
|
||||
#[rustc_const_unstable(feature = "const_array_as_mut_slice", issue = "133333")]
|
||||
#[rustc_const_stable(feature = "const_array_as_mut_slice", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub const fn as_mut_slice(&mut self) -> &mut [T] {
|
||||
self
|
||||
}
|
||||
|
|
|
|||
|
|
@ -575,7 +575,7 @@ pub trait Into<T>: Sized {
|
|||
#[rustc_diagnostic_item = "From"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_on_unimplemented(on(
|
||||
all(_Self = "&str", T = "alloc::string::String"),
|
||||
all(Self = "&str", T = "alloc::string::String"),
|
||||
note = "to coerce a `{T}` into a `{Self}`, use `&*` as a prefix",
|
||||
))]
|
||||
#[doc(search_unbox)]
|
||||
|
|
|
|||
|
|
@ -511,13 +511,8 @@ impl CStr {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::ffi::CStr;
|
||||
///
|
||||
/// let cstr = CStr::from_bytes_with_nul(b"foo\0").unwrap();
|
||||
/// assert_eq!(cstr.count_bytes(), 3);
|
||||
///
|
||||
/// let cstr = CStr::from_bytes_with_nul(b"\0").unwrap();
|
||||
/// assert_eq!(cstr.count_bytes(), 0);
|
||||
/// assert_eq!(c"foo".count_bytes(), 3);
|
||||
/// assert_eq!(c"".count_bytes(), 0);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[must_use]
|
||||
|
|
@ -533,19 +528,8 @@ impl CStr {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::ffi::CStr;
|
||||
/// # use std::ffi::FromBytesWithNulError;
|
||||
///
|
||||
/// # fn main() { test().unwrap(); }
|
||||
/// # fn test() -> Result<(), FromBytesWithNulError> {
|
||||
/// let cstr = CStr::from_bytes_with_nul(b"foo\0")?;
|
||||
/// assert!(!cstr.is_empty());
|
||||
///
|
||||
/// let empty_cstr = CStr::from_bytes_with_nul(b"\0")?;
|
||||
/// assert!(empty_cstr.is_empty());
|
||||
/// assert!(!c"foo".is_empty());
|
||||
/// assert!(c"".is_empty());
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "cstr_is_empty", since = "1.71.0")]
|
||||
|
|
@ -569,10 +553,7 @@ impl CStr {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::ffi::CStr;
|
||||
///
|
||||
/// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
|
||||
/// assert_eq!(cstr.to_bytes(), b"foo");
|
||||
/// assert_eq!(c"foo".to_bytes(), b"foo");
|
||||
/// ```
|
||||
#[inline]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
|
|
@ -598,10 +579,7 @@ impl CStr {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::ffi::CStr;
|
||||
///
|
||||
/// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
|
||||
/// assert_eq!(cstr.to_bytes_with_nul(), b"foo\0");
|
||||
/// assert_eq!(c"foo".to_bytes_with_nul(), b"foo\0");
|
||||
/// ```
|
||||
#[inline]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
|
|
@ -623,10 +601,8 @@ impl CStr {
|
|||
///
|
||||
/// ```
|
||||
/// #![feature(cstr_bytes)]
|
||||
/// use std::ffi::CStr;
|
||||
///
|
||||
/// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
|
||||
/// assert!(cstr.bytes().eq(*b"foo"));
|
||||
/// assert!(c"foo".bytes().eq(*b"foo"));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "cstr_bytes", issue = "112115")]
|
||||
|
|
@ -645,10 +621,7 @@ impl CStr {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::ffi::CStr;
|
||||
///
|
||||
/// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
|
||||
/// assert_eq!(cstr.to_str(), Ok("foo"));
|
||||
/// assert_eq!(c"foo".to_str(), Ok("foo"));
|
||||
/// ```
|
||||
#[stable(feature = "cstr_to_str", since = "1.4.0")]
|
||||
#[rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0")]
|
||||
|
|
|
|||
|
|
@ -856,10 +856,10 @@ impl Display for Arguments<'_> {
|
|||
on(
|
||||
crate_local,
|
||||
label = "`{Self}` cannot be formatted using `{{:?}}`",
|
||||
note = "add `#[derive(Debug)]` to `{Self}` or manually `impl {Debug} for {Self}`"
|
||||
note = "add `#[derive(Debug)]` to `{Self}` or manually `impl {This} for {Self}`"
|
||||
),
|
||||
message = "`{Self}` doesn't implement `{Debug}`",
|
||||
label = "`{Self}` cannot be formatted using `{{:?}}` because it doesn't implement `{Debug}`"
|
||||
message = "`{Self}` doesn't implement `{This}`",
|
||||
label = "`{Self}` cannot be formatted using `{{:?}}` because it doesn't implement `{This}`"
|
||||
)]
|
||||
#[doc(alias = "{:?}")]
|
||||
#[rustc_diagnostic_item = "Debug"]
|
||||
|
|
@ -969,12 +969,12 @@ pub use macros::Debug;
|
|||
/// ```
|
||||
#[rustc_on_unimplemented(
|
||||
on(
|
||||
any(_Self = "std::path::Path", _Self = "std::path::PathBuf"),
|
||||
any(Self = "std::path::Path", Self = "std::path::PathBuf"),
|
||||
label = "`{Self}` cannot be formatted with the default formatter; call `.display()` on it",
|
||||
note = "call `.display()` or `.to_string_lossy()` to safely print paths, \
|
||||
as they may contain non-Unicode data"
|
||||
),
|
||||
message = "`{Self}` doesn't implement `{Display}`",
|
||||
message = "`{Self}` doesn't implement `{This}`",
|
||||
label = "`{Self}` cannot be formatted with the default formatter",
|
||||
note = "in format strings you may be able to use `{{:?}}` (or {{:#?}} for pretty-print) instead"
|
||||
)]
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@ pub const unsafe fn assert_unchecked(cond: bool) {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore-wasm
|
||||
/// use std::sync::atomic::{AtomicBool, Ordering};
|
||||
/// use std::sync::Arc;
|
||||
/// use std::{hint, thread};
|
||||
|
|
|
|||
|
|
@ -2296,12 +2296,6 @@ pub fn round_ties_even_f16(x: f16) -> f16;
|
|||
#[rustc_nounwind]
|
||||
pub fn round_ties_even_f32(x: f32) -> f32;
|
||||
|
||||
/// Provided for compatibility with stdarch. DO NOT USE.
|
||||
#[inline(always)]
|
||||
pub unsafe fn rintf32(x: f32) -> f32 {
|
||||
round_ties_even_f32(x)
|
||||
}
|
||||
|
||||
/// Returns the nearest integer to an `f64`. Rounds half-way cases to the number with an even
|
||||
/// least significant digit.
|
||||
///
|
||||
|
|
@ -2311,12 +2305,6 @@ pub unsafe fn rintf32(x: f32) -> f32 {
|
|||
#[rustc_nounwind]
|
||||
pub fn round_ties_even_f64(x: f64) -> f64;
|
||||
|
||||
/// Provided for compatibility with stdarch. DO NOT USE.
|
||||
#[inline(always)]
|
||||
pub unsafe fn rintf64(x: f64) -> f64 {
|
||||
round_ties_even_f64(x)
|
||||
}
|
||||
|
||||
/// Returns the nearest integer to an `f128`. Rounds half-way cases to the number with an even
|
||||
/// least significant digit.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -97,32 +97,32 @@ use super::TrustedLen;
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_on_unimplemented(
|
||||
on(
|
||||
_Self = "&[{A}]",
|
||||
Self = "&[{A}]",
|
||||
message = "a slice of type `{Self}` cannot be built since we need to store the elements somewhere",
|
||||
label = "try explicitly collecting into a `Vec<{A}>`",
|
||||
),
|
||||
on(
|
||||
all(A = "{integer}", any(_Self = "&[{integral}]",)),
|
||||
all(A = "{integer}", any(Self = "&[{integral}]",)),
|
||||
message = "a slice of type `{Self}` cannot be built since we need to store the elements somewhere",
|
||||
label = "try explicitly collecting into a `Vec<{A}>`",
|
||||
),
|
||||
on(
|
||||
_Self = "[{A}]",
|
||||
Self = "[{A}]",
|
||||
message = "a slice of type `{Self}` cannot be built since `{Self}` has no definite size",
|
||||
label = "try explicitly collecting into a `Vec<{A}>`",
|
||||
),
|
||||
on(
|
||||
all(A = "{integer}", any(_Self = "[{integral}]",)),
|
||||
all(A = "{integer}", any(Self = "[{integral}]",)),
|
||||
message = "a slice of type `{Self}` cannot be built since `{Self}` has no definite size",
|
||||
label = "try explicitly collecting into a `Vec<{A}>`",
|
||||
),
|
||||
on(
|
||||
_Self = "[{A}; _]",
|
||||
Self = "[{A}; _]",
|
||||
message = "an array of type `{Self}` cannot be built directly from an iterator",
|
||||
label = "try collecting into a `Vec<{A}>`, then using `.try_into()`",
|
||||
),
|
||||
on(
|
||||
all(A = "{integer}", any(_Self = "[{integral}; _]",)),
|
||||
all(A = "{integer}", any(Self = "[{integral}; _]",)),
|
||||
message = "an array of type `{Self}` cannot be built directly from an iterator",
|
||||
label = "try collecting into a `Vec<{A}>`, then using `.try_into()`",
|
||||
),
|
||||
|
|
@ -239,41 +239,38 @@ pub trait FromIterator<A>: Sized {
|
|||
#[rustc_diagnostic_item = "IntoIterator"]
|
||||
#[rustc_on_unimplemented(
|
||||
on(
|
||||
_Self = "core::ops::range::RangeTo<Idx>",
|
||||
Self = "core::ops::range::RangeTo<Idx>",
|
||||
label = "if you meant to iterate until a value, add a starting value",
|
||||
note = "`..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a \
|
||||
bounded `Range`: `0..end`"
|
||||
),
|
||||
on(
|
||||
_Self = "core::ops::range::RangeToInclusive<Idx>",
|
||||
Self = "core::ops::range::RangeToInclusive<Idx>",
|
||||
label = "if you meant to iterate until a value (including it), add a starting value",
|
||||
note = "`..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant \
|
||||
to have a bounded `RangeInclusive`: `0..=end`"
|
||||
),
|
||||
on(
|
||||
_Self = "[]",
|
||||
Self = "[]",
|
||||
label = "`{Self}` is not an iterator; try calling `.into_iter()` or `.iter()`"
|
||||
),
|
||||
on(_Self = "&[]", label = "`{Self}` is not an iterator; try calling `.iter()`"),
|
||||
on(Self = "&[]", label = "`{Self}` is not an iterator; try calling `.iter()`"),
|
||||
on(
|
||||
_Self = "alloc::vec::Vec<T, A>",
|
||||
Self = "alloc::vec::Vec<T, A>",
|
||||
label = "`{Self}` is not an iterator; try calling `.into_iter()` or `.iter()`"
|
||||
),
|
||||
on(Self = "&str", label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"),
|
||||
on(
|
||||
_Self = "&str",
|
||||
Self = "alloc::string::String",
|
||||
label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
|
||||
),
|
||||
on(
|
||||
_Self = "alloc::string::String",
|
||||
label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
|
||||
),
|
||||
on(
|
||||
_Self = "{integral}",
|
||||
Self = "{integral}",
|
||||
note = "if you want to iterate between `start` until a value `end`, use the exclusive range \
|
||||
syntax `start..end` or the inclusive range syntax `start..=end`"
|
||||
),
|
||||
on(
|
||||
_Self = "{float}",
|
||||
Self = "{float}",
|
||||
note = "if you want to iterate between `start` until a value `end`, use the exclusive range \
|
||||
syntax `start..end` or the inclusive range syntax `start..=end`"
|
||||
),
|
||||
|
|
|
|||
|
|
@ -22,11 +22,11 @@ fn _assert_is_dyn_compatible(_: &dyn Iterator<Item = ()>) {}
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_on_unimplemented(
|
||||
on(
|
||||
_Self = "core::ops::range::RangeTo<Idx>",
|
||||
Self = "core::ops::range::RangeTo<Idx>",
|
||||
note = "you might have meant to use a bounded `Range`"
|
||||
),
|
||||
on(
|
||||
_Self = "core::ops::range::RangeToInclusive<Idx>",
|
||||
Self = "core::ops::range::RangeToInclusive<Idx>",
|
||||
note = "you might have meant to use a bounded `RangeInclusive`"
|
||||
),
|
||||
label = "`{Self}` is not an iterator",
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue