summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_analysis
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:58 +0000
commita4b7ed7a42c716ab9f05e351f003d589124fd55d (patch)
treeb620cd3f223850b28716e474e80c58059dca5dd4 /compiler/rustc_hir_analysis
parentAdding upstream version 1.67.1+dfsg1. (diff)
downloadrustc-a4b7ed7a42c716ab9f05e351f003d589124fd55d.tar.xz
rustc-a4b7ed7a42c716ab9f05e351f003d589124fd55d.zip
Adding upstream version 1.68.2+dfsg1.upstream/1.68.2+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_hir_analysis')
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/errors.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/generics.rs1134
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs458
-rw-r--r--compiler/rustc_hir_analysis/src/autoderef.rs224
-rw-r--r--compiler/rustc_hir_analysis/src/bounds.rs93
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs124
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs (renamed from compiler/rustc_hir_analysis/src/check/compare_method.rs)615
-rw-r--r--compiler/rustc_hir_analysis/src/check/dropck.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsicck.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs38
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs40
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs162
-rw-r--r--compiler/rustc_hir_analysis/src/check_unused.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs144
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/mod.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs45
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/unsafety.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs1033
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs30
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs24
-rw-r--r--compiler/rustc_hir_analysis/src/collect/lifetimes.rs82
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs117
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs54
-rw-r--r--compiler/rustc_hir_analysis/src/constrained_generic_params.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs30
-rw-r--r--compiler/rustc_hir_analysis/src/hir_wf_check.rs46
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs29
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs12
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/utils.rs30
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs26
-rw-r--r--compiler/rustc_hir_analysis/src/variance/constraints.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/variance/mod.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/variance/solve.rs21
-rw-r--r--compiler/rustc_hir_analysis/src/variance/test.rs5
39 files changed, 2291 insertions, 2418 deletions
diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs
index e6465d641..232ef2079 100644
--- a/compiler/rustc_hir_analysis/src/astconv/errors.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs
@@ -267,7 +267,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// segments, even though `trait_ref.path.segments` is of length `1`. Work
// around that bug here, even though it should be fixed elsewhere.
// This would otherwise cause an invalid suggestion. For an example, look at
- // `src/test/ui/issues/issue-28344.rs` where instead of the following:
+ // `tests/ui/issues/issue-28344.rs` where instead of the following:
//
// error[E0191]: the value of the associated type `Output`
// (from trait `std::ops::BitXor`) must be specified
@@ -331,7 +331,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
if potential_assoc_types.len() == assoc_items.len() {
// When the amount of missing associated types equals the number of
- // extra type arguments present. A suggesting to replace the generic args with
+ // extra type arguments present. A suggesting to replace the generic args with
// associated types is already emitted.
already_has_generics_args_suggestion = true;
} else if let (Ok(snippet), false) =
diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs
index f64d65cc6..7a499327d 100644
--- a/compiler/rustc_hir_analysis/src/astconv/generics.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs
@@ -1,6 +1,6 @@
use super::IsMethodCall;
use crate::astconv::{
- AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
+ CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
GenericArgCountResult, GenericArgPosition,
};
use crate::errors::AssocTypeBindingNotAllowed;
@@ -18,642 +18,624 @@ use rustc_session::lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS;
use rustc_span::{symbol::kw, Span};
use smallvec::SmallVec;
-impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
- /// Report an error that a generic argument did not match the generic parameter that was
- /// expected.
- fn generic_arg_mismatch_err(
- tcx: TyCtxt<'_>,
- arg: &GenericArg<'_>,
- param: &GenericParamDef,
- possible_ordering_error: bool,
- help: Option<&str>,
- ) {
- let sess = tcx.sess;
- let mut err = struct_span_err!(
- sess,
- arg.span(),
- E0747,
- "{} provided when a {} was expected",
- arg.descr(),
- param.kind.descr(),
- );
-
- if let GenericParamDefKind::Const { .. } = param.kind {
- if matches!(arg, GenericArg::Type(hir::Ty { kind: hir::TyKind::Infer, .. })) {
- err.help("const arguments cannot yet be inferred with `_`");
- if sess.is_nightly_build() {
- err.help(
- "add `#![feature(generic_arg_infer)]` to the crate attributes to enable",
- );
- }
+/// Report an error that a generic argument did not match the generic parameter that was
+/// expected.
+fn generic_arg_mismatch_err(
+ tcx: TyCtxt<'_>,
+ arg: &GenericArg<'_>,
+ param: &GenericParamDef,
+ possible_ordering_error: bool,
+ help: Option<&str>,
+) {
+ let sess = tcx.sess;
+ let mut err = struct_span_err!(
+ sess,
+ arg.span(),
+ E0747,
+ "{} provided when a {} was expected",
+ arg.descr(),
+ param.kind.descr(),
+ );
+
+ if let GenericParamDefKind::Const { .. } = param.kind {
+ if matches!(arg, GenericArg::Type(hir::Ty { kind: hir::TyKind::Infer, .. })) {
+ err.help("const arguments cannot yet be inferred with `_`");
+ if sess.is_nightly_build() {
+ err.help("add `#![feature(generic_arg_infer)]` to the crate attributes to enable");
}
}
+ }
- let add_braces_suggestion = |arg: &GenericArg<'_>, err: &mut Diagnostic| {
- let suggestions = vec![
- (arg.span().shrink_to_lo(), String::from("{ ")),
- (arg.span().shrink_to_hi(), String::from(" }")),
- ];
- err.multipart_suggestion(
- "if this generic argument was intended as a const parameter, \
+ let add_braces_suggestion = |arg: &GenericArg<'_>, err: &mut Diagnostic| {
+ let suggestions = vec![
+ (arg.span().shrink_to_lo(), String::from("{ ")),
+ (arg.span().shrink_to_hi(), String::from(" }")),
+ ];
+ err.multipart_suggestion(
+ "if this generic argument was intended as a const parameter, \
surround it with braces",
- suggestions,
- Applicability::MaybeIncorrect,
- );
- };
-
- // Specific suggestion set for diagnostics
- match (arg, &param.kind) {
- (
- GenericArg::Type(hir::Ty {
- kind: hir::TyKind::Path(rustc_hir::QPath::Resolved(_, path)),
- ..
- }),
- GenericParamDefKind::Const { .. },
- ) => match path.res {
- Res::Err => {
- add_braces_suggestion(arg, &mut err);
- err.set_primary_message(
- "unresolved item provided when a constant was expected",
- )
+ suggestions,
+ Applicability::MaybeIncorrect,
+ );
+ };
+
+ // Specific suggestion set for diagnostics
+ match (arg, &param.kind) {
+ (
+ GenericArg::Type(hir::Ty {
+ kind: hir::TyKind::Path(rustc_hir::QPath::Resolved(_, path)),
+ ..
+ }),
+ GenericParamDefKind::Const { .. },
+ ) => match path.res {
+ Res::Err => {
+ add_braces_suggestion(arg, &mut err);
+ err.set_primary_message("unresolved item provided when a constant was expected")
.emit();
- return;
- }
- Res::Def(DefKind::TyParam, src_def_id) => {
- if let Some(param_local_id) = param.def_id.as_local() {
- let param_name = tcx.hir().ty_param_name(param_local_id);
- let param_type = tcx.type_of(param.def_id);
- if param_type.is_suggestable(tcx, false) {
- err.span_suggestion(
- tcx.def_span(src_def_id),
- "consider changing this type parameter to be a `const` generic",
- format!("const {}: {}", param_name, param_type),
- Applicability::MaybeIncorrect,
- );
- };
- }
- }
- _ => add_braces_suggestion(arg, &mut err),
- },
- (
- GenericArg::Type(hir::Ty { kind: hir::TyKind::Path(_), .. }),
- GenericParamDefKind::Const { .. },
- ) => add_braces_suggestion(arg, &mut err),
- (
- GenericArg::Type(hir::Ty { kind: hir::TyKind::Array(_, len), .. }),
- GenericParamDefKind::Const { .. },
- ) if tcx.type_of(param.def_id) == tcx.types.usize => {
- let snippet = sess.source_map().span_to_snippet(tcx.hir().span(len.hir_id()));
- if let Ok(snippet) = snippet {
- err.span_suggestion(
- arg.span(),
- "array type provided where a `usize` was expected, try",
- format!("{{ {} }}", snippet),
- Applicability::MaybeIncorrect,
- );
+ return;
+ }
+ Res::Def(DefKind::TyParam, src_def_id) => {
+ if let Some(param_local_id) = param.def_id.as_local() {
+ let param_name = tcx.hir().ty_param_name(param_local_id);
+ let param_type = tcx.type_of(param.def_id);
+ if param_type.is_suggestable(tcx, false) {
+ err.span_suggestion(
+ tcx.def_span(src_def_id),
+ "consider changing this type parameter to be a `const` generic",
+ format!("const {}: {}", param_name, param_type),
+ Applicability::MaybeIncorrect,
+ );
+ };
}
}
- (GenericArg::Const(cnst), GenericParamDefKind::Type { .. }) => {
- let body = tcx.hir().body(cnst.value.body);
- if let rustc_hir::ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) =
- body.value.kind
- {
- if let Res::Def(DefKind::Fn { .. }, id) = path.res {
- err.help(&format!(
- "`{}` is a function item, not a type",
- tcx.item_name(id)
- ));
- err.help("function item types cannot be named directly");
- }
+ _ => add_braces_suggestion(arg, &mut err),
+ },
+ (
+ GenericArg::Type(hir::Ty { kind: hir::TyKind::Path(_), .. }),
+ GenericParamDefKind::Const { .. },
+ ) => add_braces_suggestion(arg, &mut err),
+ (
+ GenericArg::Type(hir::Ty { kind: hir::TyKind::Array(_, len), .. }),
+ GenericParamDefKind::Const { .. },
+ ) if tcx.type_of(param.def_id) == tcx.types.usize => {
+ let snippet = sess.source_map().span_to_snippet(tcx.hir().span(len.hir_id()));
+ if let Ok(snippet) = snippet {
+ err.span_suggestion(
+ arg.span(),
+ "array type provided where a `usize` was expected, try",
+ format!("{{ {} }}", snippet),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ (GenericArg::Const(cnst), GenericParamDefKind::Type { .. }) => {
+ let body = tcx.hir().body(cnst.value.body);
+ if let rustc_hir::ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body.value.kind
+ {
+ if let Res::Def(DefKind::Fn { .. }, id) = path.res {
+ err.help(&format!("`{}` is a function item, not a type", tcx.item_name(id)));
+ err.help("function item types cannot be named directly");
}
}
- _ => {}
}
+ _ => {}
+ }
- let kind_ord = param.kind.to_ord();
- let arg_ord = arg.to_ord();
+ let kind_ord = param.kind.to_ord();
+ let arg_ord = arg.to_ord();
- // This note is only true when generic parameters are strictly ordered by their kind.
- if possible_ordering_error && kind_ord.cmp(&arg_ord) != core::cmp::Ordering::Equal {
- let (first, last) = if kind_ord < arg_ord {
- (param.kind.descr(), arg.descr())
- } else {
- (arg.descr(), param.kind.descr())
- };
- err.note(&format!("{} arguments must be provided before {} arguments", first, last));
- if let Some(help) = help {
- err.help(help);
- }
+ // This note is only true when generic parameters are strictly ordered by their kind.
+ if possible_ordering_error && kind_ord.cmp(&arg_ord) != core::cmp::Ordering::Equal {
+ let (first, last) = if kind_ord < arg_ord {
+ (param.kind.descr(), arg.descr())
+ } else {
+ (arg.descr(), param.kind.descr())
+ };
+ err.note(&format!("{} arguments must be provided before {} arguments", first, last));
+ if let Some(help) = help {
+ err.help(help);
}
+ }
+
+ err.emit();
+}
- err.emit();
+/// Creates the relevant generic argument substitutions
+/// corresponding to a set of generic parameters. This is a
+/// rather complex function. Let us try to explain the role
+/// of each of its parameters:
+///
+/// To start, we are given the `def_id` of the thing we are
+/// creating the substitutions for, and a partial set of
+/// substitutions `parent_substs`. In general, the substitutions
+/// for an item begin with substitutions for all the "parents" of
+/// that item -- e.g., for a method it might include the
+/// parameters from the impl.
+///
+/// Therefore, the method begins by walking down these parents,
+/// starting with the outermost parent and proceed inwards until
+/// it reaches `def_id`. For each parent `P`, it will check `parent_substs`
+/// first to see if the parent's substitutions are listed in there. If so,
+/// we can append those and move on. Otherwise, it invokes the
+/// three callback functions:
+///
+/// - `args_for_def_id`: given the `DefId` `P`, supplies back the
+/// generic arguments that were given to that parent from within
+/// the path; so e.g., if you have `<T as Foo>::Bar`, the `DefId`
+/// might refer to the trait `Foo`, and the arguments might be
+/// `[T]`. The boolean value indicates whether to infer values
+/// for arguments whose values were not explicitly provided.
+/// - `provided_kind`: given the generic parameter and the value from `args_for_def_id`,
+/// instantiate a `GenericArg`.
+/// - `inferred_kind`: if no parameter was provided, and inference is enabled, then
+/// creates a suitable inference variable.
+pub fn create_substs_for_generic_args<'tcx, 'a>(
+ tcx: TyCtxt<'tcx>,
+ def_id: DefId,
+ parent_substs: &[subst::GenericArg<'tcx>],
+ has_self: bool,
+ self_ty: Option<Ty<'tcx>>,
+ arg_count: &GenericArgCountResult,
+ ctx: &mut impl CreateSubstsForGenericArgsCtxt<'a, 'tcx>,
+) -> SubstsRef<'tcx> {
+ // Collect the segments of the path; we need to substitute arguments
+ // for parameters throughout the entire path (wherever there are
+ // generic parameters).
+ let mut parent_defs = tcx.generics_of(def_id);
+ let count = parent_defs.count();
+ let mut stack = vec![(def_id, parent_defs)];
+ while let Some(def_id) = parent_defs.parent {
+ parent_defs = tcx.generics_of(def_id);
+ stack.push((def_id, parent_defs));
}
- /// Creates the relevant generic argument substitutions
- /// corresponding to a set of generic parameters. This is a
- /// rather complex function. Let us try to explain the role
- /// of each of its parameters:
- ///
- /// To start, we are given the `def_id` of the thing we are
- /// creating the substitutions for, and a partial set of
- /// substitutions `parent_substs`. In general, the substitutions
- /// for an item begin with substitutions for all the "parents" of
- /// that item -- e.g., for a method it might include the
- /// parameters from the impl.
- ///
- /// Therefore, the method begins by walking down these parents,
- /// starting with the outermost parent and proceed inwards until
- /// it reaches `def_id`. For each parent `P`, it will check `parent_substs`
- /// first to see if the parent's substitutions are listed in there. If so,
- /// we can append those and move on. Otherwise, it invokes the
- /// three callback functions:
- ///
- /// - `args_for_def_id`: given the `DefId` `P`, supplies back the
- /// generic arguments that were given to that parent from within
- /// the path; so e.g., if you have `<T as Foo>::Bar`, the `DefId`
- /// might refer to the trait `Foo`, and the arguments might be
- /// `[T]`. The boolean value indicates whether to infer values
- /// for arguments whose values were not explicitly provided.
- /// - `provided_kind`: given the generic parameter and the value from `args_for_def_id`,
- /// instantiate a `GenericArg`.
- /// - `inferred_kind`: if no parameter was provided, and inference is enabled, then
- /// creates a suitable inference variable.
- pub fn create_substs_for_generic_args<'a>(
- tcx: TyCtxt<'tcx>,
- def_id: DefId,
- parent_substs: &[subst::GenericArg<'tcx>],
- has_self: bool,
- self_ty: Option<Ty<'tcx>>,
- arg_count: &GenericArgCountResult,
- ctx: &mut impl CreateSubstsForGenericArgsCtxt<'a, 'tcx>,
- ) -> SubstsRef<'tcx> {
- // Collect the segments of the path; we need to substitute arguments
- // for parameters throughout the entire path (wherever there are
- // generic parameters).
- let mut parent_defs = tcx.generics_of(def_id);
- let count = parent_defs.count();
- let mut stack = vec![(def_id, parent_defs)];
- while let Some(def_id) = parent_defs.parent {
- parent_defs = tcx.generics_of(def_id);
- stack.push((def_id, parent_defs));
+ // We manually build up the substitution, rather than using convenience
+ // methods in `subst.rs`, so that we can iterate over the arguments and
+ // parameters in lock-step linearly, instead of trying to match each pair.
+ let mut substs: SmallVec<[subst::GenericArg<'tcx>; 8]> = SmallVec::with_capacity(count);
+ // Iterate over each segment of the path.
+ while let Some((def_id, defs)) = stack.pop() {
+ let mut params = defs.params.iter().peekable();
+
+ // If we have already computed substitutions for parents, we can use those directly.
+ while let Some(&param) = params.peek() {
+ if let Some(&kind) = parent_substs.get(param.index as usize) {
+ substs.push(kind);
+ params.next();
+ } else {
+ break;
+ }
}
- // We manually build up the substitution, rather than using convenience
- // methods in `subst.rs`, so that we can iterate over the arguments and
- // parameters in lock-step linearly, instead of trying to match each pair.
- let mut substs: SmallVec<[subst::GenericArg<'tcx>; 8]> = SmallVec::with_capacity(count);
- // Iterate over each segment of the path.
- while let Some((def_id, defs)) = stack.pop() {
- let mut params = defs.params.iter().peekable();
-
- // If we have already computed substitutions for parents, we can use those directly.
- while let Some(&param) = params.peek() {
- if let Some(&kind) = parent_substs.get(param.index as usize) {
- substs.push(kind);
- params.next();
- } else {
- break;
+ // `Self` is handled first, unless it's been handled in `parent_substs`.
+ if has_self {
+ if let Some(&param) = params.peek() {
+ if param.index == 0 {
+ if let GenericParamDefKind::Type { .. } = param.kind {
+ substs.push(
+ self_ty
+ .map(|ty| ty.into())
+ .unwrap_or_else(|| ctx.inferred_kind(None, param, true)),
+ );
+ params.next();
+ }
}
}
+ }
- // `Self` is handled first, unless it's been handled in `parent_substs`.
- if has_self {
- if let Some(&param) = params.peek() {
- if param.index == 0 {
- if let GenericParamDefKind::Type { .. } = param.kind {
- substs.push(
- self_ty
- .map(|ty| ty.into())
- .unwrap_or_else(|| ctx.inferred_kind(None, param, true)),
- );
+ // Check whether this segment takes generic arguments and the user has provided any.
+ let (generic_args, infer_args) = ctx.args_for_def_id(def_id);
+
+ let args_iter = generic_args.iter().flat_map(|generic_args| generic_args.args.iter());
+ let mut args = args_iter.clone().peekable();
+
+ // If we encounter a type or const when we expect a lifetime, we infer the lifetimes.
+ // If we later encounter a lifetime, we know that the arguments were provided in the
+ // wrong order. `force_infer_lt` records the type or const that forced lifetimes to be
+ // inferred, so we can use it for diagnostics later.
+ let mut force_infer_lt = None;
+
+ loop {
+ // We're going to iterate through the generic arguments that the user
+ // provided, matching them with the generic parameters we expect.
+ // Mismatches can occur as a result of elided lifetimes, or for malformed
+ // input. We try to handle both sensibly.
+ match (args.peek(), params.peek()) {
+ (Some(&arg), Some(&param)) => {
+ match (arg, &param.kind, arg_count.explicit_late_bound) {
+ (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime, _)
+ | (
+ GenericArg::Type(_) | GenericArg::Infer(_),
+ GenericParamDefKind::Type { .. },
+ _,
+ )
+ | (
+ GenericArg::Const(_) | GenericArg::Infer(_),
+ GenericParamDefKind::Const { .. },
+ _,
+ ) => {
+ substs.push(ctx.provided_kind(param, arg));
+ args.next();
params.next();
}
- }
- }
- }
-
- // Check whether this segment takes generic arguments and the user has provided any.
- let (generic_args, infer_args) = ctx.args_for_def_id(def_id);
-
- let args_iter = generic_args.iter().flat_map(|generic_args| generic_args.args.iter());
- let mut args = args_iter.clone().peekable();
-
- // If we encounter a type or const when we expect a lifetime, we infer the lifetimes.
- // If we later encounter a lifetime, we know that the arguments were provided in the
- // wrong order. `force_infer_lt` records the type or const that forced lifetimes to be
- // inferred, so we can use it for diagnostics later.
- let mut force_infer_lt = None;
-
- loop {
- // We're going to iterate through the generic arguments that the user
- // provided, matching them with the generic parameters we expect.
- // Mismatches can occur as a result of elided lifetimes, or for malformed
- // input. We try to handle both sensibly.
- match (args.peek(), params.peek()) {
- (Some(&arg), Some(&param)) => {
- match (arg, &param.kind, arg_count.explicit_late_bound) {
- (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime, _)
- | (
- GenericArg::Type(_) | GenericArg::Infer(_),
- GenericParamDefKind::Type { .. },
- _,
- )
- | (
- GenericArg::Const(_) | GenericArg::Infer(_),
- GenericParamDefKind::Const { .. },
- _,
- ) => {
- substs.push(ctx.provided_kind(param, arg));
- args.next();
- params.next();
- }
- (
- GenericArg::Infer(_) | GenericArg::Type(_) | GenericArg::Const(_),
- GenericParamDefKind::Lifetime,
- _,
- ) => {
- // We expected a lifetime argument, but got a type or const
- // argument. That means we're inferring the lifetimes.
- substs.push(ctx.inferred_kind(None, param, infer_args));
- force_infer_lt = Some((arg, param));
- params.next();
- }
- (GenericArg::Lifetime(_), _, ExplicitLateBound::Yes) => {
- // We've come across a lifetime when we expected something else in
- // the presence of explicit late bounds. This is most likely
- // due to the presence of the explicit bound so we're just going to
- // ignore it.
- args.next();
- }
- (_, _, _) => {
- // We expected one kind of parameter, but the user provided
- // another. This is an error. However, if we already know that
- // the arguments don't match up with the parameters, we won't issue
- // an additional error, as the user already knows what's wrong.
- if arg_count.correct.is_ok() {
- // We're going to iterate over the parameters to sort them out, and
- // show that order to the user as a possible order for the parameters
- let mut param_types_present = defs
- .params
- .iter()
- .map(|param| (param.kind.to_ord(), param.clone()))
- .collect::<Vec<(ParamKindOrd, GenericParamDef)>>();
- param_types_present.sort_by_key(|(ord, _)| *ord);
- let (mut param_types_present, ordered_params): (
- Vec<ParamKindOrd>,
- Vec<GenericParamDef>,
- ) = param_types_present.into_iter().unzip();
- param_types_present.dedup();
-
- Self::generic_arg_mismatch_err(
- tcx,
- arg,
- param,
- !args_iter.clone().is_sorted_by_key(|arg| arg.to_ord()),
- Some(&format!(
- "reorder the arguments: {}: `<{}>`",
- param_types_present
- .into_iter()
- .map(|ord| format!("{}s", ord))
- .collect::<Vec<String>>()
- .join(", then "),
- ordered_params
- .into_iter()
- .filter_map(|param| {
- if param.name == kw::SelfUpper {
- None
- } else {
- Some(param.name.to_string())
- }
- })
- .collect::<Vec<String>>()
- .join(", ")
- )),
- );
- }
-
- // We've reported the error, but we want to make sure that this
- // problem doesn't bubble down and create additional, irrelevant
- // errors. In this case, we're simply going to ignore the argument
- // and any following arguments. The rest of the parameters will be
- // inferred.
- while args.next().is_some() {}
- }
+ (
+ GenericArg::Infer(_) | GenericArg::Type(_) | GenericArg::Const(_),
+ GenericParamDefKind::Lifetime,
+ _,
+ ) => {
+ // We expected a lifetime argument, but got a type or const
+ // argument. That means we're inferring the lifetimes.
+ substs.push(ctx.inferred_kind(None, param, infer_args));
+ force_infer_lt = Some((arg, param));
+ params.next();
}
- }
-
- (Some(&arg), None) => {
- // We should never be able to reach this point with well-formed input.
- // There are three situations in which we can encounter this issue.
- //
- // 1. The number of arguments is incorrect. In this case, an error
- // will already have been emitted, and we can ignore it.
- // 2. There are late-bound lifetime parameters present, yet the
- // lifetime arguments have also been explicitly specified by the
- // user.
- // 3. We've inferred some lifetimes, which have been provided later (i.e.
- // after a type or const). We want to throw an error in this case.
-
- if arg_count.correct.is_ok()
- && arg_count.explicit_late_bound == ExplicitLateBound::No
- {
- let kind = arg.descr();
- assert_eq!(kind, "lifetime");
- let (provided_arg, param) =
- force_infer_lt.expect("lifetimes ought to have been inferred");
- Self::generic_arg_mismatch_err(tcx, provided_arg, param, false, None);
+ (GenericArg::Lifetime(_), _, ExplicitLateBound::Yes) => {
+ // We've come across a lifetime when we expected something else in
+ // the presence of explicit late bounds. This is most likely
+ // due to the presence of the explicit bound so we're just going to
+ // ignore it.
+ args.next();
}
+ (_, _, _) => {
+ // We expected one kind of parameter, but the user provided
+ // another. This is an error. However, if we already know that
+ // the arguments don't match up with the parameters, we won't issue
+ // an additional error, as the user already knows what's wrong.
+ if arg_count.correct.is_ok() {
+ // We're going to iterate over the parameters to sort them out, and
+ // show that order to the user as a possible order for the parameters
+ let mut param_types_present = defs
+ .params
+ .iter()
+ .map(|param| (param.kind.to_ord(), param.clone()))
+ .collect::<Vec<(ParamKindOrd, GenericParamDef)>>();
+ param_types_present.sort_by_key(|(ord, _)| *ord);
+ let (mut param_types_present, ordered_params): (
+ Vec<ParamKindOrd>,
+ Vec<GenericParamDef>,
+ ) = param_types_present.into_iter().unzip();
+ param_types_present.dedup();
+
+ generic_arg_mismatch_err(
+ tcx,
+ arg,
+ param,
+ !args_iter.clone().is_sorted_by_key(|arg| arg.to_ord()),
+ Some(&format!(
+ "reorder the arguments: {}: `<{}>`",
+ param_types_present
+ .into_iter()
+ .map(|ord| format!("{}s", ord))
+ .collect::<Vec<String>>()
+ .join(", then "),
+ ordered_params
+ .into_iter()
+ .filter_map(|param| {
+ if param.name == kw::SelfUpper {
+ None
+ } else {
+ Some(param.name.to_string())
+ }
+ })
+ .collect::<Vec<String>>()
+ .join(", ")
+ )),
+ );
+ }
- break;
+ // We've reported the error, but we want to make sure that this
+ // problem doesn't bubble down and create additional, irrelevant
+ // errors. In this case, we're simply going to ignore the argument
+ // and any following arguments. The rest of the parameters will be
+ // inferred.
+ while args.next().is_some() {}
+ }
}
+ }
- (None, Some(&param)) => {
- // If there are fewer arguments than parameters, it means
- // we're inferring the remaining arguments.
- substs.push(ctx.inferred_kind(Some(&substs), param, infer_args));
- params.next();
+ (Some(&arg), None) => {
+ // We should never be able to reach this point with well-formed input.
+ // There are three situations in which we can encounter this issue.
+ //
+ // 1. The number of arguments is incorrect. In this case, an error
+ // will already have been emitted, and we can ignore it.
+ // 2. There are late-bound lifetime parameters present, yet the
+ // lifetime arguments have also been explicitly specified by the
+ // user.
+ // 3. We've inferred some lifetimes, which have been provided later (i.e.
+ // after a type or const). We want to throw an error in this case.
+
+ if arg_count.correct.is_ok()
+ && arg_count.explicit_late_bound == ExplicitLateBound::No
+ {
+ let kind = arg.descr();
+ assert_eq!(kind, "lifetime");
+ let (provided_arg, param) =
+ force_infer_lt.expect("lifetimes ought to have been inferred");
+ generic_arg_mismatch_err(tcx, provided_arg, param, false, None);
}
- (None, None) => break,
+ break;
+ }
+
+ (None, Some(&param)) => {
+ // If there are fewer arguments than parameters, it means
+ // we're inferring the remaining arguments.
+ substs.push(ctx.inferred_kind(Some(&substs), param, infer_args));
+ params.next();
}
+
+ (None, None) => break,
}
}
-
- tcx.intern_substs(&substs)
}
- /// Checks that the correct number of generic arguments have been provided.
- /// Used specifically for function calls.
- pub fn check_generic_arg_count_for_call(
- tcx: TyCtxt<'_>,
- span: Span,
- def_id: DefId,
- generics: &ty::Generics,
- seg: &hir::PathSegment<'_>,
- is_method_call: IsMethodCall,
- ) -> GenericArgCountResult {
- let empty_args = hir::GenericArgs::none();
- let gen_args = seg.args.unwrap_or(&empty_args);
- let gen_pos = if is_method_call == IsMethodCall::Yes {
- GenericArgPosition::MethodCall
+ tcx.intern_substs(&substs)
+}
+
+/// Checks that the correct number of generic arguments have been provided.
+/// Used specifically for function calls.
+pub fn check_generic_arg_count_for_call(
+ tcx: TyCtxt<'_>,
+ span: Span,
+ def_id: DefId,
+ generics: &ty::Generics,
+ seg: &hir::PathSegment<'_>,
+ is_method_call: IsMethodCall,
+) -> GenericArgCountResult {
+ let empty_args = hir::GenericArgs::none();
+ let gen_args = seg.args.unwrap_or(&empty_args);
+ let gen_pos = if is_method_call == IsMethodCall::Yes {
+ GenericArgPosition::MethodCall
+ } else {
+ GenericArgPosition::Value
+ };
+ let has_self = generics.parent.is_none() && generics.has_self;
+
+ check_generic_arg_count(
+ tcx,
+ span,
+ def_id,
+ seg,
+ generics,
+ gen_args,
+ gen_pos,
+ has_self,
+ seg.infer_args,
+ )
+}
+
+/// Checks that the correct number of generic arguments have been provided.
+/// This is used both for datatypes and function calls.
+#[instrument(skip(tcx, gen_pos), level = "debug")]
+pub(crate) fn check_generic_arg_count(
+ tcx: TyCtxt<'_>,
+ span: Span,
+ def_id: DefId,
+ seg: &hir::PathSegment<'_>,
+ gen_params: &ty::Generics,
+ gen_args: &hir::GenericArgs<'_>,
+ gen_pos: GenericArgPosition,
+ has_self: bool,
+ infer_args: bool,
+) -> GenericArgCountResult {
+ let default_counts = gen_params.own_defaults();
+ let param_counts = gen_params.own_counts();
+
+ // Subtracting from param count to ensure type params synthesized from `impl Trait`
+ // cannot be explicitly specified.
+ let synth_type_param_count = gen_params
+ .params
+ .iter()
+ .filter(|param| matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: true, .. }))
+ .count();
+ let named_type_param_count = param_counts.types - has_self as usize - synth_type_param_count;
+ let infer_lifetimes =
+ (gen_pos != GenericArgPosition::Type || infer_args) && !gen_args.has_lifetime_params();
+
+ if gen_pos != GenericArgPosition::Type && let Some(b) = gen_args.bindings.first() {
+ prohibit_assoc_ty_binding(tcx, b.span);
+ }
+
+ let explicit_late_bound =
+ prohibit_explicit_late_bound_lifetimes(tcx, gen_params, gen_args, gen_pos);
+
+ let mut invalid_args = vec![];
+
+ let mut check_lifetime_args = |min_expected_args: usize,
+ max_expected_args: usize,
+ provided_args: usize,
+ late_bounds_ignore: bool| {
+ if (min_expected_args..=max_expected_args).contains(&provided_args) {
+ return Ok(());
+ }
+
+ if late_bounds_ignore {
+ return Ok(());
+ }
+
+ if provided_args > max_expected_args {
+ invalid_args.extend(
+ gen_args.args[max_expected_args..provided_args].iter().map(|arg| arg.span()),
+ );
+ };
+
+ let gen_args_info = if provided_args > min_expected_args {
+ invalid_args.extend(
+ gen_args.args[min_expected_args..provided_args].iter().map(|arg| arg.span()),
+ );
+ let num_redundant_args = provided_args - min_expected_args;
+ GenericArgsInfo::ExcessLifetimes { num_redundant_args }
} else {
- GenericArgPosition::Value
+ let num_missing_args = min_expected_args - provided_args;
+ GenericArgsInfo::MissingLifetimes { num_missing_args }
};
- let has_self = generics.parent.is_none() && generics.has_self;
- Self::check_generic_arg_count(
+ let reported = WrongNumberOfGenericArgs::new(
tcx,
- span,
- def_id,
+ gen_args_info,
seg,
- generics,
+ gen_params,
+ has_self as usize,
gen_args,
- gen_pos,
- has_self,
- seg.infer_args,
+ def_id,
)
- }
-
- /// Checks that the correct number of generic arguments have been provided.
- /// This is used both for datatypes and function calls.
- #[instrument(skip(tcx, gen_pos), level = "debug")]
- pub(crate) fn check_generic_arg_count(
- tcx: TyCtxt<'_>,
- span: Span,
- def_id: DefId,
- seg: &hir::PathSegment<'_>,
- gen_params: &ty::Generics,
- gen_args: &hir::GenericArgs<'_>,
- gen_pos: GenericArgPosition,
- has_self: bool,
- infer_args: bool,
- ) -> GenericArgCountResult {
- let default_counts = gen_params.own_defaults();
- let param_counts = gen_params.own_counts();
-
- // Subtracting from param count to ensure type params synthesized from `impl Trait`
- // cannot be explicitly specified.
- let synth_type_param_count = gen_params
- .params
- .iter()
- .filter(|param| {
- matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: true, .. })
- })
- .count();
- let named_type_param_count =
- param_counts.types - has_self as usize - synth_type_param_count;
- let infer_lifetimes =
- (gen_pos != GenericArgPosition::Type || infer_args) && !gen_args.has_lifetime_params();
-
- if gen_pos != GenericArgPosition::Type && let Some(b) = gen_args.bindings.first() {
- Self::prohibit_assoc_ty_binding(tcx, b.span);
+ .diagnostic()
+ .emit();
+
+ Err(reported)
+ };
+
+ let min_expected_lifetime_args = if infer_lifetimes { 0 } else { param_counts.lifetimes };
+ let max_expected_lifetime_args = param_counts.lifetimes;
+ let num_provided_lifetime_args = gen_args.num_lifetime_params();
+
+ let lifetimes_correct = check_lifetime_args(
+ min_expected_lifetime_args,
+ max_expected_lifetime_args,
+ num_provided_lifetime_args,
+ explicit_late_bound == ExplicitLateBound::Yes,
+ );
+
+ let mut check_types_and_consts = |expected_min,
+ expected_max,
+ expected_max_with_synth,
+ provided,
+ params_offset,
+ args_offset| {
+ debug!(
+ ?expected_min,
+ ?expected_max,
+ ?provided,
+ ?params_offset,
+ ?args_offset,
+ "check_types_and_consts"
+ );
+ if (expected_min..=expected_max).contains(&provided) {
+ return Ok(());
}
- let explicit_late_bound =
- Self::prohibit_explicit_late_bound_lifetimes(tcx, gen_params, gen_args, gen_pos);
-
- let mut invalid_args = vec![];
+ let num_default_params = expected_max - expected_min;
- let mut check_lifetime_args =
- |min_expected_args: usize,
- max_expected_args: usize,
- provided_args: usize,
- late_bounds_ignore: bool| {
- if (min_expected_args..=max_expected_args).contains(&provided_args) {
- return Ok(());
- }
-
- if late_bounds_ignore {
- return Ok(());
- }
+ let gen_args_info = if provided > expected_max {
+ invalid_args.extend(
+ gen_args.args[args_offset + expected_max..args_offset + provided]
+ .iter()
+ .map(|arg| arg.span()),
+ );
+ let num_redundant_args = provided - expected_max;
- if provided_args > max_expected_args {
- invalid_args.extend(
- gen_args.args[max_expected_args..provided_args]
- .iter()
- .map(|arg| arg.span()),
- );
- };
-
- let gen_args_info = if provided_args > min_expected_args {
- invalid_args.extend(
- gen_args.args[min_expected_args..provided_args]
- .iter()
- .map(|arg| arg.span()),
- );
- let num_redundant_args = provided_args - min_expected_args;
- GenericArgsInfo::ExcessLifetimes { num_redundant_args }
- } else {
- let num_missing_args = min_expected_args - provided_args;
- GenericArgsInfo::MissingLifetimes { num_missing_args }
- };
-
- let reported = WrongNumberOfGenericArgs::new(
- tcx,
- gen_args_info,
- seg,
- gen_params,
- has_self as usize,
- gen_args,
- def_id,
- )
- .diagnostic()
- .emit();
-
- Err(reported)
- };
-
- let min_expected_lifetime_args = if infer_lifetimes { 0 } else { param_counts.lifetimes };
- let max_expected_lifetime_args = param_counts.lifetimes;
- let num_provided_lifetime_args = gen_args.num_lifetime_params();
-
- let lifetimes_correct = check_lifetime_args(
- min_expected_lifetime_args,
- max_expected_lifetime_args,
- num_provided_lifetime_args,
- explicit_late_bound == ExplicitLateBound::Yes,
- );
+ // Provide extra note if synthetic arguments like `impl Trait` are specified.
+ let synth_provided = provided <= expected_max_with_synth;
- let mut check_types_and_consts = |expected_min,
- expected_max,
- expected_max_with_synth,
- provided,
- params_offset,
- args_offset| {
- debug!(
- ?expected_min,
- ?expected_max,
- ?provided,
- ?params_offset,
- ?args_offset,
- "check_types_and_consts"
- );
- if (expected_min..=expected_max).contains(&provided) {
- return Ok(());
+ GenericArgsInfo::ExcessTypesOrConsts {
+ num_redundant_args,
+ num_default_params,
+ args_offset,
+ synth_provided,
}
+ } else {
+ let num_missing_args = expected_max - provided;
- let num_default_params = expected_max - expected_min;
-
- let gen_args_info = if provided > expected_max {
- invalid_args.extend(
- gen_args.args[args_offset + expected_max..args_offset + provided]
- .iter()
- .map(|arg| arg.span()),
- );
- let num_redundant_args = provided - expected_max;
+ GenericArgsInfo::MissingTypesOrConsts {
+ num_missing_args,
+ num_default_params,
+ args_offset,
+ }
+ };
- // Provide extra note if synthetic arguments like `impl Trait` are specified.
- let synth_provided = provided <= expected_max_with_synth;
+ debug!(?gen_args_info);
- GenericArgsInfo::ExcessTypesOrConsts {
- num_redundant_args,
- num_default_params,
- args_offset,
- synth_provided,
- }
- } else {
- let num_missing_args = expected_max - provided;
+ let reported = WrongNumberOfGenericArgs::new(
+ tcx,
+ gen_args_info,
+ seg,
+ gen_params,
+ params_offset,
+ gen_args,
+ def_id,
+ )
+ .diagnostic()
+ .emit_unless(gen_args.has_err());
- GenericArgsInfo::MissingTypesOrConsts {
- num_missing_args,
- num_default_params,
- args_offset,
- }
- };
-
- debug!(?gen_args_info);
-
- let reported = WrongNumberOfGenericArgs::new(
- tcx,
- gen_args_info,
- seg,
- gen_params,
- params_offset,
- gen_args,
- def_id,
- )
- .diagnostic()
- .emit_unless(gen_args.has_err());
-
- Err(reported)
- };
+ Err(reported)
+ };
- let args_correct = {
- let expected_min = if infer_args {
- 0
- } else {
- param_counts.consts + named_type_param_count
- - default_counts.types
- - default_counts.consts
- };
- debug!(?expected_min);
- debug!(arg_counts.lifetimes=?gen_args.num_lifetime_params());
-
- check_types_and_consts(
- expected_min,
- param_counts.consts + named_type_param_count,
- param_counts.consts + named_type_param_count + synth_type_param_count,
- gen_args.num_generic_params(),
- param_counts.lifetimes + has_self as usize,
- gen_args.num_lifetime_params(),
- )
+ let args_correct = {
+ let expected_min = if infer_args {
+ 0
+ } else {
+ param_counts.consts + named_type_param_count
+ - default_counts.types
+ - default_counts.consts
};
+ debug!(?expected_min);
+ debug!(arg_counts.lifetimes=?gen_args.num_lifetime_params());
+
+ check_types_and_consts(
+ expected_min,
+ param_counts.consts + named_type_param_count,
+ param_counts.consts + named_type_param_count + synth_type_param_count,
+ gen_args.num_generic_params(),
+ param_counts.lifetimes + has_self as usize,
+ gen_args.num_lifetime_params(),
+ )
+ };
- GenericArgCountResult {
- explicit_late_bound,
- correct: lifetimes_correct.and(args_correct).map_err(|reported| {
- GenericArgCountMismatch { reported: Some(reported), invalid_args }
- }),
- }
+ GenericArgCountResult {
+ explicit_late_bound,
+ correct: lifetimes_correct
+ .and(args_correct)
+ .map_err(|reported| GenericArgCountMismatch { reported: Some(reported), invalid_args }),
}
+}
- /// Emits an error regarding forbidden type binding associations
- pub fn prohibit_assoc_ty_binding(tcx: TyCtxt<'_>, span: Span) {
- tcx.sess.emit_err(AssocTypeBindingNotAllowed { span });
- }
+/// Emits an error regarding forbidden type binding associations
+pub fn prohibit_assoc_ty_binding(tcx: TyCtxt<'_>, span: Span) {
+ tcx.sess.emit_err(AssocTypeBindingNotAllowed { span });
+}
- /// Prohibits explicit lifetime arguments if late-bound lifetime parameters
- /// are present. This is used both for datatypes and function calls.
- pub(crate) fn prohibit_explicit_late_bound_lifetimes(
- tcx: TyCtxt<'_>,
- def: &ty::Generics,
- args: &hir::GenericArgs<'_>,
- position: GenericArgPosition,
- ) -> ExplicitLateBound {
- let param_counts = def.own_counts();
- let infer_lifetimes = position != GenericArgPosition::Type && !args.has_lifetime_params();
-
- if infer_lifetimes {
- return ExplicitLateBound::No;
- }
+/// Prohibits explicit lifetime arguments if late-bound lifetime parameters
+/// are present. This is used both for datatypes and function calls.
+pub(crate) fn prohibit_explicit_late_bound_lifetimes(
+ tcx: TyCtxt<'_>,
+ def: &ty::Generics,
+ args: &hir::GenericArgs<'_>,
+ position: GenericArgPosition,
+) -> ExplicitLateBound {
+ let param_counts = def.own_counts();
+ let infer_lifetimes = position != GenericArgPosition::Type && !args.has_lifetime_params();
+
+ if infer_lifetimes {
+ return ExplicitLateBound::No;
+ }
- if let Some(span_late) = def.has_late_bound_regions {
- let msg = "cannot specify lifetime arguments explicitly \
+ if let Some(span_late) = def.has_late_bound_regions {
+ let msg = "cannot specify lifetime arguments explicitly \
if late bound lifetime parameters are present";
- let note = "the late bound lifetime parameter is introduced here";
- let span = args.args[0].span();
-
- if position == GenericArgPosition::Value
- && args.num_lifetime_params() != param_counts.lifetimes
- {
- let mut err = tcx.sess.struct_span_err(span, msg);
- err.span_note(span_late, note);
- err.emit();
- } else {
- let mut multispan = MultiSpan::from_span(span);
- multispan.push_span_label(span_late, note);
- tcx.struct_span_lint_hir(
- LATE_BOUND_LIFETIME_ARGUMENTS,
- args.args[0].hir_id(),
- multispan,
- msg,
- |lint| lint,
- );
- }
-
- ExplicitLateBound::Yes
+ let note = "the late bound lifetime parameter is introduced here";
+ let span = args.args[0].span();
+
+ if position == GenericArgPosition::Value
+ && args.num_lifetime_params() != param_counts.lifetimes
+ {
+ let mut err = tcx.sess.struct_span_err(span, msg);
+ err.span_note(span_late, note);
+ err.emit();
} else {
- ExplicitLateBound::No
+ let mut multispan = MultiSpan::from_span(span);
+ multispan.push_span_label(span_late, note);
+ tcx.struct_span_lint_hir(
+ LATE_BOUND_LIFETIME_ARGUMENTS,
+ args.args[0].hir_id(),
+ multispan,
+ msg,
+ |lint| lint,
+ );
}
+
+ ExplicitLateBound::Yes
+ } else {
+ ExplicitLateBound::No
}
}
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 78d204d47..6435b05ce 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -3,8 +3,11 @@
//! instance of `AstConv`.
mod errors;
-mod generics;
+pub mod generics;
+use crate::astconv::generics::{
+ check_generic_arg_count, create_substs_for_generic_args, prohibit_assoc_ty_binding,
+};
use crate::bounds::Bounds;
use crate::collect::HirPlaceholderCollector;
use crate::errors::{
@@ -24,13 +27,12 @@ use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{walk_generics, Visitor as _};
use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
+use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::middle::stability::AllowUnstable;
use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
-use rustc_middle::ty::DynKind;
use rustc_middle::ty::GenericParamDefKind;
-use rustc_middle::ty::{
- self, Const, DefIdTree, EarlyBinder, IsSuggestable, Ty, TyCtxt, TypeVisitable,
-};
+use rustc_middle::ty::{self, Const, DefIdTree, IsSuggestable, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::{DynKind, EarlyBinder};
use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
use rustc_span::edition::Edition;
use rustc_span::lev_distance::find_best_match_for_name;
@@ -108,11 +110,12 @@ pub trait AstConv<'tcx> {
poly_trait_ref: ty::PolyTraitRef<'tcx>,
) -> Ty<'tcx>;
- /// Normalize an associated type coming from the user.
- ///
- /// This should only be used by astconv. Use `FnCtxt::normalize`
- /// or `ObligationCtxt::normalize` in downstream crates.
- fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx>;
+ /// Returns `AdtDef` if `ty` is an ADT.
+ /// Note that `ty` might be a projection type that needs normalization.
+ /// This used to get the enum variants in scope of the type.
+ /// For example, `Self::A` could refer to an associated type
+ /// or to an enum variant depending on the result of this function.
+ fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>>;
/// Invoked when we encounter an error from some prior pass
/// (e.g., resolve) that is translated into a ty-error. This is
@@ -121,6 +124,13 @@ pub trait AstConv<'tcx> {
fn set_tainted_by_errors(&self, e: ErrorGuaranteed);
fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span);
+
+ fn astconv(&self) -> &dyn AstConv<'tcx>
+ where
+ Self: Sized,
+ {
+ self
+ }
}
#[derive(Debug)]
@@ -280,7 +290,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
ty::BoundConstness::NotConst,
);
if let Some(b) = item_segment.args().bindings.first() {
- Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
+ prohibit_assoc_ty_binding(self.tcx(), b.span);
}
substs
@@ -350,7 +360,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
assert!(self_ty.is_none());
}
- let arg_count = Self::check_generic_arg_count(
+ let arg_count = check_generic_arg_count(
tcx,
span,
def_id,
@@ -487,13 +497,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// Avoid ICE #86756 when type error recovery goes awry.
return tcx.ty_error().into();
}
- self.astconv
- .normalize_ty(
- self.span,
- EarlyBinder(tcx.at(self.span).type_of(param.def_id))
- .subst(tcx, substs),
- )
- .into()
+ tcx.at(self.span).bound_type_of(param.def_id).subst(tcx, substs).into()
} else if infer_args {
self.astconv.ty_infer(Some(param), self.span).into()
} else {
@@ -507,9 +511,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
return tcx.const_error(ty).into();
}
if !infer_args && has_default {
- tcx.bound_const_param_default(param.def_id)
- .subst(tcx, substs.unwrap())
- .into()
+ tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into()
} else {
if infer_args {
self.astconv.ct_infer(ty, Some(param), self.span).into()
@@ -531,7 +533,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
inferred_params: vec![],
infer_args,
};
- let substs = Self::create_substs_for_generic_args(
+ let substs = create_substs_for_generic_args(
tcx,
def_id,
parent_substs,
@@ -567,17 +569,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.bindings
.iter()
.map(|binding| {
- let kind = match binding.kind {
- hir::TypeBindingKind::Equality { ref term } => match term {
- hir::Term::Ty(ref ty) => {
+ let kind = match &binding.kind {
+ hir::TypeBindingKind::Equality { term } => match term {
+ hir::Term::Ty(ty) => {
ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty).into())
}
- hir::Term::Const(ref c) => {
+ hir::Term::Const(c) => {
let c = Const::from_anon_const(self.tcx(), c.def_id);
ConvertedBindingKind::Equality(c.into())
}
},
- hir::TypeBindingKind::Constraint { ref bounds } => {
+ hir::TypeBindingKind::Constraint { bounds } => {
ConvertedBindingKind::Constraint(bounds)
}
};
@@ -617,7 +619,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
);
if let Some(b) = item_segment.args().bindings.first() {
- Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
+ prohibit_assoc_ty_binding(self.tcx(), b.span);
}
args
@@ -680,10 +682,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let assoc_bindings = self.create_assoc_bindings_for_generic_args(args);
let poly_trait_ref =
- ty::Binder::bind_with_vars(ty::TraitRef::new(trait_def_id, substs), bound_vars);
+ ty::Binder::bind_with_vars(tcx.mk_trait_ref(trait_def_id, substs), bound_vars);
debug!(?poly_trait_ref, ?assoc_bindings);
- bounds.trait_bounds.push((poly_trait_ref, span, constness));
+ bounds.push_trait_bound(tcx, poly_trait_ref, span, constness);
let mut dup_bindings = FxHashMap::default();
for binding in &assoc_bindings {
@@ -811,9 +813,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
constness,
);
if let Some(b) = trait_segment.args().bindings.first() {
- Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
+ prohibit_assoc_ty_binding(self.tcx(), b.span);
}
- ty::TraitRef::new(trait_def_id, substs)
+ self.tcx().mk_trait_ref(trait_def_id, substs)
}
#[instrument(level = "debug", skip(self, span))]
@@ -854,18 +856,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
/// Sets `implicitly_sized` to true on `Bounds` if necessary
- pub(crate) fn add_implicitly_sized<'hir>(
+ pub(crate) fn add_implicitly_sized(
&self,
- bounds: &mut Bounds<'hir>,
- ast_bounds: &'hir [hir::GenericBound<'hir>],
- self_ty_where_predicates: Option<(LocalDefId, &'hir [hir::WherePredicate<'hir>])>,
+ bounds: &mut Bounds<'tcx>,
+ self_ty: Ty<'tcx>,
+ ast_bounds: &'tcx [hir::GenericBound<'tcx>],
+ self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
span: Span,
) {
let tcx = self.tcx();
// Try to find an unbound in bounds.
let mut unbound = None;
- let mut search_bounds = |ast_bounds: &'hir [hir::GenericBound<'hir>]| {
+ let mut search_bounds = |ast_bounds: &'tcx [hir::GenericBound<'tcx>]| {
for ab in ast_bounds {
if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab {
if unbound.is_none() {
@@ -913,7 +916,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// No lang item for `Sized`, so we can't add it as a bound.
return;
}
- bounds.implicitly_sized = Some(span);
+ bounds.push_sized(tcx, self_ty, span);
}
/// This helper takes a *converted* parameter type (`param_ty`)
@@ -964,10 +967,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
hir::GenericBound::Outlives(lifetime) => {
let region = self.ast_region_to_region(lifetime, None);
- bounds.region_bounds.push((
- ty::Binder::bind_with_vars(region, bound_vars),
+ bounds.push_region_bound(
+ self.tcx(),
+ ty::Binder::bind_with_vars(
+ ty::OutlivesPredicate(param_ty, region),
+ bound_vars,
+ ),
lifetime.ident.span,
- ));
+ );
}
}
}
@@ -985,7 +992,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
/// ```
///
/// The `sized_by_default` parameter indicates if, in this context, the `param_ty` should be
- /// considered `Sized` unless there is an explicit `?Sized` bound. This would be true in the
+ /// considered `Sized` unless there is an explicit `?Sized` bound. This would be true in the
/// example above, but is not true in supertrait listings like `trait Foo: Bar + Baz`.
///
/// `span` should be the declaration size of the parameter.
@@ -1146,10 +1153,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
debug!(?substs_trait_ref_and_assoc_item);
- ty::ProjectionTy {
- item_def_id: assoc_item.def_id,
- substs: substs_trait_ref_and_assoc_item,
- }
+ self.tcx().mk_alias_ty(assoc_item.def_id, substs_trait_ref_and_assoc_item)
});
if !speculative {
@@ -1195,7 +1199,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// the "projection predicate" for:
//
// `<T as Iterator>::Item = u32`
- let assoc_item_def_id = projection_ty.skip_binder().item_def_id;
+ let assoc_item_def_id = projection_ty.skip_binder().def_id;
let def_kind = tcx.def_kind(assoc_item_def_id);
match (def_kind, term.unpack()) {
(hir::def::DefKind::AssocTy, ty::TermKind::Ty(_))
@@ -1203,17 +1207,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
(_, _) => {
let got = if let Some(_) = term.ty() { "type" } else { "constant" };
let expected = def_kind.descr(assoc_item_def_id);
- let reported = tcx
- .sess
- .struct_span_err(
+ let mut err = tcx.sess.struct_span_err(
+ binding.span,
+ &format!("expected {expected} bound, found {got}"),
+ );
+ err.span_note(
+ tcx.def_span(assoc_item_def_id),
+ &format!("{expected} defined here"),
+ );
+
+ if let hir::def::DefKind::AssocConst = def_kind
+ && let Some(t) = term.ty() && (t.is_enum() || t.references_error())
+ && tcx.features().associated_const_equality {
+ err.span_suggestion(
binding.span,
- &format!("expected {expected} bound, found {got}"),
- )
- .span_note(
- tcx.def_span(assoc_item_def_id),
- &format!("{expected} defined here"),
- )
- .emit();
+ "if equating a const, try wrapping with braces",
+ format!("{} = {{ const }}", binding.item_name),
+ Applicability::HasPlaceholders,
+ );
+ }
+ let reported = err.emit();
term = match def_kind {
hir::def::DefKind::AssocTy => {
tcx.ty_error_with_guaranteed(reported).into()
@@ -1229,13 +1242,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
};
}
}
- bounds.projection_bounds.push((
- projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate {
- projection_ty,
- term: term,
- }),
+ bounds.push_projection_bound(
+ tcx,
+ projection_ty
+ .map_bound(|projection_ty| ty::ProjectionPredicate { projection_ty, term }),
binding.span,
- ));
+ );
}
ConvertedBindingKind::Constraint(ast_bounds) => {
// "Desugar" a constraint like `T: Iterator<Item: Debug>` to
@@ -1244,7 +1256,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
//
// Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty`
// parameter to have a skipped binder.
- let param_ty = tcx.mk_ty(ty::Projection(projection_ty.skip_binder()));
+ let param_ty = tcx.mk_ty(ty::Alias(ty::Projection, projection_ty.skip_binder()));
self.add_bounds(param_ty, ast_bounds.iter(), bounds, candidate.bound_vars());
}
}
@@ -1258,16 +1270,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
item_segment: &hir::PathSegment<'_>,
) -> Ty<'tcx> {
let substs = self.ast_path_substs_for_ty(span, did, item_segment);
- self.normalize_ty(
- span,
- EarlyBinder(self.tcx().at(span).type_of(did)).subst(self.tcx(), substs),
- )
+ self.tcx().at(span).bound_type_of(did).subst(self.tcx(), substs)
}
fn conv_object_ty_poly_trait_ref(
&self,
span: Span,
- trait_bounds: &[hir::PolyTraitRef<'_>],
+ hir_trait_bounds: &[hir::PolyTraitRef<'_>],
lifetime: &hir::Lifetime,
borrowed: bool,
representation: DynKind,
@@ -1277,7 +1286,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let mut bounds = Bounds::default();
let mut potential_assoc_types = Vec::new();
let dummy_self = self.tcx().types.trait_object_dummy_self;
- for trait_bound in trait_bounds.iter().rev() {
+ for trait_bound in hir_trait_bounds.iter().rev() {
if let GenericArgCountResult {
correct:
Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }),
@@ -1294,10 +1303,45 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
}
+ let mut trait_bounds = vec![];
+ let mut projection_bounds = vec![];
+ for (pred, span) in bounds.predicates() {
+ let bound_pred = pred.kind();
+ match bound_pred.skip_binder() {
+ ty::PredicateKind::Clause(clause) => match clause {
+ ty::Clause::Trait(trait_pred) => {
+ assert_eq!(trait_pred.polarity, ty::ImplPolarity::Positive);
+ trait_bounds.push((
+ bound_pred.rebind(trait_pred.trait_ref),
+ span,
+ trait_pred.constness,
+ ));
+ }
+ ty::Clause::Projection(proj) => {
+ projection_bounds.push((bound_pred.rebind(proj), span));
+ }
+ ty::Clause::TypeOutlives(_) => {
+ // Do nothing, we deal with regions separately
+ }
+ ty::Clause::RegionOutlives(_) => bug!(),
+ },
+ ty::PredicateKind::WellFormed(_)
+ | ty::PredicateKind::ObjectSafe(_)
+ | ty::PredicateKind::ClosureKind(_, _, _)
+ | ty::PredicateKind::Subtype(_)
+ | ty::PredicateKind::Coerce(_)
+ | ty::PredicateKind::ConstEvaluatable(_)
+ | ty::PredicateKind::ConstEquate(_, _)
+ | ty::PredicateKind::TypeWellFormedFromEnv(_)
+ | ty::PredicateKind::Ambiguous => bug!(),
+ }
+ }
+
// Expand trait aliases recursively and check that only one regular (non-auto) trait
// is used and no 'maybe' bounds are used.
let expanded_traits =
- traits::expand_trait_aliases(tcx, bounds.trait_bounds.iter().map(|&(a, b, _)| (a, b)));
+ traits::expand_trait_aliases(tcx, trait_bounds.iter().map(|&(a, b, _)| (a, b)));
+
let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = expanded_traits
.filter(|i| i.trait_ref().self_ty().skip_binder() == dummy_self)
.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
@@ -1334,8 +1378,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
if regular_traits.is_empty() && auto_traits.is_empty() {
- let trait_alias_span = bounds
- .trait_bounds
+ let trait_alias_span = trait_bounds
.iter()
.map(|&(trait_ref, _, _)| trait_ref.def_id())
.find(|&trait_ref| tcx.is_trait_alias(trait_ref))
@@ -1366,8 +1409,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// Use a `BTreeSet` to keep output in a more consistent order.
let mut associated_types: FxHashMap<Span, BTreeSet<DefId>> = FxHashMap::default();
- let regular_traits_refs_spans = bounds
- .trait_bounds
+ let regular_traits_refs_spans = trait_bounds
.into_iter()
.filter(|(trait_ref, _, _)| !tcx.trait_is_auto(trait_ref.def_id()));
@@ -1421,7 +1463,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// the discussion in #56288 for alternatives.
if !references_self {
// Include projections defined on supertraits.
- bounds.projection_bounds.push((pred, span));
+ projection_bounds.push((pred, span));
}
}
_ => (),
@@ -1429,7 +1471,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
}
- for (projection_bound, _) in &bounds.projection_bounds {
+ for (projection_bound, _) in &projection_bounds {
for def_ids in associated_types.values_mut() {
def_ids.remove(&projection_bound.projection_def_id());
}
@@ -1438,7 +1480,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self.complain_about_missing_associated_types(
associated_types,
potential_assoc_types,
- trait_bounds,
+ hir_trait_bounds,
);
// De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as
@@ -1455,7 +1497,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| {
assert_eq!(trait_ref.self_ty(), dummy_self);
- // Verify that `dummy_self` did not leak inside default type parameters. This
+ // Verify that `dummy_self` did not leak inside default type parameters. This
// could not be done at path creation, since we need to see through trait aliases.
let mut missing_type_params = vec![];
let mut references_self = false;
@@ -1480,7 +1522,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let substs = tcx.intern_substs(&substs[..]);
let span = i.bottom().1;
- let empty_generic_args = trait_bounds.iter().any(|hir_bound| {
+ let empty_generic_args = hir_trait_bounds.iter().any(|hir_bound| {
hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id)
&& hir_bound.span.contains(span)
});
@@ -1512,7 +1554,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
})
});
- let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| {
+ let existential_projections = projection_bounds.iter().map(|(bound, _)| {
bound.map_bound(|mut b| {
assert_eq!(b.projection_ty.self_ty(), dummy_self);
@@ -1600,8 +1642,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
fn report_ambiguous_associated_type(
&self,
span: Span,
- type_str: &str,
- trait_str: &str,
+ types: &[String],
+ traits: &[String],
name: Symbol,
) -> ErrorGuaranteed {
let mut err = struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type");
@@ -1612,19 +1654,92 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.keys()
.any(|full_span| full_span.contains(span))
{
- err.span_suggestion(
+ err.span_suggestion_verbose(
span.shrink_to_lo(),
"you are looking for the module in `std`, not the primitive type",
"std::",
Applicability::MachineApplicable,
);
} else {
- err.span_suggestion(
- span,
- "use fully-qualified syntax",
- format!("<{} as {}>::{}", type_str, trait_str, name),
- Applicability::HasPlaceholders,
- );
+ match (types, traits) {
+ ([], []) => {
+ err.span_suggestion_verbose(
+ span,
+ &format!(
+ "if there were a type named `Type` that implements a trait named \
+ `Trait` with associated type `{name}`, you could use the \
+ fully-qualified path",
+ ),
+ format!("<Type as Trait>::{name}"),
+ Applicability::HasPlaceholders,
+ );
+ }
+ ([], [trait_str]) => {
+ err.span_suggestion_verbose(
+ span,
+ &format!(
+ "if there were a type named `Example` that implemented `{trait_str}`, \
+ you could use the fully-qualified path",
+ ),
+ format!("<Example as {trait_str}>::{name}"),
+ Applicability::HasPlaceholders,
+ );
+ }
+ ([], traits) => {
+ err.span_suggestions(
+ span,
+ &format!(
+ "if there were a type named `Example` that implemented one of the \
+ traits with associated type `{name}`, you could use the \
+ fully-qualified path",
+ ),
+ traits
+ .iter()
+ .map(|trait_str| format!("<Example as {trait_str}>::{name}"))
+ .collect::<Vec<_>>(),
+ Applicability::HasPlaceholders,
+ );
+ }
+ ([type_str], []) => {
+ err.span_suggestion_verbose(
+ span,
+ &format!(
+ "if there were a trait named `Example` with associated type `{name}` \
+ implemented for `{type_str}`, you could use the fully-qualified path",
+ ),
+ format!("<{type_str} as Example>::{name}"),
+ Applicability::HasPlaceholders,
+ );
+ }
+ (types, []) => {
+ err.span_suggestions(
+ span,
+ &format!(
+ "if there were a trait named `Example` with associated type `{name}` \
+ implemented for one of the types, you could use the fully-qualified \
+ path",
+ ),
+ types
+ .into_iter()
+ .map(|type_str| format!("<{type_str} as Example>::{name}")),
+ Applicability::HasPlaceholders,
+ );
+ }
+ (types, traits) => {
+ let mut suggestions = vec![];
+ for type_str in types {
+ for trait_str in traits {
+ suggestions.push(format!("<{type_str} as {trait_str}>::{name}"));
+ }
+ }
+ err.span_suggestions(
+ span,
+ "use the fully-qualified path",
+ suggestions,
+ Applicability::MachineApplicable,
+ );
+ }
+ }
}
err.emit()
}
@@ -1793,7 +1908,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
Ok(bound)
}
- // Create a type from a path to an associated type.
+ // Create a type from a path to an associated type or to an enum variant.
// For a path `A::B::C::D`, `qself_ty` and `qself_def` are the type and def for `A::B::C`
// and item_segment is the path segment for `D`. We return a type and a def for
// the whole path.
@@ -1813,7 +1928,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
let tcx = self.tcx();
let assoc_ident = assoc_segment.ident;
- let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = qself.kind {
+ let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
path.res
} else {
Res::Err
@@ -1821,7 +1936,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// Check if we have an enum variant.
let mut variant_resolution = None;
- if let ty::Adt(adt_def, adt_substs) = qself_ty.kind() {
+ if let Some(adt_def) = self.probe_adt(span, qself_ty) {
if adt_def.is_enum() {
let variant_def = adt_def
.variants()
@@ -1856,8 +1971,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
return;
};
let (qself_sugg_span, is_self) = if let hir::TyKind::Path(
- hir::QPath::Resolved(_, ref path)
- ) = qself.kind {
+ hir::QPath::Resolved(_, path)
+ ) = &qself.kind {
// If the path segment already has type params, we want to overwrite
// them.
match &path.segments[..] {
@@ -1923,6 +2038,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let Some(assoc_ty_did) = self.lookup_assoc_ty(assoc_ident, hir_ref_id, span, impl_) else {
continue;
};
+ let ty::Adt(_, adt_substs) = qself_ty.kind() else {
+ // FIXME(inherent_associated_types)
+ bug!("unimplemented: non-adt self of inherent assoc ty");
+ };
let item_substs = self.create_substs_for_associated_item(
span,
assoc_ty_did,
@@ -1930,7 +2049,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
adt_substs,
);
let ty = tcx.bound_type_of(assoc_ty_did).subst(tcx, item_substs);
- let ty = self.normalize_ty(span, ty);
return Ok((ty, DefKind::AssocTy, assoc_ty_did));
}
}
@@ -1948,7 +2066,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
};
self.one_bound_for_assoc_type(
- || traits::supertraits(tcx, ty::Binder::dummy(trait_ref)),
+ || traits::supertraits(tcx, ty::Binder::dummy(trait_ref.subst_identity())),
|| "Self".to_string(),
assoc_ident,
span,
@@ -2004,12 +2122,64 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
err.emit()
} else if let Err(reported) = qself_ty.error_reported() {
reported
+ } else if let ty::Alias(ty::Opaque, alias_ty) = qself_ty.kind() {
+ // `<impl Trait as OtherTrait>::Assoc` makes no sense.
+ struct_span_err!(
+ tcx.sess,
+ tcx.def_span(alias_ty.def_id),
+ E0667,
+ "`impl Trait` is not allowed in path parameters"
+ )
+ .emit() // Already reported in an earlier stage.
} else {
+ // Find all the `impl`s that `qself_ty` has for any trait that has the
+ // associated type, so that we suggest the right one.
+ let infcx = tcx.infer_ctxt().build();
+ // We create a fresh `ty::ParamEnv` instead of the one for `self.item_def_id()`
+ // to avoid a cycle error in `src/test/ui/resolve/issue-102946.rs`.
+ let param_env = ty::ParamEnv::empty();
+ let traits: Vec<_> = self
+ .tcx()
+ .all_traits()
+ .filter(|trait_def_id| {
+ // Consider only traits with the associated type
+ tcx.associated_items(*trait_def_id)
+ .in_definition_order()
+ .any(|i| {
+ i.kind.namespace() == Namespace::TypeNS
+ && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
+ && matches!(i.kind, ty::AssocKind::Type)
+ })
+ // Consider only accessible traits
+ && tcx.visibility(*trait_def_id)
+ .is_accessible_from(self.item_def_id(), tcx)
+ && tcx.all_impls(*trait_def_id)
+ .any(|impl_def_id| {
+ let trait_ref = tcx.impl_trait_ref(impl_def_id);
+ trait_ref.map_or(false, |trait_ref| {
+ let impl_ = trait_ref.subst(
+ tcx,
+ infcx.fresh_substs_for_item(span, impl_def_id),
+ );
+ infcx
+ .can_eq(
+ param_env,
+ tcx.erase_regions(impl_.self_ty()),
+ tcx.erase_regions(qself_ty),
+ )
+ .is_ok()
+ })
+ && tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
+ })
+ })
+ .map(|trait_def_id| tcx.def_path_str(trait_def_id))
+ .collect();
+
// Don't print `TyErr` to the user.
self.report_ambiguous_associated_type(
span,
- &qself_ty.to_string(),
- "Trait",
+ &[qself_ty.to_string()],
+ &traits,
assoc_ident.name,
)
};
@@ -2027,7 +2197,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
};
let ty = self.projected_ty_from_poly_trait_ref(span, assoc_ty_did, assoc_segment, bound);
- let ty = self.normalize_ty(span, ty);
if let Some(variant_def_id) = variant_resolution {
tcx.struct_span_lint_hir(
@@ -2128,16 +2297,30 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let is_part_of_self_trait_constraints = def_id == trait_def_id;
let is_part_of_fn_in_self_trait = parent_def_id == Some(trait_def_id);
- let type_name = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
- "Self"
+ let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
+ vec!["Self".to_string()]
} else {
- "Type"
+ // Find all the types that have an `impl` for the trait.
+ tcx.all_impls(trait_def_id)
+ .filter(|impl_def_id| {
+ // Consider only accessible traits
+ tcx.visibility(*impl_def_id).is_accessible_from(self.item_def_id(), tcx)
+ && tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
+ })
+ .filter_map(|impl_def_id| tcx.impl_trait_ref(impl_def_id))
+ .map(|impl_| impl_.subst_identity().self_ty())
+ // We don't care about blanket impls.
+ .filter(|self_ty| !self_ty.has_non_region_param())
+ .map(|self_ty| tcx.erase_regions(self_ty).to_string())
+ .collect()
};
-
+ // FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that
+ // references the trait. Relevant for the first case in
+ // `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs`
let reported = self.report_ambiguous_associated_type(
span,
- type_name,
- &path_str,
+ &type_names,
+ &[path_str],
item_segment.ident.name,
);
return tcx.ty_error_with_guaranteed(reported)
@@ -2163,7 +2346,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
debug!("qpath_to_ty: trait_ref={:?}", trait_ref);
- self.normalize_ty(span, tcx.mk_projection(item_def_id, item_substs))
+ tcx.mk_projection(item_def_id, item_substs)
}
pub fn prohibit_generics<'a>(
@@ -2243,7 +2426,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
),
"s",
),
- [only] => (format!("{only}"), ""),
+ [only] => (only.to_string(), ""),
[] => unreachable!(),
};
let last_span = *arg_spans.last().unwrap();
@@ -2266,7 +2449,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
for segment in segments {
// Only emit the first error to avoid overloading the user with error messages.
if let Some(b) = segment.args().bindings.first() {
- Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
+ prohibit_assoc_ty_binding(self.tcx(), b.span);
return true;
}
}
@@ -2280,6 +2463,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self_ty: Option<Ty<'tcx>>,
kind: DefKind,
def_id: DefId,
+ span: Span,
) -> Vec<PathSeg> {
// We need to extract the type parameters supplied by the user in
// the path `path`. Due to the current setup, this is a bit of a
@@ -2347,8 +2531,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// Case 2. Reference to a variant constructor.
DefKind::Ctor(CtorOf::Variant, ..) | DefKind::Variant => {
- let adt_def = self_ty.map(|t| t.ty_adt_def().unwrap());
- let (generics_def_id, index) = if let Some(adt_def) = adt_def {
+ let (generics_def_id, index) = if let Some(self_ty) = self_ty {
+ let adt_def = self.probe_adt(span, self_ty).unwrap();
debug_assert!(adt_def.is_enum());
(adt_def.did(), last)
} else if last >= 1 && segments[last - 1].args.is_some() {
@@ -2424,7 +2608,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
err.note("`impl Trait` types can't have type parameters");
});
let substs = self.ast_path_substs_for_ty(span, did, item_segment.0);
- self.normalize_ty(span, tcx.mk_opaque(did, substs))
+ tcx.mk_opaque(did, substs)
}
Res::Def(
DefKind::Enum
@@ -2444,7 +2628,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
assert_eq!(opt_self_ty, None);
let path_segs =
- self.def_ids_for_value_path_segments(path.segments, None, kind, def_id);
+ self.def_ids_for_value_path_segments(path.segments, None, kind, def_id, span);
let generic_segs: FxHashSet<_> =
path_segs.iter().map(|PathSeg(_, index)| index).collect();
self.prohibit_generics(
@@ -2576,7 +2760,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
"generic `Self` types are currently not permitted in anonymous constants",
);
if let Some(hir::Node::Item(&hir::Item {
- kind: hir::ItemKind::Impl(ref impl_),
+ kind: hir::ItemKind::Impl(impl_),
..
})) = tcx.hir().get_if_local(def_id)
{
@@ -2584,7 +2768,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
tcx.ty_error_with_guaranteed(err.emit())
} else {
- self.normalize_ty(span, ty)
+ ty
}
}
Res::Def(DefKind::AssocTy, def_id) => {
@@ -2633,7 +2817,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let e = self
.tcx()
.sess
- .delay_span_bug(path.span, "path with `Res:Err` but no error emitted");
+ .delay_span_bug(path.span, "path with `Res::Err` but no error emitted");
self.set_tainted_by_errors(e);
self.tcx().ty_error_with_guaranteed(e)
}
@@ -2648,7 +2832,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
/// Parses the programmer's textual representation of a type into our
- /// internal notion of a type. This is meant to be used within a path.
+ /// internal notion of a type. This is meant to be used within a path.
pub fn ast_ty_to_ty_in_path(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
self.ast_ty_to_ty_inner(ast_ty, false, true)
}
@@ -2659,12 +2843,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool) -> Ty<'tcx> {
let tcx = self.tcx();
- let result_ty = match ast_ty.kind {
- hir::TyKind::Slice(ref ty) => tcx.mk_slice(self.ast_ty_to_ty(ty)),
- hir::TyKind::Ptr(ref mt) => {
+ let result_ty = match &ast_ty.kind {
+ hir::TyKind::Slice(ty) => tcx.mk_slice(self.ast_ty_to_ty(ty)),
+ hir::TyKind::Ptr(mt) => {
tcx.mk_ptr(ty::TypeAndMut { ty: self.ast_ty_to_ty(mt.ty), mutbl: mt.mutbl })
}
- hir::TyKind::Rptr(ref region, ref mt) => {
+ hir::TyKind::Ref(region, mt) => {
let r = self.ast_region_to_region(region, None);
debug!(?r);
let t = self.ast_ty_to_ty_inner(mt.ty, true, false);
@@ -2684,7 +2868,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
Some(ast_ty),
))
}
- hir::TyKind::TraitObject(bounds, ref lifetime, repr) => {
+ hir::TyKind::TraitObject(bounds, lifetime, repr) => {
self.maybe_lint_bare_trait(ast_ty, in_path);
let repr = match repr {
TraitObjectSyntax::Dyn | TraitObjectSyntax::None => ty::Dyn,
@@ -2692,12 +2876,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
};
self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed, repr)
}
- hir::TyKind::Path(hir::QPath::Resolved(ref maybe_qself, ref path)) => {
+ hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
debug!(?maybe_qself, ?path);
let opt_self_ty = maybe_qself.as_ref().map(|qself| self.ast_ty_to_ty(qself));
self.res_to_ty(opt_self_ty, path, false)
}
- hir::TyKind::OpaqueDef(item_id, lifetimes, in_trait) => {
+ &hir::TyKind::OpaqueDef(item_id, lifetimes, in_trait) => {
let opaque_ty = tcx.hir().item(item_id);
let def_id = item_id.owner_id.to_def_id();
@@ -2708,14 +2892,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
}
}
- hir::TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => {
+ hir::TyKind::Path(hir::QPath::TypeRelative(qself, segment)) => {
debug!(?qself, ?segment);
let ty = self.ast_ty_to_ty_inner(qself, false, true);
self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, qself, segment, false)
.map(|(ty, _, _)| ty)
.unwrap_or_else(|_| tcx.ty_error())
}
- hir::TyKind::Path(hir::QPath::LangItem(lang_item, span, _)) => {
+ &hir::TyKind::Path(hir::QPath::LangItem(lang_item, span, _)) => {
let def_id = tcx.require_lang_item(lang_item, Some(span));
let (substs, _) = self.create_substs_for_ast_path(
span,
@@ -2727,10 +2911,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
None,
ty::BoundConstness::NotConst,
);
- EarlyBinder(self.normalize_ty(span, tcx.at(span).type_of(def_id)))
- .subst(tcx, substs)
+ EarlyBinder(tcx.at(span).type_of(def_id)).subst(tcx, substs)
}
- hir::TyKind::Array(ref ty, ref length) => {
+ hir::TyKind::Array(ty, length) => {
let length = match length {
&hir::ArrayLen::Infer(_, span) => self.ct_infer(tcx.types.usize, None, span),
hir::ArrayLen::Body(constant) => {
@@ -2738,10 +2921,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
};
- let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(ty), length));
- self.normalize_ty(ast_ty.span, array_ty)
+ tcx.mk_ty(ty::Array(self.ast_ty_to_ty(ty), length))
}
- hir::TyKind::Typeof(ref e) => {
+ hir::TyKind::Typeof(e) => {
let ty_erased = tcx.type_of(e.def_id);
let ty = tcx.fold_regions(ty_erased, |r, _| {
if r.is_erased() { tcx.lifetimes.re_static } else { r }
@@ -2943,7 +3125,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), ident, .. }) =
hir.get(fn_hir_id) else { return None };
let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(i), .. }) =
- hir.get(hir.get_parent_node(fn_hir_id)) else { bug!("ImplItem should have Impl parent") };
+ hir.get_parent(fn_hir_id) else { bug!("ImplItem should have Impl parent") };
let trait_ref = self.instantiate_mono_trait_ref(
i.of_trait.as_ref()?,
@@ -3123,7 +3305,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let label = "add `dyn` keyword before this trait";
let mut diag =
rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg);
- diag.multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable);
+ if self_ty.span.can_be_used_for_suggestions() {
+ diag.multipart_suggestion_verbose(
+ label,
+ sugg,
+ Applicability::MachineApplicable,
+ );
+ }
// check if the impl trait that we are considering is a impl of a local trait
self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
diag.emit();
diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs
new file mode 100644
index 000000000..730560cc6
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/autoderef.rs
@@ -0,0 +1,224 @@
+use crate::errors::AutoDerefReachedRecursionLimit;
+use crate::traits::query::evaluate_obligation::InferCtxtExt;
+use crate::traits::NormalizeExt;
+use crate::traits::{self, TraitEngine, TraitEngineExt};
+use rustc_hir as hir;
+use rustc_infer::infer::InferCtxt;
+use rustc_middle::ty::TypeVisitable;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_session::Limit;
+use rustc_span::def_id::LOCAL_CRATE;
+use rustc_span::Span;
+
+#[derive(Copy, Clone, Debug)]
+pub enum AutoderefKind {
+ Builtin,
+ Overloaded,
+}
+
+struct AutoderefSnapshot<'tcx> {
+ at_start: bool,
+ reached_recursion_limit: bool,
+ steps: Vec<(Ty<'tcx>, AutoderefKind)>,
+ cur_ty: Ty<'tcx>,
+ obligations: Vec<traits::PredicateObligation<'tcx>>,
+}
+
+pub struct Autoderef<'a, 'tcx> {
+ // Meta infos:
+ infcx: &'a InferCtxt<'tcx>,
+ span: Span,
+ body_id: hir::HirId,
+ param_env: ty::ParamEnv<'tcx>,
+
+ // Current state:
+ state: AutoderefSnapshot<'tcx>,
+
+ // Configurations:
+ include_raw_pointers: bool,
+ silence_errors: bool,
+}
+
+impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
+ type Item = (Ty<'tcx>, usize);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let tcx = self.infcx.tcx;
+
+ debug!("autoderef: steps={:?}, cur_ty={:?}", self.state.steps, self.state.cur_ty);
+ if self.state.at_start {
+ self.state.at_start = false;
+ debug!("autoderef stage #0 is {:?}", self.state.cur_ty);
+ return Some((self.state.cur_ty, 0));
+ }
+
+ // If we have reached the recursion limit, error gracefully.
+ if !tcx.recursion_limit().value_within_limit(self.state.steps.len()) {
+ if !self.silence_errors {
+ report_autoderef_recursion_limit_error(tcx, self.span, self.state.cur_ty);
+ }
+ self.state.reached_recursion_limit = true;
+ return None;
+ }
+
+ if self.state.cur_ty.is_ty_var() {
+ return None;
+ }
+
+ // Otherwise, deref if type is derefable:
+ let (kind, new_ty) =
+ if let Some(mt) = self.state.cur_ty.builtin_deref(self.include_raw_pointers) {
+ (AutoderefKind::Builtin, mt.ty)
+ } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) {
+ (AutoderefKind::Overloaded, ty)
+ } else {
+ return None;
+ };
+
+ if new_ty.references_error() {
+ return None;
+ }
+
+ self.state.steps.push((self.state.cur_ty, kind));
+ debug!(
+ "autoderef stage #{:?} is {:?} from {:?}",
+ self.step_count(),
+ new_ty,
+ (self.state.cur_ty, kind)
+ );
+ self.state.cur_ty = new_ty;
+
+ Some((self.state.cur_ty, self.step_count()))
+ }
+}
+
+impl<'a, 'tcx> Autoderef<'a, 'tcx> {
+ pub fn new(
+ infcx: &'a InferCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ body_id: hir::HirId,
+ span: Span,
+ base_ty: Ty<'tcx>,
+ ) -> Autoderef<'a, 'tcx> {
+ Autoderef {
+ infcx,
+ span,
+ body_id,
+ param_env,
+ state: AutoderefSnapshot {
+ steps: vec![],
+ cur_ty: infcx.resolve_vars_if_possible(base_ty),
+ obligations: vec![],
+ at_start: true,
+ reached_recursion_limit: false,
+ },
+ include_raw_pointers: false,
+ silence_errors: false,
+ }
+ }
+
+ fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
+ debug!("overloaded_deref_ty({:?})", ty);
+
+ let tcx = self.infcx.tcx;
+
+ // <ty as Deref>
+ let trait_ref = tcx.mk_trait_ref(tcx.lang_items().deref_trait()?, [ty]);
+
+ let cause = traits::ObligationCause::misc(self.span, self.body_id);
+
+ let obligation = traits::Obligation::new(
+ tcx,
+ cause.clone(),
+ self.param_env,
+ ty::Binder::dummy(trait_ref),
+ );
+ if !self.infcx.predicate_may_hold(&obligation) {
+ debug!("overloaded_deref_ty: cannot match obligation");
+ return None;
+ }
+
+ let normalized_ty = self
+ .infcx
+ .at(&cause, self.param_env)
+ .normalize(tcx.mk_projection(tcx.lang_items().deref_target()?, trait_ref.substs));
+ let mut fulfillcx = <dyn TraitEngine<'tcx>>::new_in_snapshot(tcx);
+ let normalized_ty =
+ normalized_ty.into_value_registering_obligations(self.infcx, &mut *fulfillcx);
+ let errors = fulfillcx.select_where_possible(&self.infcx);
+ if !errors.is_empty() {
+ // This shouldn't happen, except for evaluate/fulfill mismatches,
+ // but that's not a reason for an ICE (`predicate_may_hold` is conservative
+ // by design).
+ debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", errors);
+ return None;
+ }
+ let obligations = fulfillcx.pending_obligations();
+ debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations);
+ self.state.obligations.extend(obligations);
+
+ Some(self.infcx.resolve_vars_if_possible(normalized_ty))
+ }
+
+ /// Returns the final type we ended up with, which may be an inference
+ /// variable (we will resolve it first, if we want).
+ pub fn final_ty(&self, resolve: bool) -> Ty<'tcx> {
+ if resolve {
+ self.infcx.resolve_vars_if_possible(self.state.cur_ty)
+ } else {
+ self.state.cur_ty
+ }
+ }
+
+ pub fn step_count(&self) -> usize {
+ self.state.steps.len()
+ }
+
+ pub fn into_obligations(self) -> Vec<traits::PredicateObligation<'tcx>> {
+ self.state.obligations
+ }
+
+ pub fn current_obligations(&self) -> Vec<traits::PredicateObligation<'tcx>> {
+ self.state.obligations.clone()
+ }
+
+ pub fn steps(&self) -> &[(Ty<'tcx>, AutoderefKind)] {
+ &self.state.steps
+ }
+
+ pub fn span(&self) -> Span {
+ self.span
+ }
+
+ pub fn reached_recursion_limit(&self) -> bool {
+ self.state.reached_recursion_limit
+ }
+
+ /// also dereference through raw pointer types
+ /// e.g., assuming ptr_to_Foo is the type `*const Foo`
+ /// fcx.autoderef(span, ptr_to_Foo) => [*const Foo]
+ /// fcx.autoderef(span, ptr_to_Foo).include_raw_ptrs() => [*const Foo, Foo]
+ pub fn include_raw_pointers(mut self) -> Self {
+ self.include_raw_pointers = true;
+ self
+ }
+
+ pub fn silence_errors(mut self) -> Self {
+ self.silence_errors = true;
+ self
+ }
+}
+
+pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) {
+ // We've reached the recursion limit, error gracefully.
+ let suggested_limit = match tcx.recursion_limit() {
+ Limit(0) => Limit(2),
+ limit => limit * 2,
+ };
+ tcx.sess.emit_err(AutoDerefReachedRecursionLimit {
+ span,
+ ty,
+ suggested_limit,
+ crate_name: tcx.crate_name(LOCAL_CRATE),
+ });
+}
diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs
index 3e3544ce6..0880c8c15 100644
--- a/compiler/rustc_hir_analysis/src/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/bounds.rs
@@ -1,6 +1,7 @@
//! Bounds are restrictions applied to some types after they've been converted into the
//! `ty` form from the HIR.
+use rustc_hir::LangItem;
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
use rustc_span::Span;
@@ -15,73 +16,53 @@ use rustc_span::Span;
/// ^^^^^^^^^ bounding the type parameter `T`
///
/// impl dyn Bar + Baz
-/// ^^^^^^^^^ bounding the forgotten dynamic type
+/// ^^^^^^^^^ bounding the type-erased dynamic type
/// ```
///
/// Our representation is a bit mixed here -- in some cases, we
/// include the self type (e.g., `trait_bounds`) but in others we do not
#[derive(Default, PartialEq, Eq, Clone, Debug)]
pub struct Bounds<'tcx> {
- /// A list of region bounds on the (implicit) self type. So if you
- /// had `T: 'a + 'b` this might would be a list `['a, 'b]` (but
- /// the `T` is not explicitly included).
- pub region_bounds: Vec<(ty::Binder<'tcx, ty::Region<'tcx>>, Span)>,
-
- /// A list of trait bounds. So if you had `T: Debug` this would be
- /// `T: Debug`. Note that the self-type is explicit here.
- pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span, ty::BoundConstness)>,
-
- /// A list of projection equality bounds. So if you had `T:
- /// Iterator<Item = u32>` this would include `<T as
- /// Iterator>::Item => u32`. Note that the self-type is explicit
- /// here.
- pub projection_bounds: Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>,
-
- /// `Some` if there is *no* `?Sized` predicate. The `span`
- /// is the location in the source of the `T` declaration which can
- /// be cited as the source of the `T: Sized` requirement.
- pub implicitly_sized: Option<Span>,
+ pub predicates: Vec<(ty::Predicate<'tcx>, Span)>,
}
impl<'tcx> Bounds<'tcx> {
- /// Converts a bounds list into a flat set of predicates (like
- /// where-clauses). Because some of our bounds listings (e.g.,
- /// regions) don't include the self-type, you must supply the
- /// self-type here (the `param_ty` parameter).
- pub fn predicates<'out, 's>(
- &'s self,
+ pub fn push_region_bound(
+ &mut self,
tcx: TyCtxt<'tcx>,
- param_ty: Ty<'tcx>,
- // the output must live shorter than the duration of the borrow of self and 'tcx.
- ) -> impl Iterator<Item = (ty::Predicate<'tcx>, Span)> + 'out
- where
- 'tcx: 'out,
- 's: 'out,
- {
- // If it could be sized, and is, add the `Sized` predicate.
- let sized_predicate = self.implicitly_sized.and_then(|span| {
- // FIXME: use tcx.at(span).mk_trait_ref(LangItem::Sized) here? This may make no-core code harder to write.
- let sized = tcx.lang_items().sized_trait()?;
- let trait_ref = ty::Binder::dummy(tcx.mk_trait_ref(sized, [param_ty]));
- Some((trait_ref.without_const().to_predicate(tcx), span))
- });
+ region: ty::PolyTypeOutlivesPredicate<'tcx>,
+ span: Span,
+ ) {
+ self.predicates.push((region.to_predicate(tcx), span));
+ }
- let region_preds = self.region_bounds.iter().map(move |&(region_bound, span)| {
- let pred = region_bound
- .map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound))
- .to_predicate(tcx);
- (pred, span)
- });
- let trait_bounds =
- self.trait_bounds.iter().map(move |&(bound_trait_ref, span, constness)| {
- let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx);
- (predicate, span)
- });
- let projection_bounds = self
- .projection_bounds
- .iter()
- .map(move |&(projection, span)| (projection.to_predicate(tcx), span));
+ pub fn push_trait_bound(
+ &mut self,
+ tcx: TyCtxt<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ span: Span,
+ constness: ty::BoundConstness,
+ ) {
+ self.predicates.push((trait_ref.with_constness(constness).to_predicate(tcx), span));
+ }
+
+ pub fn push_projection_bound(
+ &mut self,
+ tcx: TyCtxt<'tcx>,
+ projection: ty::PolyProjectionPredicate<'tcx>,
+ span: Span,
+ ) {
+ self.predicates.push((projection.to_predicate(tcx), span));
+ }
+
+ pub fn push_sized(&mut self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) {
+ let sized_def_id = tcx.require_lang_item(LangItem::Sized, Some(span));
+ let trait_ref = ty::Binder::dummy(tcx.mk_trait_ref(sized_def_id, [ty]));
+ // Preferrable to put this obligation first, since we report better errors for sized ambiguity.
+ self.predicates.insert(0, (trait_ref.without_const().to_predicate(tcx), span));
+ }
- sized_predicate.into_iter().chain(region_preds).chain(trait_bounds).chain(projection_bounds)
+ pub fn predicates(&self) -> impl Iterator<Item = (ty::Predicate<'tcx>, Span)> + '_ {
+ self.predicates.iter().cloned()
}
}
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index fc0ca6209..abc1c2d7b 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -1,8 +1,8 @@
use crate::check::intrinsicck::InlineAsmCtxt;
use crate::errors::LinkageType;
-use super::compare_method::check_type_bounds;
-use super::compare_method::{compare_impl_method, compare_ty_impl};
+use super::compare_impl_item::check_type_bounds;
+use super::compare_impl_item::{compare_impl_method, compare_impl_ty};
use super::*;
use rustc_attr as attr;
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
@@ -99,18 +99,17 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
ty: Ty<'tcx>,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
- span: Span,
) -> bool {
// We don't just accept all !needs_drop fields, due to semver concerns.
match ty.kind() {
ty::Ref(..) => true, // references never drop (even mutable refs, which are non-Copy and hence fail the later check)
ty::Tuple(tys) => {
// allow tuples of allowed types
- tys.iter().all(|ty| allowed_union_field(ty, tcx, param_env, span))
+ tys.iter().all(|ty| allowed_union_field(ty, tcx, param_env))
}
ty::Array(elem, _len) => {
// Like `Copy`, we do *not* special-case length 0.
- allowed_union_field(*elem, tcx, param_env, span)
+ allowed_union_field(*elem, tcx, param_env)
}
_ => {
// Fallback case: allow `ManuallyDrop` and things that are `Copy`.
@@ -124,7 +123,7 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
for field in &def.non_enum_variant().fields {
let field_ty = field.ty(tcx, substs);
- if !allowed_union_field(field_ty, tcx, param_env, span) {
+ if !allowed_union_field(field_ty, tcx, param_env) {
let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) {
// We are currently checking the type this field came from, so it must be local.
Some(Node::Field(field)) => (field.span, field.ty.span),
@@ -163,7 +162,7 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
}
/// Check that a `static` is inhabited.
-fn check_static_inhabited<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
+fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) {
// Make sure statics are inhabited.
// Other parts of the compiler assume that there are no uninhabited places. In principle it
// would be enough to check this for `extern` statics, as statics with an initializer will
@@ -213,7 +212,7 @@ fn check_static_inhabited<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
/// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo`
/// projections that would result in "inheriting lifetimes".
-fn check_opaque<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
+fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) {
let item = tcx.hir().item(id);
let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item.kind else {
tcx.sess.delay_span_bug(tcx.hir().span(id.hir_id()), "expected opaque item");
@@ -246,8 +245,8 @@ fn check_opaque<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
/// in "inheriting lifetimes".
#[instrument(level = "debug", skip(tcx, span))]
-pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
- tcx: TyCtxt<'tcx>,
+pub(super) fn check_opaque_for_inheriting_lifetimes(
+ tcx: TyCtxt<'_>,
def_id: LocalDefId,
span: Span,
) {
@@ -268,7 +267,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
debug!(?t, "root_visit_ty");
if t == self.opaque_identity_ty {
- ControlFlow::CONTINUE
+ ControlFlow::Continue(())
} else {
t.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
tcx: self.tcx,
@@ -283,7 +282,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
if self.references_parent_regions {
ControlFlow::Break(t)
} else {
- ControlFlow::CONTINUE
+ ControlFlow::Continue(())
}
}
}
@@ -469,14 +468,14 @@ fn check_opaque_meets_bounds<'tcx>(
// Can have different predicates to their defining use
hir::OpaqueTyOrigin::TyAlias => {
let outlives_environment = OutlivesEnvironment::new(param_env);
- infcx.check_region_obligations_and_report_errors(
+ let _ = infcx.err_ctxt().check_region_obligations_and_report_errors(
defining_use_anchor,
&outlives_environment,
);
}
}
// Clean up after ourselves
- let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+ let _ = infcx.take_opaque_types();
}
fn is_enum_of_nonnullable_ptr<'tcx>(
@@ -497,7 +496,7 @@ fn is_enum_of_nonnullable_ptr<'tcx>(
matches!(field.ty(tcx, substs).kind(), ty::FnPtr(..) | ty::Ref(..))
}
-fn check_static_linkage<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
+fn check_static_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) {
if tcx.codegen_fn_attrs(def_id).import_linkage.is_some() {
if match tcx.type_of(def_id).kind() {
ty::RawPtr(_) => false,
@@ -509,7 +508,7 @@ fn check_static_linkage<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
}
}
-fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
+fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
debug!(
"check_item_type(it.def_id={:?}, it.name={})",
id.owner_id,
@@ -532,16 +531,14 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
DefKind::Fn => {} // entirely within check_item_body
DefKind::Impl => {
let it = tcx.hir().item(id);
- let hir::ItemKind::Impl(ref impl_) = it.kind else {
- return;
- };
+ let hir::ItemKind::Impl(impl_) = it.kind else { return };
debug!("ItemKind::Impl {} with id {:?}", it.ident, it.owner_id);
if let Some(impl_trait_ref) = tcx.impl_trait_ref(it.owner_id) {
check_impl_items_against_trait(
tcx,
it.span,
it.owner_id.def_id,
- impl_trait_ref,
+ impl_trait_ref.subst_identity(),
&impl_.items,
);
check_on_unimplemented(tcx, it);
@@ -549,15 +546,15 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
}
DefKind::Trait => {
let it = tcx.hir().item(id);
- let hir::ItemKind::Trait(_, _, _, _, ref items) = it.kind else {
+ let hir::ItemKind::Trait(_, _, _, _, items) = it.kind else {
return;
};
check_on_unimplemented(tcx, it);
for item in items.iter() {
let item = tcx.hir().trait_item(item.id);
- match item.kind {
- hir::TraitItemKind::Fn(ref sig, _) => {
+ match &item.kind {
+ hir::TraitItemKind::Fn(sig, _) => {
let abi = sig.header.abi;
fn_maybe_err(tcx, item.ident.span, abi);
}
@@ -570,7 +567,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
assoc_item,
assoc_item,
default.span,
- ty::TraitRef { def_id: it.owner_id.to_def_id(), substs: trait_substs },
+ tcx.mk_trait_ref(it.owner_id.to_def_id(), trait_substs),
);
}
_ => {}
@@ -653,8 +650,8 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
}
let item = tcx.hir().foreign_item(item.id);
- match item.kind {
- hir::ForeignItemKind::Fn(ref fn_decl, _, _) => {
+ match &item.kind {
+ hir::ForeignItemKind::Fn(fn_decl, _, _) => {
require_c_abi_if_c_variadic(tcx, fn_decl, abi, item.span);
}
hir::ForeignItemKind::Static(..) => {
@@ -775,7 +772,7 @@ fn check_impl_items_against_trait<'tcx>(
let impl_item_full = tcx.hir().impl_item(impl_item.id);
match impl_item_full.kind {
hir::ImplItemKind::Const(..) => {
- let _ = tcx.compare_assoc_const_impl_item_with_trait_item((
+ let _ = tcx.compare_impl_const((
impl_item.id.owner_id.def_id,
ty_impl_item.trait_item_def_id.unwrap(),
));
@@ -792,7 +789,7 @@ fn check_impl_items_against_trait<'tcx>(
}
hir::ImplItemKind::Type(impl_ty) => {
let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
- compare_ty_impl(
+ compare_impl_ty(
tcx,
&ty_impl_item,
impl_ty.span,
@@ -1061,10 +1058,8 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
if adt.variants().len() != 1 {
bad_variant_count(tcx, adt, tcx.def_span(adt.did()), adt.did());
- if adt.variants().is_empty() {
- // Don't bother checking the fields. No variants (and thus no fields) exist.
- return;
- }
+ // Don't bother checking the fields.
+ return;
}
// For each field, figure out if it's known to be a ZST and align(1), with "known"
@@ -1161,7 +1156,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
}
#[allow(trivial_numeric_casts)]
-fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
+fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let def = tcx.adt_def(def_id);
def.destructor(tcx); // force the destructor to be evaluated
@@ -1396,11 +1391,15 @@ fn async_opaque_type_cycle_error(tcx: TyCtxt<'_>, span: Span) -> ErrorGuaranteed
///
/// If all the return expressions evaluate to `!`, then we explain that the error will go away
/// after changing it. This can happen when a user uses `panic!()` or similar as a placeholder.
-fn opaque_type_cycle_error(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> ErrorGuaranteed {
+fn opaque_type_cycle_error(
+ tcx: TyCtxt<'_>,
+ opaque_def_id: LocalDefId,
+ span: Span,
+) -> ErrorGuaranteed {
let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type");
let mut label = false;
- if let Some((def_id, visitor)) = get_owner_return_paths(tcx, def_id) {
+ if let Some((def_id, visitor)) = get_owner_return_paths(tcx, opaque_def_id) {
let typeck_results = tcx.typeck(def_id);
if visitor
.returns
@@ -1436,21 +1435,30 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> E
.filter_map(|e| typeck_results.node_type_opt(e.hir_id).map(|t| (e.span, t)))
.filter(|(_, ty)| !matches!(ty.kind(), ty::Never))
{
- struct OpaqueTypeCollector(Vec<DefId>);
+ #[derive(Default)]
+ struct OpaqueTypeCollector {
+ opaques: Vec<DefId>,
+ closures: Vec<DefId>,
+ }
impl<'tcx> ty::visit::TypeVisitor<'tcx> for OpaqueTypeCollector {
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match *t.kind() {
- ty::Opaque(def, _) => {
- self.0.push(def);
- ControlFlow::CONTINUE
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
+ self.opaques.push(def);
+ ControlFlow::Continue(())
+ }
+ ty::Closure(def_id, ..) | ty::Generator(def_id, ..) => {
+ self.closures.push(def_id);
+ t.super_visit_with(self)
}
_ => t.super_visit_with(self),
}
}
}
- let mut visitor = OpaqueTypeCollector(vec![]);
+
+ let mut visitor = OpaqueTypeCollector::default();
ty.visit_with(&mut visitor);
- for def_id in visitor.0 {
+ for def_id in visitor.opaques {
let ty_span = tcx.def_span(def_id);
if !seen.contains(&ty_span) {
err.span_label(ty_span, &format!("returning this opaque type `{ty}`"));
@@ -1458,6 +1466,40 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> E
}
err.span_label(sp, &format!("returning here with type `{ty}`"));
}
+
+ for closure_def_id in visitor.closures {
+ let Some(closure_local_did) = closure_def_id.as_local() else { continue; };
+ let typeck_results = tcx.typeck(closure_local_did);
+
+ let mut label_match = |ty: Ty<'_>, span| {
+ for arg in ty.walk() {
+ if let ty::GenericArgKind::Type(ty) = arg.unpack()
+ && let ty::Alias(ty::Opaque, ty::AliasTy { def_id: captured_def_id, .. }) = *ty.kind()
+ && captured_def_id == opaque_def_id.to_def_id()
+ {
+ err.span_label(
+ span,
+ format!(
+ "{} captures itself here",
+ tcx.def_kind(closure_def_id).descr(closure_def_id)
+ ),
+ );
+ }
+ }
+ };
+
+ // Label any closure upvars that capture the opaque
+ for capture in typeck_results.closure_min_captures_flattened(closure_local_did)
+ {
+ label_match(capture.place.ty(), capture.get_path_span(tcx));
+ }
+ // Label any generator locals that capture the opaque
+ for interior_ty in
+ typeck_results.generator_interior_types.as_ref().skip_binder()
+ {
+ label_match(interior_ty.ty, interior_ty.span);
+ }
+ }
}
}
}
diff --git a/compiler/rustc_hir_analysis/src/check/compare_method.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index db150ebf0..cfebcceef 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_method.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -2,7 +2,9 @@ use super::potentially_plural_count;
use crate::errors::LifetimesOrBoundsMismatchOnTrait;
use hir::def_id::{DefId, LocalDefId};
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
-use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed};
+use rustc_errors::{
+ pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed, MultiSpan,
+};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit;
@@ -34,7 +36,7 @@ use std::iter;
/// - `impl_m_span`: span to use for reporting errors
/// - `trait_m`: the method in the trait
/// - `impl_trait_ref`: the TraitRef corresponding to the trait implementation
-pub(crate) fn compare_impl_method<'tcx>(
+pub(super) fn compare_impl_method<'tcx>(
tcx: TyCtxt<'tcx>,
impl_m: &ty::AssocItem,
trait_m: &ty::AssocItem,
@@ -45,38 +47,22 @@ pub(crate) fn compare_impl_method<'tcx>(
let impl_m_span = tcx.def_span(impl_m.def_id);
- if let Err(_) = compare_self_type(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref) {
- return;
- }
-
- if let Err(_) = compare_number_of_generics(tcx, impl_m, trait_m, trait_item_span, false) {
- return;
- }
-
- if let Err(_) = compare_generic_param_kinds(tcx, impl_m, trait_m, false) {
- return;
- }
-
- if let Err(_) =
- compare_number_of_method_arguments(tcx, impl_m, impl_m_span, trait_m, trait_item_span)
- {
- return;
- }
-
- if let Err(_) = compare_synthetic_generics(tcx, impl_m, trait_m) {
- return;
- }
-
- if let Err(_) = compare_predicate_entailment(
- tcx,
- impl_m,
- impl_m_span,
- trait_m,
- impl_trait_ref,
- CheckImpliedWfMode::Check,
- ) {
- return;
- }
+ let _: Result<_, ErrorGuaranteed> = try {
+ compare_self_type(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref)?;
+ compare_number_of_generics(tcx, impl_m, trait_m, trait_item_span, false)?;
+ compare_generic_param_kinds(tcx, impl_m, trait_m, false)?;
+ compare_number_of_method_arguments(tcx, impl_m, impl_m_span, trait_m, trait_item_span)?;
+ compare_synthetic_generics(tcx, impl_m, trait_m)?;
+ compare_asyncness(tcx, impl_m, impl_m_span, trait_m, trait_item_span)?;
+ compare_method_predicate_entailment(
+ tcx,
+ impl_m,
+ impl_m_span,
+ trait_m,
+ impl_trait_ref,
+ CheckImpliedWfMode::Check,
+ )?;
+ };
}
/// This function is best explained by example. Consider a trait:
@@ -132,7 +118,7 @@ pub(crate) fn compare_impl_method<'tcx>(
/// <'a> fn(t: &'i0 U0, m: &'a) -> Foo
///
/// This type is also the same but the name of the bound region (`'a`
-/// vs `'b`). However, the normal subtyping rules on fn types handle
+/// vs `'b`). However, the normal subtyping rules on fn types handle
/// this kind of equivalency just fine.
///
/// We now use these substitutions to ensure that all declared bounds are
@@ -146,7 +132,7 @@ pub(crate) fn compare_impl_method<'tcx>(
/// Finally we register each of these predicates as an obligation and check that
/// they hold.
#[instrument(level = "debug", skip(tcx, impl_m_span, impl_trait_ref))]
-fn compare_predicate_entailment<'tcx>(
+fn compare_method_predicate_entailment<'tcx>(
tcx: TyCtxt<'tcx>,
impl_m: &ty::AssocItem,
impl_m_span: Span,
@@ -203,9 +189,11 @@ fn compare_predicate_entailment<'tcx>(
//
// We then register the obligations from the impl_m and check to see
// if all constraints hold.
- hybrid_preds
- .predicates
- .extend(trait_m_predicates.instantiate_own(tcx, trait_to_placeholder_substs).predicates);
+ hybrid_preds.predicates.extend(
+ trait_m_predicates
+ .instantiate_own(tcx, trait_to_placeholder_substs)
+ .map(|(predicate, _)| predicate),
+ );
// Construct trait parameter environment and then shift it into the placeholder viewpoint.
// The key step here is to update the caller_bounds's predicates to be
@@ -224,7 +212,7 @@ fn compare_predicate_entailment<'tcx>(
debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds());
let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs);
- for (predicate, span) in iter::zip(impl_m_own_bounds.predicates, impl_m_own_bounds.spans) {
+ for (predicate, span) in impl_m_own_bounds {
let normalize_cause = traits::ObligationCause::misc(span, impl_m_hir_id);
let predicate = ocx.normalize(&normalize_cause, param_env, predicate);
@@ -266,8 +254,8 @@ fn compare_predicate_entailment<'tcx>(
let unnormalized_impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(unnormalized_impl_sig));
let norm_cause = ObligationCause::misc(impl_m_span, impl_m_hir_id);
- let impl_fty = ocx.normalize(&norm_cause, param_env, unnormalized_impl_fty);
- debug!("compare_impl_method: impl_fty={:?}", impl_fty);
+ let impl_sig = ocx.normalize(&norm_cause, param_env, unnormalized_impl_sig);
+ debug!("compare_impl_method: impl_fty={:?}", impl_sig);
let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs);
let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig);
@@ -290,18 +278,17 @@ fn compare_predicate_entailment<'tcx>(
// type would be more appropriate. In other places we have a `Vec<Span>`
// corresponding to their `Vec<Predicate>`, but we don't have that here.
// Fixing this would improve the output of test `issue-83765.rs`.
- let result = ocx.sup(&cause, param_env, trait_fty, impl_fty);
+ let result = ocx.sup(&cause, param_env, trait_sig, impl_sig);
if let Err(terr) = result {
- debug!(?terr, "sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty);
+ debug!(?impl_sig, ?trait_sig, ?terr, "sub_types failed");
let emitted = report_trait_method_mismatch(
&infcx,
cause,
terr,
- (trait_m, trait_fty),
- (impl_m, impl_fty),
- trait_sig,
+ (trait_m, trait_sig),
+ (impl_m, impl_sig),
impl_trait_ref,
);
return Err(emitted);
@@ -317,15 +304,6 @@ fn compare_predicate_entailment<'tcx>(
ty::Binder::dummy(ty::PredicateKind::WellFormed(unnormalized_impl_fty.into())),
));
}
- let emit_implied_wf_lint = || {
- infcx.tcx.struct_span_lint_hir(
- rustc_session::lint::builtin::IMPLIED_BOUNDS_ENTAILMENT,
- impl_m_hir_id,
- infcx.tcx.def_span(impl_m.def_id),
- "impl method assumes more implied bounds than the corresponding trait method",
- |lint| lint,
- );
- };
// Check that all obligations are satisfied by the implementation's
// version.
@@ -333,7 +311,7 @@ fn compare_predicate_entailment<'tcx>(
if !errors.is_empty() {
match check_implied_wf {
CheckImpliedWfMode::Check => {
- return compare_predicate_entailment(
+ return compare_method_predicate_entailment(
tcx,
impl_m,
impl_m_span,
@@ -343,7 +321,7 @@ fn compare_predicate_entailment<'tcx>(
)
.map(|()| {
// If the skip-mode was successful, emit a lint.
- emit_implied_wf_lint();
+ emit_implied_wf_lint(infcx.tcx, impl_m, impl_m_hir_id, vec![]);
});
}
CheckImpliedWfMode::Skip => {
@@ -370,7 +348,7 @@ fn compare_predicate_entailment<'tcx>(
// becomes a hard error (i.e. ideally we'd just call `resolve_regions_and_report_errors`
match check_implied_wf {
CheckImpliedWfMode::Check => {
- return compare_predicate_entailment(
+ return compare_method_predicate_entailment(
tcx,
impl_m,
impl_m_span,
@@ -379,8 +357,16 @@ fn compare_predicate_entailment<'tcx>(
CheckImpliedWfMode::Skip,
)
.map(|()| {
+ let bad_args = extract_bad_args_for_implies_lint(
+ tcx,
+ &errors,
+ (trait_m, trait_sig),
+ // Unnormalized impl sig corresponds to the HIR types written
+ (impl_m, unnormalized_impl_sig),
+ impl_m_hir_id,
+ );
// If the skip-mode was successful, emit a lint.
- emit_implied_wf_lint();
+ emit_implied_wf_lint(tcx, impl_m, impl_m_hir_id, bad_args);
});
}
CheckImpliedWfMode::Skip => {
@@ -397,29 +383,227 @@ fn compare_predicate_entailment<'tcx>(
Ok(())
}
+fn extract_bad_args_for_implies_lint<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ errors: &[infer::RegionResolutionError<'tcx>],
+ (trait_m, trait_sig): (&ty::AssocItem, ty::FnSig<'tcx>),
+ (impl_m, impl_sig): (&ty::AssocItem, ty::FnSig<'tcx>),
+ hir_id: hir::HirId,
+) -> Vec<(Span, Option<String>)> {
+ let mut blame_generics = vec![];
+ for error in errors {
+ // Look for the subregion origin that contains an input/output type
+ let origin = match error {
+ infer::RegionResolutionError::ConcreteFailure(o, ..) => o,
+ infer::RegionResolutionError::GenericBoundFailure(o, ..) => o,
+ infer::RegionResolutionError::SubSupConflict(_, _, o, ..) => o,
+ infer::RegionResolutionError::UpperBoundUniverseConflict(.., o, _) => o,
+ };
+ // Extract (possible) input/output types from origin
+ match origin {
+ infer::SubregionOrigin::Subtype(trace) => {
+ if let Some((a, b)) = trace.values.ty() {
+ blame_generics.extend([a, b]);
+ }
+ }
+ infer::SubregionOrigin::RelateParamBound(_, ty, _) => blame_generics.push(*ty),
+ infer::SubregionOrigin::ReferenceOutlivesReferent(ty, _) => blame_generics.push(*ty),
+ _ => {}
+ }
+ }
+
+ let fn_decl = tcx.hir().fn_decl_by_hir_id(hir_id).unwrap();
+ let opt_ret_ty = match fn_decl.output {
+ hir::FnRetTy::DefaultReturn(_) => None,
+ hir::FnRetTy::Return(ty) => Some(ty),
+ };
+
+ // Map late-bound regions from trait to impl, so the names are right.
+ let mapping = std::iter::zip(
+ tcx.fn_sig(trait_m.def_id).bound_vars(),
+ tcx.fn_sig(impl_m.def_id).bound_vars(),
+ )
+ .filter_map(|(impl_bv, trait_bv)| {
+ if let ty::BoundVariableKind::Region(impl_bv) = impl_bv
+ && let ty::BoundVariableKind::Region(trait_bv) = trait_bv
+ {
+ Some((impl_bv, trait_bv))
+ } else {
+ None
+ }
+ })
+ .collect();
+
+ // For each arg, see if it was in the "blame" of any of the region errors.
+ // If so, then try to produce a suggestion to replace the argument type with
+ // one from the trait.
+ let mut bad_args = vec![];
+ for (idx, (ty, hir_ty)) in
+ std::iter::zip(impl_sig.inputs_and_output, fn_decl.inputs.iter().chain(opt_ret_ty))
+ .enumerate()
+ {
+ let expected_ty = trait_sig.inputs_and_output[idx]
+ .fold_with(&mut RemapLateBound { tcx, mapping: &mapping });
+ if blame_generics.iter().any(|blame| ty.contains(*blame)) {
+ let expected_ty_sugg = expected_ty.to_string();
+ bad_args.push((
+ hir_ty.span,
+ // Only suggest something if it actually changed.
+ (expected_ty_sugg != ty.to_string()).then_some(expected_ty_sugg),
+ ));
+ }
+ }
+
+ bad_args
+}
+
+struct RemapLateBound<'a, 'tcx> {
+ tcx: TyCtxt<'tcx>,
+ mapping: &'a FxHashMap<ty::BoundRegionKind, ty::BoundRegionKind>,
+}
+
+impl<'tcx> TypeFolder<'tcx> for RemapLateBound<'_, 'tcx> {
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ if let ty::ReFree(fr) = *r {
+ self.tcx.mk_region(ty::ReFree(ty::FreeRegion {
+ bound_region: self
+ .mapping
+ .get(&fr.bound_region)
+ .copied()
+ .unwrap_or(fr.bound_region),
+ ..fr
+ }))
+ } else {
+ r
+ }
+ }
+}
+
+fn emit_implied_wf_lint<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ impl_m: &ty::AssocItem,
+ hir_id: hir::HirId,
+ bad_args: Vec<(Span, Option<String>)>,
+) {
+ let span: MultiSpan = if bad_args.is_empty() {
+ tcx.def_span(impl_m.def_id).into()
+ } else {
+ bad_args.iter().map(|(span, _)| *span).collect::<Vec<_>>().into()
+ };
+ tcx.struct_span_lint_hir(
+ rustc_session::lint::builtin::IMPLIED_BOUNDS_ENTAILMENT,
+ hir_id,
+ span,
+ "impl method assumes more implied bounds than the corresponding trait method",
+ |lint| {
+ let bad_args: Vec<_> =
+ bad_args.into_iter().filter_map(|(span, sugg)| Some((span, sugg?))).collect();
+ if !bad_args.is_empty() {
+ lint.multipart_suggestion(
+ format!(
+ "replace {} type{} to make the impl signature compatible",
+ pluralize!("this", bad_args.len()),
+ pluralize!(bad_args.len())
+ ),
+ bad_args,
+ Applicability::MaybeIncorrect,
+ );
+ }
+ lint
+ },
+ );
+}
+
#[derive(Debug, PartialEq, Eq)]
enum CheckImpliedWfMode {
/// Checks implied well-formedness of the impl method. If it fails, we will
/// re-check with `Skip`, and emit a lint if it succeeds.
Check,
/// Skips checking implied well-formedness of the impl method, but will emit
- /// a lint if the `compare_predicate_entailment` succeeded. This means that
+ /// a lint if the `compare_method_predicate_entailment` succeeded. This means that
/// the reason that we had failed earlier during `Check` was due to the impl
/// having stronger requirements than the trait.
Skip,
}
+fn compare_asyncness<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ impl_m: &ty::AssocItem,
+ impl_m_span: Span,
+ trait_m: &ty::AssocItem,
+ trait_item_span: Option<Span>,
+) -> Result<(), ErrorGuaranteed> {
+ if tcx.asyncness(trait_m.def_id) == hir::IsAsync::Async {
+ match tcx.fn_sig(impl_m.def_id).skip_binder().output().kind() {
+ ty::Alias(ty::Opaque, ..) => {
+ // allow both `async fn foo()` and `fn foo() -> impl Future`
+ }
+ ty::Error(_) => {
+ // We don't know if it's ok, but at least it's already an error.
+ }
+ _ => {
+ return Err(tcx.sess.emit_err(crate::errors::AsyncTraitImplShouldBeAsync {
+ span: impl_m_span,
+ method_name: trait_m.name,
+ trait_item_span,
+ }));
+ }
+ };
+ }
+
+ Ok(())
+}
+
+/// Given a method def-id in an impl, compare the method signature of the impl
+/// against the trait that it's implementing. In doing so, infer the hidden types
+/// that this method's signature provides to satisfy each return-position `impl Trait`
+/// in the trait signature.
+///
+/// The method is also responsible for making sure that the hidden types for each
+/// RPITIT actually satisfy the bounds of the `impl Trait`, i.e. that if we infer
+/// `impl Trait = Foo`, that `Foo: Trait` holds.
+///
+/// For example, given the sample code:
+///
+/// ```
+/// #![feature(return_position_impl_trait_in_trait)]
+///
+/// use std::ops::Deref;
+///
+/// trait Foo {
+/// fn bar() -> impl Deref<Target = impl Sized>;
+/// // ^- RPITIT #1 ^- RPITIT #2
+/// }
+///
+/// impl Foo for () {
+/// fn bar() -> Box<String> { Box::new(String::new()) }
+/// }
+/// ```
+///
+/// The hidden types for the RPITITs in `bar` would be inferred to:
+/// * `impl Deref` (RPITIT #1) = `Box<String>`
+/// * `impl Sized` (RPITIT #2) = `String`
+///
+/// The relationship between these two types is straightforward in this case, but
+/// may be more tenuously connected via other `impl`s and normalization rules for
+/// cases of more complicated nested RPITITs.
#[instrument(skip(tcx), level = "debug", ret)]
-pub fn collect_trait_impl_trait_tys<'tcx>(
+pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: DefId,
) -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed> {
let impl_m = tcx.opt_associated_item(def_id).unwrap();
let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap();
- let impl_trait_ref = tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap();
+ let impl_trait_ref =
+ tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap().subst_identity();
let param_env = tcx.param_env(def_id);
- // First, check a few of the same thing as `compare_impl_method`, just so we don't ICE during substitutions later.
+ // First, check a few of the same things as `compare_impl_method`,
+ // just so we don't ICE during substitution later.
compare_number_of_generics(tcx, impl_m, trait_m, tcx.hir().span_if_local(impl_m.def_id), true)?;
compare_generic_param_kinds(tcx, impl_m, trait_m, true)?;
check_region_bounds_on_impl_item(tcx, impl_m, trait_m, true)?;
@@ -459,6 +643,7 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
tcx.fn_sig(impl_m.def_id),
),
);
+ impl_sig.error_reported()?;
let impl_return_ty = impl_sig.output();
// Normalize the trait signature with liberated bound vars, passing it through
@@ -473,6 +658,7 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
)
.fold_with(&mut collector);
let trait_sig = ocx.normalize(&norm_cause, param_env, unnormalized_trait_sig);
+ trait_sig.error_reported()?;
let trait_return_ty = trait_sig.output();
let wf_tys = FxIndexSet::from_iter(
@@ -510,27 +696,23 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
debug!(?trait_sig, ?impl_sig, "equating function signatures");
- let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
- let impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig));
-
// Unify the whole function signature. We need to do this to fully infer
// the lifetimes of the return type, but do this after unifying just the
// return types, since we want to avoid duplicating errors from
- // `compare_predicate_entailment`.
- match ocx.eq(&cause, param_env, trait_fty, impl_fty) {
+ // `compare_method_predicate_entailment`.
+ match ocx.eq(&cause, param_env, trait_sig, impl_sig) {
Ok(()) => {}
Err(terr) => {
- // This function gets called during `compare_predicate_entailment` when normalizing a
+ // This function gets called during `compare_method_predicate_entailment` when normalizing a
// signature that contains RPITIT. When the method signatures don't match, we have to
- // emit an error now because `compare_predicate_entailment` will not report the error
+ // emit an error now because `compare_method_predicate_entailment` will not report the error
// when normalization fails.
let emitted = report_trait_method_mismatch(
infcx,
cause,
terr,
- (trait_m, trait_fty),
- (impl_m, impl_fty),
- trait_sig,
+ (trait_m, trait_sig),
+ (impl_m, impl_sig),
impl_trait_ref,
);
return Err(emitted);
@@ -552,17 +734,17 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
Some(infcx),
infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys),
);
- infcx.check_region_obligations_and_report_errors(
+ infcx.err_ctxt().check_region_obligations_and_report_errors(
impl_m.def_id.expect_local(),
&outlives_environment,
- );
+ )?;
let mut collected_tys = FxHashMap::default();
for (def_id, (ty, substs)) in collector.types {
match infcx.fully_resolve(ty) {
Ok(ty) => {
// `ty` contains free regions that we created earlier while liberating the
- // trait fn signature. However, projection normalization expects `ty` to
+ // trait fn signature. However, projection normalization expects `ty` to
// contains `def_id`'s early-bound regions.
let id_substs = InternalSubsts::identity_for_item(tcx, def_id);
debug!(?id_substs, ?substs);
@@ -657,10 +839,10 @@ impl<'tcx> TypeFolder<'tcx> for ImplTraitInTraitCollector<'_, 'tcx> {
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
- if let ty::Projection(proj) = ty.kind()
- && self.tcx().def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder
+ if let ty::Alias(ty::Projection, proj) = ty.kind()
+ && self.tcx().def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder
{
- if let Some((ty, _)) = self.types.get(&proj.item_def_id) {
+ if let Some((ty, _)) = self.types.get(&proj.def_id) {
return *ty;
}
//FIXME(RPITIT): Deny nested RPITIT in substs too
@@ -672,9 +854,9 @@ impl<'tcx> TypeFolder<'tcx> for ImplTraitInTraitCollector<'_, 'tcx> {
span: self.span,
kind: TypeVariableOriginKind::MiscVariable,
});
- self.types.insert(proj.item_def_id, (infer_ty, proj.substs));
+ self.types.insert(proj.def_id, (infer_ty, proj.substs));
// Recurse into bounds
- for (pred, pred_span) in self.tcx().bound_explicit_item_bounds(proj.item_def_id).subst_iter_copied(self.tcx(), proj.substs) {
+ for (pred, pred_span) in self.tcx().bound_explicit_item_bounds(proj.def_id).subst_iter_copied(self.tcx(), proj.substs) {
let pred = pred.fold_with(self);
let pred = self.ocx.normalize(
&ObligationCause::misc(self.span, self.body_id),
@@ -687,7 +869,7 @@ impl<'tcx> TypeFolder<'tcx> for ImplTraitInTraitCollector<'_, 'tcx> {
ObligationCause::new(
self.span,
self.body_id,
- ObligationCauseCode::BindingObligation(proj.item_def_id, pred_span),
+ ObligationCauseCode::BindingObligation(proj.def_id, pred_span),
),
self.param_env,
pred,
@@ -704,9 +886,8 @@ fn report_trait_method_mismatch<'tcx>(
infcx: &InferCtxt<'tcx>,
mut cause: ObligationCause<'tcx>,
terr: TypeError<'tcx>,
- (trait_m, trait_fty): (&ty::AssocItem, Ty<'tcx>),
- (impl_m, impl_fty): (&ty::AssocItem, Ty<'tcx>),
- trait_sig: ty::FnSig<'tcx>,
+ (trait_m, trait_sig): (&ty::AssocItem, ty::FnSig<'tcx>),
+ (impl_m, impl_sig): (&ty::AssocItem, ty::FnSig<'tcx>),
impl_trait_ref: ty::TraitRef<'tcx>,
) -> ErrorGuaranteed {
let tcx = infcx.tcx;
@@ -735,16 +916,14 @@ fn report_trait_method_mismatch<'tcx>(
// When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
// span points only at the type `Box<Self`>, but we want to cover the whole
// argument pattern and type.
- let span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
- ImplItemKind::Fn(ref sig, body) => tcx
- .hir()
- .body_param_names(body)
- .zip(sig.decl.inputs.iter())
- .map(|(param, ty)| param.span.to(ty.span))
- .next()
- .unwrap_or(impl_err_span),
- _ => bug!("{:?} is not a method", impl_m),
- };
+ let ImplItemKind::Fn(ref sig, body) = tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{impl_m:?} is not a method") };
+ let span = tcx
+ .hir()
+ .body_param_names(body)
+ .zip(sig.decl.inputs.iter())
+ .map(|(param, ty)| param.span.to(ty.span))
+ .next()
+ .unwrap_or(impl_err_span);
diag.span_suggestion(
span,
@@ -757,22 +936,21 @@ fn report_trait_method_mismatch<'tcx>(
if trait_sig.inputs().len() == *i {
// Suggestion to change output type. We do not suggest in `async` functions
// to avoid complex logic or incorrect output.
- match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
- ImplItemKind::Fn(ref sig, _) if !sig.header.asyncness.is_async() => {
- let msg = "change the output type to match the trait";
- let ap = Applicability::MachineApplicable;
- match sig.decl.output {
- hir::FnRetTy::DefaultReturn(sp) => {
- let sugg = format!("-> {} ", trait_sig.output());
- diag.span_suggestion_verbose(sp, msg, sugg, ap);
- }
- hir::FnRetTy::Return(hir_ty) => {
- let sugg = trait_sig.output();
- diag.span_suggestion(hir_ty.span, msg, sugg, ap);
- }
- };
- }
- _ => {}
+ if let ImplItemKind::Fn(sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind
+ && !sig.header.asyncness.is_async()
+ {
+ let msg = "change the output type to match the trait";
+ let ap = Applicability::MachineApplicable;
+ match sig.decl.output {
+ hir::FnRetTy::DefaultReturn(sp) => {
+ let sugg = format!("-> {} ", trait_sig.output());
+ diag.span_suggestion_verbose(sp, msg, sugg, ap);
+ }
+ hir::FnRetTy::Return(hir_ty) => {
+ let sugg = trait_sig.output();
+ diag.span_suggestion(hir_ty.span, msg, sugg, ap);
+ }
+ };
};
} else if let Some(trait_ty) = trait_sig.inputs().get(*i) {
diag.span_suggestion(
@@ -791,10 +969,7 @@ fn report_trait_method_mismatch<'tcx>(
&mut diag,
&cause,
trait_err_span.map(|sp| (sp, "type in trait".to_owned())),
- Some(infer::ValuePairs::Terms(ExpectedFound {
- expected: trait_fty.into(),
- found: impl_fty.into(),
- })),
+ Some(infer::ValuePairs::Sigs(ExpectedFound { expected: trait_sig, found: impl_sig })),
terr,
false,
false,
@@ -824,7 +999,7 @@ fn check_region_bounds_on_impl_item<'tcx>(
// Must have same number of early-bound lifetime parameters.
// Unfortunately, if the user screws up the bounds, then this
- // will change classification between early and late. E.g.,
+ // will change classification between early and late. E.g.,
// if in trait we have `<'a,'b:'a>`, and in impl we just have
// `<'a,'b>`, then we have 2 early-bound lifetime parameters
// in trait but 0 in the impl. But if we report "expected 2
@@ -902,25 +1077,18 @@ fn extract_spans_for_error_reporting<'tcx>(
trait_m: &ty::AssocItem,
) -> (Span, Option<Span>) {
let tcx = infcx.tcx;
- let mut impl_args = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
- ImplItemKind::Fn(ref sig, _) => {
- sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
- }
- _ => bug!("{:?} is not a method", impl_m),
+ let mut impl_args = {
+ let ImplItemKind::Fn(sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{:?} is not a method", impl_m) };
+ sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
};
- let trait_args =
- trait_m.def_id.as_local().map(|def_id| match tcx.hir().expect_trait_item(def_id).kind {
- TraitItemKind::Fn(ref sig, _) => {
- sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
- }
- _ => bug!("{:?} is not a TraitItemKind::Fn", trait_m),
- });
+
+ let trait_args = trait_m.def_id.as_local().map(|def_id| {
+ let TraitItemKind::Fn(sig, _) = &tcx.hir().expect_trait_item(def_id).kind else { bug!("{:?} is not a TraitItemKind::Fn", trait_m) };
+ sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
+ });
match terr {
- TypeError::ArgumentMutability(i) => {
- (impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i)))
- }
- TypeError::ArgumentSorts(ExpectedFound { .. }, i) => {
+ TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => {
(impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i)))
}
_ => (cause.span(), tcx.hir().span_if_local(trait_m.def_id)),
@@ -935,9 +1103,9 @@ fn compare_self_type<'tcx>(
impl_trait_ref: ty::TraitRef<'tcx>,
) -> Result<(), ErrorGuaranteed> {
// Try to give more informative error messages about self typing
- // mismatches. Note that any mismatch will also be detected
+ // mismatches. Note that any mismatch will also be detected
// below, where we construct a canonical function type that
- // includes the self parameter as a normal parameter. It's just
+ // includes the self parameter as a normal parameter. It's just
// that the error messages you get out of this code are a bit more
// inscrutable, particularly for cases where one method has no
// self.
@@ -980,8 +1148,7 @@ fn compare_self_type<'tcx>(
} else {
err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
}
- let reported = err.emit();
- return Err(reported);
+ return Err(err.emit());
}
(true, false) => {
@@ -1000,8 +1167,8 @@ fn compare_self_type<'tcx>(
} else {
err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
}
- let reported = err.emit();
- return Err(reported);
+
+ return Err(err.emit());
}
}
@@ -1183,41 +1350,39 @@ fn compare_number_of_method_arguments<'tcx>(
let trait_m_fty = tcx.fn_sig(trait_m.def_id);
let trait_number_args = trait_m_fty.inputs().skip_binder().len();
let impl_number_args = impl_m_fty.inputs().skip_binder().len();
+
if trait_number_args != impl_number_args {
- let trait_span = if let Some(def_id) = trait_m.def_id.as_local() {
- match tcx.hir().expect_trait_item(def_id).kind {
- TraitItemKind::Fn(ref trait_m_sig, _) => {
- let pos = if trait_number_args > 0 { trait_number_args - 1 } else { 0 };
- if let Some(arg) = trait_m_sig.decl.inputs.get(pos) {
- Some(if pos == 0 {
- arg.span
- } else {
- arg.span.with_lo(trait_m_sig.decl.inputs[0].span.lo())
- })
- } else {
- trait_item_span
- }
- }
- _ => bug!("{:?} is not a method", impl_m),
- }
- } else {
- trait_item_span
- };
- let impl_span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
- ImplItemKind::Fn(ref impl_m_sig, _) => {
- let pos = if impl_number_args > 0 { impl_number_args - 1 } else { 0 };
- if let Some(arg) = impl_m_sig.decl.inputs.get(pos) {
+ let trait_span = trait_m
+ .def_id
+ .as_local()
+ .and_then(|def_id| {
+ let TraitItemKind::Fn(trait_m_sig, _) = &tcx.hir().expect_trait_item(def_id).kind else { bug!("{:?} is not a method", impl_m) };
+ let pos = trait_number_args.saturating_sub(1);
+ trait_m_sig.decl.inputs.get(pos).map(|arg| {
if pos == 0 {
arg.span
} else {
- arg.span.with_lo(impl_m_sig.decl.inputs[0].span.lo())
+ arg.span.with_lo(trait_m_sig.decl.inputs[0].span.lo())
}
+ })
+ })
+ .or(trait_item_span);
+
+ let ImplItemKind::Fn(impl_m_sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{:?} is not a method", impl_m) };
+ let pos = impl_number_args.saturating_sub(1);
+ let impl_span = impl_m_sig
+ .decl
+ .inputs
+ .get(pos)
+ .map(|arg| {
+ if pos == 0 {
+ arg.span
} else {
- impl_m_span
+ arg.span.with_lo(impl_m_sig.decl.inputs[0].span.lo())
}
- }
- _ => bug!("{:?} is not a method", impl_m),
- };
+ })
+ .unwrap_or(impl_m_span);
+
let mut err = struct_span_err!(
tcx.sess,
impl_span,
@@ -1228,6 +1393,7 @@ fn compare_number_of_method_arguments<'tcx>(
tcx.def_path_str(trait_m.def_id),
trait_number_args
);
+
if let Some(trait_span) = trait_span {
err.span_label(
trait_span,
@@ -1239,6 +1405,7 @@ fn compare_number_of_method_arguments<'tcx>(
} else {
err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
}
+
err.span_label(
impl_span,
format!(
@@ -1247,8 +1414,8 @@ fn compare_number_of_method_arguments<'tcx>(
impl_number_args
),
);
- let reported = err.emit();
- return Err(reported);
+
+ return Err(err.emit());
}
Ok(())
@@ -1295,7 +1462,7 @@ fn compare_synthetic_generics<'tcx>(
// explicit generics
(true, false) => {
err.span_label(impl_span, "expected generic parameter, found `impl Trait`");
- (|| {
+ let _: Option<_> = try {
// try taking the name from the trait impl
// FIXME: this is obviously suboptimal since the name can already be used
// as another generic argument
@@ -1328,26 +1495,23 @@ fn compare_synthetic_generics<'tcx>(
],
Applicability::MaybeIncorrect,
);
- Some(())
- })();
+ };
}
// The case where the trait method uses `impl Trait`, but the impl method uses
// explicit generics.
(false, true) => {
err.span_label(impl_span, "expected `impl Trait`, found generic parameter");
- (|| {
+ let _: Option<_> = try {
let impl_m = impl_m.def_id.as_local()?;
let impl_m = tcx.hir().expect_impl_item(impl_m);
- let input_tys = match impl_m.kind {
- hir::ImplItemKind::Fn(ref sig, _) => sig.decl.inputs,
- _ => unreachable!(),
- };
+ let hir::ImplItemKind::Fn(sig, _) = &impl_m.kind else { unreachable!() };
+ let input_tys = sig.decl.inputs;
+
struct Visitor(Option<Span>, hir::def_id::LocalDefId);
impl<'v> intravisit::Visitor<'v> for Visitor {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
intravisit::walk_ty(self, ty);
- if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) =
- ty.kind
+ if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ty.kind
&& let Res::Def(DefKind::TyParam, def_id) = path.res
&& def_id == self.1.to_def_id()
{
@@ -1355,6 +1519,7 @@ fn compare_synthetic_generics<'tcx>(
}
}
}
+
let mut visitor = Visitor(None, impl_def_id);
for ty in input_tys {
intravisit::Visitor::visit_ty(&mut visitor, ty);
@@ -1375,13 +1540,11 @@ fn compare_synthetic_generics<'tcx>(
],
Applicability::MaybeIncorrect,
);
- Some(())
- })();
+ };
}
_ => unreachable!(),
}
- let reported = err.emit();
- error_found = Some(reported);
+ error_found = Some(err.emit());
}
}
if let Some(reported) = error_found { Err(reported) } else { Ok(()) }
@@ -1482,14 +1645,15 @@ fn compare_generic_param_kinds<'tcx>(
Ok(())
}
-/// Use `tcx.compare_assoc_const_impl_item_with_trait_item` instead
-pub(crate) fn raw_compare_const_impl<'tcx>(
- tcx: TyCtxt<'tcx>,
+/// Use `tcx.compare_impl_const` instead
+pub(super) fn compare_impl_const_raw(
+ tcx: TyCtxt<'_>,
(impl_const_item_def, trait_const_item_def): (LocalDefId, DefId),
) -> Result<(), ErrorGuaranteed> {
let impl_const_item = tcx.associated_item(impl_const_item_def);
let trait_const_item = tcx.associated_item(trait_const_item_def);
- let impl_trait_ref = tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap();
+ let impl_trait_ref =
+ tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap().subst_identity();
debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
let impl_c_span = tcx.def_span(impl_const_item_def.to_def_id());
@@ -1540,10 +1704,8 @@ pub(crate) fn raw_compare_const_impl<'tcx>(
);
// Locate the Span containing just the type of the offending impl
- match tcx.hir().expect_impl_item(impl_const_item_def).kind {
- ImplItemKind::Const(ref ty, _) => cause.span = ty.span,
- _ => bug!("{:?} is not a impl const", impl_const_item),
- }
+ let ImplItemKind::Const(ty, _) = tcx.hir().expect_impl_item(impl_const_item_def).kind else { bug!("{impl_const_item:?} is not a impl const") };
+ cause.span = ty.span;
let mut diag = struct_span_err!(
tcx.sess,
@@ -1555,10 +1717,8 @@ pub(crate) fn raw_compare_const_impl<'tcx>(
let trait_c_span = trait_const_item_def.as_local().map(|trait_c_def_id| {
// Add a label to the Span containing just the type of the const
- match tcx.hir().expect_trait_item(trait_c_def_id).kind {
- TraitItemKind::Const(ref ty, _) => ty.span,
- _ => bug!("{:?} is not a trait const", trait_const_item),
- }
+ let TraitItemKind::Const(ty, _) = tcx.hir().expect_trait_item(trait_c_def_id).kind else { bug!("{trait_const_item:?} is not a trait const") };
+ ty.span
});
infcx.err_ctxt().note_type_err(
@@ -1583,13 +1743,14 @@ pub(crate) fn raw_compare_const_impl<'tcx>(
return Err(infcx.err_ctxt().report_fulfillment_errors(&errors, None));
}
- // FIXME return `ErrorReported` if region obligations error?
let outlives_environment = OutlivesEnvironment::new(param_env);
- infcx.check_region_obligations_and_report_errors(impl_const_item_def, &outlives_environment);
+ infcx
+ .err_ctxt()
+ .check_region_obligations_and_report_errors(impl_const_item_def, &outlives_environment)?;
Ok(())
}
-pub(crate) fn compare_ty_impl<'tcx>(
+pub(super) fn compare_impl_ty<'tcx>(
tcx: TyCtxt<'tcx>,
impl_ty: &ty::AssocItem,
impl_ty_span: Span,
@@ -1599,7 +1760,7 @@ pub(crate) fn compare_ty_impl<'tcx>(
) {
debug!("compare_impl_type(impl_trait_ref={:?})", impl_trait_ref);
- let _: Result<(), ErrorGuaranteed> = (|| {
+ let _: Result<(), ErrorGuaranteed> = try {
compare_number_of_generics(tcx, impl_ty, trait_ty, trait_item_span, false)?;
compare_generic_param_kinds(tcx, impl_ty, trait_ty, false)?;
@@ -1607,11 +1768,11 @@ pub(crate) fn compare_ty_impl<'tcx>(
let sp = tcx.def_span(impl_ty.def_id);
compare_type_predicate_entailment(tcx, impl_ty, sp, trait_ty, impl_trait_ref)?;
- check_type_bounds(tcx, trait_ty, impl_ty, impl_ty_span, impl_trait_ref)
- })();
+ check_type_bounds(tcx, trait_ty, impl_ty, impl_ty_span, impl_trait_ref)?;
+ };
}
-/// The equivalent of [compare_predicate_entailment], but for associated types
+/// The equivalent of [compare_method_predicate_entailment], but for associated types
/// instead of associated functions.
fn compare_type_predicate_entailment<'tcx>(
tcx: TyCtxt<'tcx>,
@@ -1630,8 +1791,7 @@ fn compare_type_predicate_entailment<'tcx>(
check_region_bounds_on_impl_item(tcx, impl_ty, trait_ty, false)?;
let impl_ty_own_bounds = impl_ty_predicates.instantiate_own(tcx, impl_substs);
-
- if impl_ty_own_bounds.is_empty() {
+ if impl_ty_own_bounds.len() == 0 {
// Nothing to check.
return Ok(());
}
@@ -1646,9 +1806,11 @@ fn compare_type_predicate_entailment<'tcx>(
// associated type in the trait are assumed.
let impl_predicates = tcx.predicates_of(impl_ty_predicates.parent.unwrap());
let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
- hybrid_preds
- .predicates
- .extend(trait_ty_predicates.instantiate_own(tcx, trait_to_impl_substs).predicates);
+ hybrid_preds.predicates.extend(
+ trait_ty_predicates
+ .instantiate_own(tcx, trait_to_impl_substs)
+ .map(|(predicate, _)| predicate),
+ );
debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds);
@@ -1664,9 +1826,7 @@ fn compare_type_predicate_entailment<'tcx>(
debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds());
- assert_eq!(impl_ty_own_bounds.predicates.len(), impl_ty_own_bounds.spans.len());
- for (span, predicate) in std::iter::zip(impl_ty_own_bounds.spans, impl_ty_own_bounds.predicates)
- {
+ for (predicate, span) in impl_ty_own_bounds {
let cause = ObligationCause::misc(span, impl_ty_hir_id);
let predicate = ocx.normalize(&cause, param_env, predicate);
@@ -1693,10 +1853,10 @@ fn compare_type_predicate_entailment<'tcx>(
// Finally, resolve all regions. This catches wily misuses of
// lifetime parameters.
let outlives_environment = OutlivesEnvironment::new(param_env);
- infcx.check_region_obligations_and_report_errors(
+ infcx.err_ctxt().check_region_obligations_and_report_errors(
impl_ty.def_id.expect_local(),
&outlives_environment,
- );
+ )?;
Ok(())
}
@@ -1715,7 +1875,7 @@ fn compare_type_predicate_entailment<'tcx>(
/// from the impl could be overridden). We also can't normalize generic
/// associated types (yet) because they contain bound parameters.
#[instrument(level = "debug", skip(tcx))]
-pub fn check_type_bounds<'tcx>(
+pub(super) fn check_type_bounds<'tcx>(
tcx: TyCtxt<'tcx>,
trait_ty: &ty::AssocItem,
impl_ty: &ty::AssocItem,
@@ -1820,8 +1980,8 @@ pub fn check_type_bounds<'tcx>(
let normalize_param_env = {
let mut predicates = param_env.caller_bounds().iter().collect::<Vec<_>>();
match impl_ty_value.kind() {
- ty::Projection(proj)
- if proj.item_def_id == trait_ty.def_id && proj.substs == rebased_substs =>
+ ty::Alias(ty::Projection, proj)
+ if proj.def_id == trait_ty.def_id && proj.substs == rebased_substs =>
{
// Don't include this predicate if the projected type is
// exactly the same as the projection. This can occur in
@@ -1832,10 +1992,7 @@ pub fn check_type_bounds<'tcx>(
_ => predicates.push(
ty::Binder::bind_with_vars(
ty::ProjectionPredicate {
- projection_ty: ty::ProjectionTy {
- item_def_id: trait_ty.def_id,
- substs: rebased_substs,
- },
+ projection_ty: tcx.mk_alias_ty(trait_ty.def_id, rebased_substs),
term: impl_ty_value.into(),
},
bound_vars,
@@ -1910,26 +2067,10 @@ pub fn check_type_bounds<'tcx>(
let outlives_environment =
OutlivesEnvironment::with_bounds(param_env, Some(&infcx), implied_bounds);
- infcx.check_region_obligations_and_report_errors(
+ infcx.err_ctxt().check_region_obligations_and_report_errors(
impl_ty.def_id.expect_local(),
&outlives_environment,
- );
-
- let constraints = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
- for (key, value) in constraints {
- infcx
- .err_ctxt()
- .report_mismatched_types(
- &ObligationCause::misc(
- value.hidden_type.span,
- tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local()),
- ),
- tcx.mk_opaque(key.def_id.to_def_id(), key.substs),
- value.hidden_type.ty,
- TypeError::Mismatch,
- )
- .emit();
- }
+ )?;
Ok(())
}
diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs
index d6e3ddb0a..64fd61c13 100644
--- a/compiler/rustc_hir_analysis/src/check/dropck.rs
+++ b/compiler/rustc_hir_analysis/src/check/dropck.rs
@@ -46,7 +46,7 @@ pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), Erro
)
}
_ => {
- // Destructors only work on nominal types. This was
+ // Destructors only work on nominal types. This was
// already checked by coherence, but compilation may
// not have been terminated.
let span = tcx.def_span(drop_impl_did);
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 69e54b41d..598dc2dca 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -75,7 +75,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: DefId) -> hir
sym::abort
| sym::assert_inhabited
| sym::assert_zero_valid
- | sym::assert_uninit_valid
+ | sym::assert_mem_uninitialized_valid
| sym::size_of
| sym::min_align_of
| sym::needs_drop
@@ -193,9 +193,9 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
}
sym::rustc_peek => (1, vec![param(0)], param(0)),
sym::caller_location => (0, vec![], tcx.caller_location_ty()),
- sym::assert_inhabited | sym::assert_zero_valid | sym::assert_uninit_valid => {
- (1, Vec::new(), tcx.mk_unit())
- }
+ sym::assert_inhabited
+ | sym::assert_zero_valid
+ | sym::assert_mem_uninitialized_valid => (1, Vec::new(), tcx.mk_unit()),
sym::forget => (1, vec![param(0)], tcx.mk_unit()),
sym::transmute => (2, vec![param(0)], param(1)),
sym::prefetch_read_data
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
index 17c4d0d48..82030d82f 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
@@ -351,7 +351,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
}
match *op {
- hir::InlineAsmOperand::In { reg, ref expr } => {
+ hir::InlineAsmOperand::In { reg, expr } => {
self.check_asm_operand_type(
idx,
reg,
@@ -362,7 +362,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
&target_features,
);
}
- hir::InlineAsmOperand::Out { reg, late: _, ref expr } => {
+ hir::InlineAsmOperand::Out { reg, late: _, expr } => {
if let Some(expr) = expr {
self.check_asm_operand_type(
idx,
@@ -375,7 +375,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
);
}
}
- hir::InlineAsmOperand::InOut { reg, late: _, ref expr } => {
+ hir::InlineAsmOperand::InOut { reg, late: _, expr } => {
self.check_asm_operand_type(
idx,
reg,
@@ -386,7 +386,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
&target_features,
);
}
- hir::InlineAsmOperand::SplitInOut { reg, late: _, ref in_expr, ref out_expr } => {
+ hir::InlineAsmOperand::SplitInOut { reg, late: _, in_expr, out_expr } => {
let in_ty = self.check_asm_operand_type(
idx,
reg,
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 29255472a..14bca34b7 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -14,23 +14,23 @@ can be broken down into several distinct phases:
- main: the main pass does the lion's share of the work: it
determines the types of all expressions, resolves
- methods, checks for most invalid conditions, and so forth. In
+ methods, checks for most invalid conditions, and so forth. In
some cases, where a type is unknown, it may create a type or region
variable and use that as the type of an expression.
In the process of checking, various constraints will be placed on
these type variables through the subtyping relationships requested
- through the `demand` module. The `infer` module is in charge
+ through the `demand` module. The `infer` module is in charge
of resolving those constraints.
- regionck: after main is complete, the regionck pass goes over all
types looking for regions and making sure that they did not escape
- into places where they are not in scope. This may also influence the
+ into places where they are not in scope. This may also influence the
final assignments of the various region variables if there is some
flexibility.
- writeback: writes the final types within a function body, replacing
- type variables with their final inferred types. These final types
+ type variables with their final inferred types. These final types
are written into the `tcx.node_types` table, which should *never* contain
any reference to a type variable.
@@ -38,8 +38,8 @@ can be broken down into several distinct phases:
While type checking a function, the intermediate types for the
expressions, blocks, and so forth contained within the function are
-stored in `fcx.node_types` and `fcx.node_substs`. These types
-may contain unresolved type variables. After type checking is
+stored in `fcx.node_types` and `fcx.node_substs`. These types
+may contain unresolved type variables. After type checking is
complete, the functions in the writeback module are used to take the
types from this table, resolve them, and then write them into their
permanent home in the type context `tcx`.
@@ -51,19 +51,19 @@ nodes within the function.
The types of top-level items, which never contain unbound type
variables, are stored directly into the `tcx` typeck_results.
-N.B., a type variable is not the same thing as a type parameter. A
+N.B., a type variable is not the same thing as a type parameter. A
type variable is an instance of a type parameter. That is,
given a generic function `fn foo<T>(t: T)`, while checking the
function `foo`, the type `ty_param(0)` refers to the type `T`, which
is treated in abstract. However, when `foo()` is called, `T` will be
-substituted for a fresh type variable `N`. This variable will
+substituted for a fresh type variable `N`. This variable will
eventually be resolved to some concrete type (which might itself be
a type parameter).
*/
mod check;
-mod compare_method;
+mod compare_impl_item;
pub mod dropck;
pub mod intrinsic;
pub mod intrinsicck;
@@ -94,7 +94,7 @@ use std::num::NonZeroU32;
use crate::require_c_abi_if_c_variadic;
use crate::util::common::indenter;
-use self::compare_method::collect_trait_impl_trait_tys;
+use self::compare_impl_item::collect_return_position_impl_trait_in_trait_tys;
use self::region::region_scope_tree;
pub fn provide(providers: &mut Providers) {
@@ -103,8 +103,8 @@ pub fn provide(providers: &mut Providers) {
adt_destructor,
check_mod_item_types,
region_scope_tree,
- collect_trait_impl_trait_tys,
- compare_assoc_const_impl_item_with_trait_item: compare_method::raw_compare_const_impl,
+ collect_return_position_impl_trait_in_trait_tys,
+ compare_impl_const: compare_impl_item::compare_impl_const_raw,
..*providers
};
}
@@ -115,10 +115,10 @@ fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> {
/// Given a `DefId` for an opaque type in return position, find its parent item's return
/// expressions.
-fn get_owner_return_paths<'tcx>(
- tcx: TyCtxt<'tcx>,
+fn get_owner_return_paths(
+ tcx: TyCtxt<'_>,
def_id: LocalDefId,
-) -> Option<(LocalDefId, ReturnsVisitor<'tcx>)> {
+) -> Option<(LocalDefId, ReturnsVisitor<'_>)> {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let parent_id = tcx.hir().get_parent_item(hir_id).def_id;
tcx.hir().find_by_def_id(parent_id).and_then(|node| node.body_id()).map(|body_id| {
@@ -352,11 +352,7 @@ fn bounds_from_generic_predicates<'tcx>(
// insert the associated types where they correspond, but for now let's be "lazy" and
// propose this instead of the following valid resugaring:
// `T: Trait, Trait::Assoc = K` → `T: Trait<Assoc = K>`
- where_clauses.push(format!(
- "{} = {}",
- tcx.def_path_str(p.projection_ty.item_def_id),
- p.term,
- ));
+ where_clauses.push(format!("{} = {}", tcx.def_path_str(p.projection_ty.def_id), p.term));
}
let where_clauses = if where_clauses.is_empty() {
String::new()
@@ -445,7 +441,7 @@ fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
ty::AssocKind::Fn => {
// We skip the binder here because the binder would deanonymize all
// late-bound regions, and we don't want method signatures to show up
- // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
+ // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
// regions just fine, showing `fn(&MyType)`.
fn_sig_suggestion(
tcx,
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index b315ebad4..b28bfb1d5 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -180,7 +180,7 @@ fn resolve_arm<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, arm: &'tcx hir
visitor.terminating_scopes.insert(arm.body.hir_id.local_id);
- if let Some(hir::Guard::If(ref expr)) = arm.guard {
+ if let Some(hir::Guard::If(expr)) = arm.guard {
visitor.terminating_scopes.insert(expr.hir_id.local_id);
}
@@ -242,8 +242,8 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
// This ensures fixed size stacks.
hir::ExprKind::Binary(
source_map::Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. },
- ref l,
- ref r,
+ l,
+ r,
) => {
// expr is a short circuiting operator (|| or &&). As its
// functionality can't be overridden by traits, it always
@@ -288,20 +288,20 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
terminating(r.hir_id.local_id);
}
}
- hir::ExprKind::If(_, ref then, Some(ref otherwise)) => {
+ hir::ExprKind::If(_, then, Some(otherwise)) => {
terminating(then.hir_id.local_id);
terminating(otherwise.hir_id.local_id);
}
- hir::ExprKind::If(_, ref then, None) => {
+ hir::ExprKind::If(_, then, None) => {
terminating(then.hir_id.local_id);
}
- hir::ExprKind::Loop(ref body, _, _, _) => {
+ hir::ExprKind::Loop(body, _, _, _) => {
terminating(body.hir_id.local_id);
}
- hir::ExprKind::DropTemps(ref expr) => {
+ hir::ExprKind::DropTemps(expr) => {
// `DropTemps(expr)` does not denote a conditional scope.
// Rather, we want to achieve the same behavior as `{ let _t = expr; _t }`.
terminating(expr.hir_id.local_id);
@@ -325,7 +325,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
// The idea is that call.callee_id represents *the time when
// the invoked function is actually running* and call.id
// represents *the time to prepare the arguments and make the
- // call*. See the section "Borrows in Calls" borrowck/README.md
+ // call*. See the section "Borrows in Calls" borrowck/README.md
// for an extended explanation of why this distinction is
// important.
//
@@ -396,7 +396,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
let body = visitor.tcx.hir().body(body);
visitor.visit_body(body);
}
- hir::ExprKind::AssignOp(_, ref left_expr, ref right_expr) => {
+ hir::ExprKind::AssignOp(_, left_expr, right_expr) => {
debug!(
"resolve_expr - enabling pessimistic_yield, was previously {}",
prev_pessimistic
@@ -447,7 +447,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
}
}
- hir::ExprKind::If(ref cond, ref then, Some(ref otherwise)) => {
+ hir::ExprKind::If(cond, then, Some(otherwise)) => {
let expr_cx = visitor.cx;
visitor.enter_scope(Scope { id: then.hir_id.local_id, data: ScopeData::IfThen });
visitor.cx.var_parent = visitor.cx.parent;
@@ -457,7 +457,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
visitor.visit_expr(otherwise);
}
- hir::ExprKind::If(ref cond, ref then, None) => {
+ hir::ExprKind::If(cond, then, None) => {
let expr_cx = visitor.cx;
visitor.enter_scope(Scope { id: then.hir_id.local_id, data: ScopeData::IfThen });
visitor.cx.var_parent = visitor.cx.parent;
@@ -641,21 +641,21 @@ fn resolve_local<'tcx>(
match pat.kind {
PatKind::Binding(hir::BindingAnnotation(hir::ByRef::Yes, _), ..) => true,
- PatKind::Struct(_, ref field_pats, _) => {
+ PatKind::Struct(_, field_pats, _) => {
field_pats.iter().any(|fp| is_binding_pat(&fp.pat))
}
- PatKind::Slice(ref pats1, ref pats2, ref pats3) => {
+ PatKind::Slice(pats1, pats2, pats3) => {
pats1.iter().any(|p| is_binding_pat(&p))
|| pats2.iter().any(|p| is_binding_pat(&p))
|| pats3.iter().any(|p| is_binding_pat(&p))
}
- PatKind::Or(ref subpats)
- | PatKind::TupleStruct(_, ref subpats, _)
- | PatKind::Tuple(ref subpats, _) => subpats.iter().any(|p| is_binding_pat(&p)),
+ PatKind::Or(subpats)
+ | PatKind::TupleStruct(_, subpats, _)
+ | PatKind::Tuple(subpats, _) => subpats.iter().any(|p| is_binding_pat(&p)),
- PatKind::Box(ref subpat) => is_binding_pat(&subpat),
+ PatKind::Box(subpat) => is_binding_pat(&subpat),
PatKind::Ref(_, _)
| PatKind::Binding(hir::BindingAnnotation(hir::ByRef::No, _), ..)
@@ -704,11 +704,11 @@ fn resolve_local<'tcx>(
record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id);
}
}
- hir::ExprKind::Cast(ref subexpr, _) => {
+ hir::ExprKind::Cast(subexpr, _) => {
record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id)
}
- hir::ExprKind::Block(ref block, _) => {
- if let Some(ref subexpr) = block.expr {
+ hir::ExprKind::Block(block, _) => {
+ if let Some(subexpr) = block.expr {
record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id);
}
}
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index b065ace6b..11237afe8 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1,4 +1,6 @@
+use crate::autoderef::Autoderef;
use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
+
use hir::def::DefKind;
use rustc_ast as ast;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
@@ -22,7 +24,6 @@ use rustc_session::parse::feature_err;
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::autoderef::Autoderef;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
@@ -31,8 +32,6 @@ use rustc_trait_selection::traits::{
};
use std::cell::LazyCell;
-use std::convert::TryInto;
-use std::iter;
use std::ops::{ControlFlow, Deref};
pub(super) struct WfCheckingCtxt<'a, 'tcx> {
@@ -98,25 +97,28 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
let infcx = &tcx.infer_ctxt().build();
let ocx = ObligationCtxt::new(infcx);
- let assumed_wf_types = ocx.assumed_wf_types(param_env, span, body_def_id);
-
let mut wfcx = WfCheckingCtxt { ocx, span, body_id, param_env };
if !tcx.features().trivial_bounds {
wfcx.check_false_global_bounds()
}
f(&mut wfcx);
+
+ let assumed_wf_types = wfcx.ocx.assumed_wf_types(param_env, span, body_def_id);
+ let implied_bounds = infcx.implied_bounds_tys(param_env, body_id, assumed_wf_types);
+
let errors = wfcx.select_all_or_error();
if !errors.is_empty() {
infcx.err_ctxt().report_fulfillment_errors(&errors, None);
return;
}
- let implied_bounds = infcx.implied_bounds_tys(param_env, body_id, assumed_wf_types);
let outlives_environment =
OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
- infcx.check_region_obligations_and_report_errors(body_def_id, &outlives_environment);
+ let _ = infcx
+ .err_ctxt()
+ .check_region_obligations_and_report_errors(body_def_id, &outlives_environment);
}
fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) {
@@ -176,10 +178,10 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
//
// won't be allowed unless there's an *explicit* implementation of `Send`
// for `T`
- hir::ItemKind::Impl(ref impl_) => {
+ hir::ItemKind::Impl(impl_) => {
let is_auto = tcx
.impl_trait_ref(def_id)
- .map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.def_id));
+ .map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.skip_binder().def_id));
if let (hir::Defaultness::Default { .. }, true) = (impl_.defaultness, is_auto) {
let sp = impl_.of_trait.as_ref().map_or(item.span, |t| t.path.span);
let mut err =
@@ -222,15 +224,15 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
hir::ItemKind::Const(ty, ..) => {
check_item_type(tcx, def_id, ty.span, false);
}
- hir::ItemKind::Struct(_, ref ast_generics) => {
+ hir::ItemKind::Struct(_, ast_generics) => {
check_type_defn(tcx, item, false);
check_variances_for_type_defn(tcx, item, ast_generics);
}
- hir::ItemKind::Union(_, ref ast_generics) => {
+ hir::ItemKind::Union(_, ast_generics) => {
check_type_defn(tcx, item, true);
check_variances_for_type_defn(tcx, item, ast_generics);
}
- hir::ItemKind::Enum(_, ref ast_generics) => {
+ hir::ItemKind::Enum(_, ast_generics) => {
check_type_defn(tcx, item, true);
check_variances_for_type_defn(tcx, item, ast_generics);
}
@@ -292,7 +294,7 @@ fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) {
// Do some rudimentary sanity checking to avoid an ICE later (issue #83471).
if let Some(hir::FnSig { decl, span, .. }) = method_sig {
if let [self_ty, _] = decl.inputs {
- if !matches!(self_ty.kind, hir::TyKind::Rptr(_, _)) {
+ if !matches!(self_ty.kind, hir::TyKind::Ref(_, _)) {
tcx.sess
.struct_span_err(
self_ty.span,
@@ -411,10 +413,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
tcx,
param_env,
item_hir_id,
- tcx.explicit_item_bounds(item_def_id)
- .iter()
- .copied()
- .collect::<Vec<_>>(),
+ tcx.explicit_item_bounds(item_def_id).to_vec(),
&FxIndexSet::default(),
gat_def_id.def_id,
gat_generics,
@@ -760,7 +759,7 @@ impl<'tcx> TypeVisitor<'tcx> for GATSubstCollector<'tcx> {
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match t.kind() {
- ty::Projection(p) if p.item_def_id == self.gat => {
+ ty::Alias(ty::Projection, p) if p.def_id == self.gat => {
for (idx, subst) in p.substs.iter().enumerate() {
match subst.unpack() {
GenericArgKind::Lifetime(lt) if !lt.is_late_bound() => {
@@ -1248,13 +1247,17 @@ fn check_impl<'tcx>(
constness: hir::Constness,
) {
enter_wf_checking_ctxt(tcx, item.span, item.owner_id.def_id, |wfcx| {
- match *ast_trait_ref {
- Some(ref ast_trait_ref) => {
+ match ast_trait_ref {
+ Some(ast_trait_ref) => {
// `#[rustc_reservation_impl]` impls are not real impls and
// therefore don't need to be WF (the trait's `Self: Trait` predicate
// won't hold).
- let trait_ref = tcx.impl_trait_ref(item.owner_id).unwrap();
- let trait_ref = wfcx.normalize(ast_trait_ref.path.span, None, trait_ref);
+ let trait_ref = tcx.impl_trait_ref(item.owner_id).unwrap().subst_identity();
+ let trait_ref = wfcx.normalize(
+ ast_trait_ref.path.span,
+ Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
+ trait_ref,
+ );
let trait_pred = ty::TraitPredicate {
trait_ref,
constness: match constness {
@@ -1263,7 +1266,7 @@ fn check_impl<'tcx>(
},
polarity: ty::ImplPolarity::Positive,
};
- let obligations = traits::wf::trait_obligations(
+ let mut obligations = traits::wf::trait_obligations(
wfcx.infcx,
wfcx.param_env,
wfcx.body_id,
@@ -1271,6 +1274,13 @@ fn check_impl<'tcx>(
ast_trait_ref.path.span,
item,
);
+ for obligation in &mut obligations {
+ if let Some(pred) = obligation.predicate.to_opt_poly_trait_pred()
+ && pred.self_ty().skip_binder() == trait_ref.self_ty()
+ {
+ obligation.cause.span = ast_self_ty.span;
+ }
+ }
debug!(?obligations);
wfcx.register_obligations(obligations);
}
@@ -1299,7 +1309,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
let infcx = wfcx.infcx;
let tcx = wfcx.tcx();
- let predicates = tcx.bound_predicates_of(def_id.to_def_id());
+ let predicates = tcx.predicates_of(def_id.to_def_id());
let generics = tcx.generics_of(def_id);
let is_our_default = |def: &ty::GenericParamDef| match def.kind {
@@ -1339,7 +1349,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
// is incorrect when dealing with unused substs, for example
// for `struct Foo<const N: usize, const M: usize = { 1 - 2 }>`
// we should eagerly error.
- let default_ct = tcx.const_param_default(param.def_id);
+ let default_ct = tcx.const_param_default(param.def_id).subst_identity();
if !default_ct.needs_subst() {
wfcx.register_wf_obligation(
tcx.def_span(param.def_id),
@@ -1385,7 +1395,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
GenericParamDefKind::Const { .. } => {
// If the param has a default, ...
if is_our_default(param) {
- let default_ct = tcx.const_param_default(param.def_id);
+ let default_ct = tcx.const_param_default(param.def_id).subst_identity();
// ... and it's not a dependent default, ...
if !default_ct.needs_subst() {
// ... then substitute it with the default.
@@ -1400,7 +1410,6 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
// Now we build the substituted predicates.
let default_obligations = predicates
- .0
.predicates
.iter()
.flat_map(|&(pred, sp)| {
@@ -1419,7 +1428,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
}
fn visit_region(&mut self, _: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
- ControlFlow::BREAK
+ ControlFlow::Break(())
}
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
@@ -1431,13 +1440,13 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
}
let mut param_count = CountParams::default();
let has_region = pred.visit_with(&mut param_count).is_break();
- let substituted_pred = predicates.rebind(pred).subst(tcx, substs);
+ let substituted_pred = ty::EarlyBinder(pred).subst(tcx, substs);
// Don't check non-defaulted params, dependent defaults (including lifetimes)
// or preds with multiple params.
if substituted_pred.has_non_region_param() || param_count.params.len() > 1 || has_region
{
None
- } else if predicates.0.predicates.iter().any(|&(p, _)| p == substituted_pred) {
+ } else if predicates.predicates.iter().any(|&(p, _)| p == substituted_pred) {
// Avoid duplication of predicates that contain no parameters, for example.
None
} else {
@@ -1463,22 +1472,21 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
traits::Obligation::new(tcx, cause, wfcx.param_env, pred)
});
- let predicates = predicates.0.instantiate_identity(tcx);
+ let predicates = predicates.instantiate_identity(tcx);
let predicates = wfcx.normalize(span, None, predicates);
debug!(?predicates.predicates);
assert_eq!(predicates.predicates.len(), predicates.spans.len());
- let wf_obligations =
- iter::zip(&predicates.predicates, &predicates.spans).flat_map(|(&p, &sp)| {
- traits::wf::predicate_obligations(
- infcx,
- wfcx.param_env.without_const(),
- wfcx.body_id,
- p,
- sp,
- )
- });
+ let wf_obligations = predicates.into_iter().flat_map(|(p, sp)| {
+ traits::wf::predicate_obligations(
+ infcx,
+ wfcx.param_env.without_const(),
+ wfcx.body_id,
+ p,
+ sp,
+ )
+ });
let obligations: Vec<_> = wf_obligations.chain(default_obligations).collect();
wfcx.register_obligations(obligations);
@@ -1493,54 +1501,38 @@ fn check_fn_or_method<'tcx>(
def_id: LocalDefId,
) {
let tcx = wfcx.tcx();
- let sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig);
+ let mut sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig);
// Normalize the input and output types one at a time, using a different
// `WellFormedLoc` for each. We cannot call `normalize_associated_types`
// on the entire `FnSig`, since this would use the same `WellFormedLoc`
// for each type, preventing the HIR wf check from generating
// a nice error message.
- let ty::FnSig { mut inputs_and_output, c_variadic, unsafety, abi } = sig;
- inputs_and_output = tcx.mk_type_list(inputs_and_output.iter().enumerate().map(|(i, ty)| {
- wfcx.normalize(
- span,
- Some(WellFormedLoc::Param {
- function: def_id,
- // Note that the `param_idx` of the output type is
- // one greater than the index of the last input type.
- param_idx: i.try_into().unwrap(),
- }),
- ty,
- )
- }));
- // Manually call `normalize_associated_types_in` on the other types
- // in `FnSig`. This ensures that if the types of these fields
- // ever change to include projections, we will start normalizing
- // them automatically.
- let sig = ty::FnSig {
- inputs_and_output,
- c_variadic: wfcx.normalize(span, None, c_variadic),
- unsafety: wfcx.normalize(span, None, unsafety),
- abi: wfcx.normalize(span, None, abi),
- };
+ let arg_span =
+ |idx| hir_decl.inputs.get(idx).map_or(hir_decl.output.span(), |arg: &hir::Ty<'_>| arg.span);
+
+ sig.inputs_and_output =
+ tcx.mk_type_list(sig.inputs_and_output.iter().enumerate().map(|(idx, ty)| {
+ wfcx.normalize(
+ arg_span(idx),
+ Some(WellFormedLoc::Param {
+ function: def_id,
+ // Note that the `param_idx` of the output type is
+ // one greater than the index of the last input type.
+ param_idx: idx.try_into().unwrap(),
+ }),
+ ty,
+ )
+ }));
- for (i, (&input_ty, ty)) in iter::zip(sig.inputs(), hir_decl.inputs).enumerate() {
+ for (idx, ty) in sig.inputs_and_output.iter().enumerate() {
wfcx.register_wf_obligation(
- ty.span,
- Some(WellFormedLoc::Param { function: def_id, param_idx: i.try_into().unwrap() }),
- input_ty.into(),
+ arg_span(idx),
+ Some(WellFormedLoc::Param { function: def_id, param_idx: idx.try_into().unwrap() }),
+ ty.into(),
);
}
- wfcx.register_wf_obligation(
- hir_decl.output.span(),
- Some(WellFormedLoc::Param {
- function: def_id,
- param_idx: sig.inputs().len().try_into().unwrap(),
- }),
- sig.output().into(),
- );
-
check_where_clauses(wfcx, span, def_id);
check_return_position_impl_trait_in_trait_bounds(
@@ -1593,12 +1585,12 @@ fn check_return_position_impl_trait_in_trait_bounds<'tcx>(
{
for arg in fn_output.walk() {
if let ty::GenericArgKind::Type(ty) = arg.unpack()
- && let ty::Projection(proj) = ty.kind()
- && tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder
- && tcx.impl_trait_in_trait_parent(proj.item_def_id) == fn_def_id.to_def_id()
+ && let ty::Alias(ty::Projection, proj) = ty.kind()
+ && tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder
+ && tcx.impl_trait_in_trait_parent(proj.def_id) == fn_def_id.to_def_id()
{
- let span = tcx.def_span(proj.item_def_id);
- let bounds = wfcx.tcx().explicit_item_bounds(proj.item_def_id);
+ let span = tcx.def_span(proj.def_id);
+ let bounds = wfcx.tcx().explicit_item_bounds(proj.def_id);
let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| {
let bound = ty::EarlyBinder(bound).subst(tcx, proj.substs);
let normalized_bound = wfcx.normalize(span, None, bound);
@@ -1674,7 +1666,7 @@ fn check_method_receiver<'tcx>(
}
}
-fn e0307<'tcx>(tcx: TyCtxt<'tcx>, span: Span, receiver_ty: Ty<'_>) {
+fn e0307(tcx: TyCtxt<'_>, span: Span, receiver_ty: Ty<'_>) {
struct_span_err!(
tcx.sess.diagnostic(),
span,
@@ -1916,7 +1908,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
}
let pred = obligation.predicate;
// Match the existing behavior.
- if pred.is_global() && !pred.has_late_bound_regions() {
+ if pred.is_global() && !pred.has_late_bound_vars() {
let pred = self.normalize(span, None, pred);
let hir_node = tcx.hir().find(self.body_id);
diff --git a/compiler/rustc_hir_analysis/src/check_unused.rs b/compiler/rustc_hir_analysis/src/check_unused.rs
index 5749b0478..ebb78213a 100644
--- a/compiler/rustc_hir_analysis/src/check_unused.rs
+++ b/compiler/rustc_hir_analysis/src/check_unused.rs
@@ -50,7 +50,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
fn unused_crates_lint(tcx: TyCtxt<'_>) {
let lint = lint::builtin::UNUSED_EXTERN_CRATES;
- // Collect first the crates that are completely unused. These we
+ // Collect first the crates that are completely unused. These we
// can always suggest removing (no matter which edition we are
// in).
let unused_extern_crates: FxHashMap<LocalDefId, Span> = tcx
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 193ecdb16..28c040878 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -7,13 +7,15 @@ use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::lang_items::LangItem;
use rustc_hir::ItemKind;
-use rustc_infer::infer;
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::infer::{self, RegionResolutionError};
use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitable};
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
-use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError};
+use rustc_trait_selection::traits::misc::{
+ type_allowed_to_implement_copy, CopyImplementationError, InfringingFieldsReason,
+};
use rustc_trait_selection::traits::predicate_for_trait_def;
use rustc_trait_selection::traits::{self, ObligationCause};
use std::collections::BTreeMap;
@@ -54,12 +56,9 @@ fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
_ => {}
}
- let sp = match tcx.hir().expect_item(impl_did).kind {
- ItemKind::Impl(ref impl_) => impl_.self_ty.span,
- _ => bug!("expected Drop impl item"),
- };
+ let ItemKind::Impl(impl_) = tcx.hir().expect_item(impl_did).kind else { bug!("expected Drop impl item") };
- tcx.sess.emit_err(DropImplOnWrongItem { span: sp });
+ tcx.sess.emit_err(DropImplOnWrongItem { span: impl_.self_ty.span });
}
fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
@@ -82,7 +81,7 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
};
let cause = traits::ObligationCause::misc(span, impl_hir_id);
- match can_type_implement_copy(tcx, param_env, self_type, cause) {
+ match type_allowed_to_implement_copy(tcx, param_env, self_type, cause) {
Ok(()) => {}
Err(CopyImplementationError::InfrigingFields(fields)) => {
let mut err = struct_span_err!(
@@ -97,50 +96,70 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
let mut errors: BTreeMap<_, Vec<_>> = Default::default();
let mut bounds = vec![];
- for (field, ty) in fields {
+ for (field, ty, reason) in fields {
let field_span = tcx.def_span(field.did);
- let field_ty_span = match tcx.hir().get_if_local(field.did) {
- Some(hir::Node::Field(field_def)) => field_def.ty.span,
- _ => field_span,
- };
err.span_label(field_span, "this field does not implement `Copy`");
- // Spin up a new FulfillmentContext, so we can get the _precise_ reason
- // why this field does not implement Copy. This is useful because sometimes
- // it is not immediately clear why Copy is not implemented for a field, since
- // all we point at is the field itself.
- let infcx = tcx.infer_ctxt().ignoring_regions().build();
- for error in traits::fully_solve_bound(
- &infcx,
- traits::ObligationCause::dummy_with_span(field_ty_span),
- param_env,
- ty,
- tcx.require_lang_item(LangItem::Copy, Some(span)),
- ) {
- let error_predicate = error.obligation.predicate;
- // Only note if it's not the root obligation, otherwise it's trivial and
- // should be self-explanatory (i.e. a field literally doesn't implement Copy).
-
- // FIXME: This error could be more descriptive, especially if the error_predicate
- // contains a foreign type or if it's a deeply nested type...
- if error_predicate != error.root_obligation.predicate {
- errors
- .entry((ty.to_string(), error_predicate.to_string()))
- .or_default()
- .push(error.obligation.cause.span);
+
+ match reason {
+ InfringingFieldsReason::Fulfill(fulfillment_errors) => {
+ for error in fulfillment_errors {
+ let error_predicate = error.obligation.predicate;
+ // Only note if it's not the root obligation, otherwise it's trivial and
+ // should be self-explanatory (i.e. a field literally doesn't implement Copy).
+
+ // FIXME: This error could be more descriptive, especially if the error_predicate
+ // contains a foreign type or if it's a deeply nested type...
+ if error_predicate != error.root_obligation.predicate {
+ errors
+ .entry((ty.to_string(), error_predicate.to_string()))
+ .or_default()
+ .push(error.obligation.cause.span);
+ }
+ if let ty::PredicateKind::Clause(ty::Clause::Trait(
+ ty::TraitPredicate {
+ trait_ref,
+ polarity: ty::ImplPolarity::Positive,
+ ..
+ },
+ )) = error_predicate.kind().skip_binder()
+ {
+ let ty = trait_ref.self_ty();
+ if let ty::Param(_) = ty.kind() {
+ bounds.push((
+ format!("{ty}"),
+ trait_ref.print_only_trait_path().to_string(),
+ Some(trait_ref.def_id),
+ ));
+ }
+ }
+ }
}
- if let ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate {
- trait_ref,
- polarity: ty::ImplPolarity::Positive,
- ..
- })) = error_predicate.kind().skip_binder()
- {
- let ty = trait_ref.self_ty();
- if let ty::Param(_) = ty.kind() {
- bounds.push((
- format!("{ty}"),
- trait_ref.print_only_trait_path().to_string(),
- Some(trait_ref.def_id),
- ));
+ InfringingFieldsReason::Regions(region_errors) => {
+ for error in region_errors {
+ let ty = ty.to_string();
+ match error {
+ RegionResolutionError::ConcreteFailure(origin, a, b) => {
+ let predicate = format!("{b}: {a}");
+ errors
+ .entry((ty.clone(), predicate.clone()))
+ .or_default()
+ .push(origin.span());
+ if let ty::RegionKind::ReEarlyBound(ebr) = *b && ebr.has_name() {
+ bounds.push((b.to_string(), a.to_string(), None));
+ }
+ }
+ RegionResolutionError::GenericBoundFailure(origin, a, b) => {
+ let predicate = format!("{a}: {b}");
+ errors
+ .entry((ty.clone(), predicate.clone()))
+ .or_default()
+ .push(origin.span());
+ if let infer::region_constraints::GenericKind::Param(_) = a {
+ bounds.push((a.to_string(), b.to_string(), None));
+ }
+ }
+ _ => continue,
+ }
}
}
}
@@ -171,7 +190,7 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
}
}
-fn visit_implementation_of_coerce_unsized<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) {
+fn visit_implementation_of_coerce_unsized(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did);
// Just compute this for the side-effects, in particular reporting
@@ -181,7 +200,7 @@ fn visit_implementation_of_coerce_unsized<'tcx>(tcx: TyCtxt<'tcx>, impl_did: Loc
tcx.at(span).coerce_unsized_info(impl_did);
}
-fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) {
+fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did);
let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
@@ -192,7 +211,7 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did:
let source = tcx.type_of(impl_did);
assert!(!source.has_escaping_bound_vars());
let target = {
- let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
+ let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().subst_identity();
assert_eq!(trait_ref.def_id, dispatch_from_dyn_trait);
trait_ref.substs.type_at(1)
@@ -325,7 +344,9 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did:
// Finally, resolve all regions.
let outlives_env = OutlivesEnvironment::new(param_env);
- infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env);
+ let _ = infcx
+ .err_ctxt()
+ .check_region_obligations_and_report_errors(impl_did, &outlives_env);
}
}
_ => {
@@ -352,7 +373,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
});
let source = tcx.type_of(impl_did);
- let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
+ let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().subst_identity();
assert_eq!(trait_ref.def_id, coerce_unsized_trait);
let target = trait_ref.substs.type_at(1);
debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target);
@@ -436,7 +457,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
// when this coercion occurs, we would be changing the
// field `ptr` from a thin pointer of type `*mut [i32;
// 3]` to a fat pointer of type `*mut [i32]` (with
- // extra data `3`). **The purpose of this check is to
+ // extra data `3`). **The purpose of this check is to
// make sure that we know how to do this conversion.**
//
// To check if this impl is legal, we would walk down
@@ -503,12 +524,11 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
return err_info;
} else if diff_fields.len() > 1 {
let item = tcx.hir().expect_item(impl_did);
- let span =
- if let ItemKind::Impl(hir::Impl { of_trait: Some(ref t), .. }) = item.kind {
- t.path.span
- } else {
- tcx.def_span(impl_did)
- };
+ let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(t), .. }) = &item.kind {
+ t.path.span
+ } else {
+ tcx.def_span(impl_did)
+ };
struct_span_err!(
tcx.sess,
@@ -565,7 +585,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
// Finally, resolve all regions.
let outlives_env = OutlivesEnvironment::new(param_env);
- infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env);
+ let _ = infcx.err_ctxt().check_region_obligations_and_report_errors(impl_did, &outlives_env);
CoerceUnsizedInfo { custom_kind: kind }
}
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index 2890c149b..dfb982409 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -182,7 +182,7 @@ impl<'tcx> InherentCollect<'tcx> {
}
let item = self.tcx.hir().item(id);
- let hir::ItemKind::Impl(hir::Impl { of_trait: None, self_ty: ty, ref items, .. }) = item.kind else {
+ let hir::ItemKind::Impl(hir::Impl { of_trait: None, self_ty: ty, items, .. }) = item.kind else {
return;
};
@@ -223,7 +223,7 @@ impl<'tcx> InherentCollect<'tcx> {
| ty::Tuple(..) => {
self.check_primitive_impl(item.owner_id.def_id, self_ty, items, ty.span)
}
- ty::Projection(..) | ty::Opaque(..) | ty::Param(_) => {
+ ty::Alias(..) | ty::Param(_) => {
let mut err = struct_span_err!(
self.tcx.sess,
ty.span,
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
index 972769eb1..a9331af4e 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
@@ -198,10 +198,10 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
// entire graph when there are many connected regions.
rustc_index::newtype_index! {
- pub struct RegionId {
- ENCODABLE = custom
- }
+ #[custom_encodable]
+ pub struct RegionId {}
}
+
struct ConnectedRegion {
idents: SmallVec<[Symbol; 8]>,
impl_blocks: FxHashSet<usize>,
diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs
index 1bf3768fe..d3b5778ba 100644
--- a/compiler/rustc_hir_analysis/src/coherence/mod.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs
@@ -128,7 +128,7 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) {
let impls = tcx.hir().trait_impls(def_id);
for &impl_def_id in impls {
- let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+ let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity();
check_impl(tcx, impl_def_id, trait_ref);
check_object_overlap(tcx, impl_def_id, trait_ref);
@@ -171,7 +171,7 @@ fn check_object_overlap<'tcx>(
for component_def_id in component_def_ids {
if !tcx.is_object_safe(component_def_id) {
// Without the 'object_safe_for_dispatch' feature this is an error
- // which will be reported by wfcheck. Ignore it here.
+ // which will be reported by wfcheck. Ignore it here.
// This is tested by `coherence-impl-trait-for-trait-object-safe.rs`.
// With the feature enabled, the trait is not implemented automatically,
// so this is valid.
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index cc5114dba..95b03eb82 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -21,7 +21,7 @@ pub(crate) fn orphan_check_impl(
tcx: TyCtxt<'_>,
impl_def_id: LocalDefId,
) -> Result<(), ErrorGuaranteed> {
- let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+ let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity();
trait_ref.error_reported()?;
let ret = do_orphan_check_impl(tcx, trait_ref, impl_def_id);
@@ -40,7 +40,7 @@ fn do_orphan_check_impl<'tcx>(
let trait_def_id = trait_ref.def_id;
let item = tcx.hir().expect_item(def_id);
- let hir::ItemKind::Impl(ref impl_) = item.kind else {
+ let hir::ItemKind::Impl(impl_) = item.kind else {
bug!("{:?} is not an impl: {:?}", def_id, item);
};
let sp = tcx.def_span(def_id);
@@ -53,7 +53,7 @@ fn do_orphan_check_impl<'tcx>(
sp,
item.span,
tr.path.span,
- trait_ref.self_ty(),
+ trait_ref,
impl_.self_ty.span,
&impl_.generics,
err,
@@ -154,11 +154,12 @@ fn emit_orphan_check_error<'tcx>(
sp: Span,
full_impl_span: Span,
trait_span: Span,
- self_ty: Ty<'tcx>,
+ trait_ref: ty::TraitRef<'tcx>,
self_ty_span: Span,
generics: &hir::Generics<'tcx>,
err: traits::OrphanCheckErr<'tcx>,
) -> Result<!, ErrorGuaranteed> {
+ let self_ty = trait_ref.self_ty();
Err(match err {
traits::OrphanCheckErr::NonLocalInputType(tys) => {
let msg = match self_ty.kind() {
@@ -184,11 +185,26 @@ fn emit_orphan_check_error<'tcx>(
ty::Adt(def, _) => tcx.mk_adt(*def, ty::List::empty()),
_ => ty,
};
- let this = "this".to_string();
- let (ty, postfix) = match &ty.kind() {
- ty::Slice(_) => (this, " because slices are always foreign"),
- ty::Array(..) => (this, " because arrays are always foreign"),
- ty::Tuple(..) => (this, " because tuples are always foreign"),
+ let msg = |ty: &str, postfix: &str| {
+ format!("{ty} is not defined in the current crate{postfix}")
+ };
+
+ let this = |name: &str| {
+ if !trait_ref.def_id.is_local() && !is_target_ty {
+ msg("this", &format!(" because this is a foreign trait"))
+ } else {
+ msg("this", &format!(" because {name} are always foreign"))
+ }
+ };
+ let msg = match &ty.kind() {
+ ty::Slice(_) => this("slices"),
+ ty::Array(..) => this("arrays"),
+ ty::Tuple(..) => this("tuples"),
+ ty::Alias(ty::Opaque, ..) => {
+ "type alias impl trait is treated as if it were foreign, \
+ because its hidden type could be from a foreign crate"
+ .to_string()
+ }
ty::RawPtr(ptr_ty) => {
emit_newtype_suggestion_for_raw_ptr(
full_impl_span,
@@ -198,12 +214,11 @@ fn emit_orphan_check_error<'tcx>(
&mut err,
);
- (format!("`{}`", ty), " because raw pointers are always foreign")
+ msg(&format!("`{ty}`"), " because raw pointers are always foreign")
}
- _ => (format!("`{}`", ty), ""),
+ _ => msg(&format!("`{ty}`"), ""),
};
- let msg = format!("{} is not defined in the current crate{}", ty, postfix);
if is_target_ty {
// Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
err.span_label(self_ty_span, &msg);
@@ -401,13 +416,13 @@ fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty:
if t != self.self_ty_root {
for impl_def_id in tcx.non_blanket_impls_for_ty(self.trait_def_id, t) {
match tcx.impl_polarity(impl_def_id) {
- ImplPolarity::Negative => return ControlFlow::BREAK,
+ ImplPolarity::Negative => return ControlFlow::Break(()),
ImplPolarity::Reservation => {}
// FIXME(@lcnr): That's probably not good enough, idk
//
// We might just want to take the rustdoc code and somehow avoid
// explicit impls for `Self`.
- ImplPolarity::Positive => return ControlFlow::CONTINUE,
+ ImplPolarity::Positive => return ControlFlow::Continue(()),
}
}
}
@@ -425,7 +440,7 @@ fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty:
}
}
- ControlFlow::CONTINUE
+ ControlFlow::Continue(())
}
_ => t.super_visit_with(self),
}
diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
index a34815b45..fe6119dce 100644
--- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
@@ -11,9 +11,10 @@ use rustc_span::def_id::LocalDefId;
pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Impl));
let item = tcx.hir().expect_item(def_id);
- let hir::ItemKind::Impl(ref impl_) = item.kind else { bug!() };
+ let hir::ItemKind::Impl(impl_) = item.kind else { bug!() };
if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) {
+ let trait_ref = trait_ref.subst_identity();
let trait_def = tcx.trait_def(trait_ref.def_id);
let unsafe_attr =
impl_.generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle");
@@ -21,7 +22,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
(Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => {
struct_span_err!(
tcx.sess,
- item.span,
+ tcx.def_span(def_id),
E0199,
"implementing the trait `{}` is not unsafe",
trait_ref.print_only_trait_path()
@@ -38,7 +39,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
(Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => {
struct_span_err!(
tcx.sess,
- item.span,
+ tcx.def_span(def_id),
E0200,
"the trait `{}` requires an `unsafe impl` declaration",
trait_ref.print_only_trait_path()
@@ -61,7 +62,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
(Unsafety::Normal, Some(attr_name), Unsafety::Normal, hir::ImplPolarity::Positive) => {
struct_span_err!(
tcx.sess,
- item.span,
+ tcx.def_span(def_id),
E0569,
"requires an `unsafe impl` declaration due to `#[{}]` attribute",
attr_name
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 1183a26d5..c17778ce8 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -17,29 +17,26 @@
use crate::astconv::AstConv;
use crate::check::intrinsic::intrinsic_operation_unsafety;
use crate::errors;
-use rustc_ast as ast;
-use rustc_ast::{MetaItemKind, NestedMetaItem};
-use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
+use hir::def::DefKind;
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey};
use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
-use rustc_hir::{lang_items, GenericParamKind, LangItem, Node};
+use rustc_hir::{GenericParamKind, Node};
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::traits::ObligationCause;
use rustc_middle::hir::nested_filter;
-use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
-use rustc_middle::mir::mono::Linkage;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::util::{Discr, IntTypeExt};
-use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, IsSuggestable, ToPredicate, Ty, TyCtxt};
-use rustc_session::lint;
-use rustc_session::parse::feature_err;
+use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, ToPredicate, Ty, TyCtxt};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
-use rustc_target::spec::{abi, SanitizerSet};
+use rustc_target::spec::abi;
+use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
+use rustc_trait_selection::traits::ObligationCtxt;
use std::iter;
mod generics_of;
@@ -78,10 +75,7 @@ pub fn provide(providers: &mut Providers) {
impl_polarity,
is_foreign_item,
generator_kind,
- codegen_fn_attrs,
- asm_target_features,
collect_mod_item_types,
- should_inherit_track_caller,
is_type_alias_impl_trait,
..*providers
};
@@ -220,7 +214,7 @@ pub(crate) fn placeholder_type_error_diag<'tcx>(
is_fn = true;
// Check if parent is const or static
- let parent_id = tcx.hir().get_parent_node(hir_ty.hir_id);
+ let parent_id = tcx.hir().parent_id(hir_ty.hir_id);
let parent_node = tcx.hir().get(parent_id);
is_const_or_static = matches!(
@@ -358,7 +352,7 @@ impl<'tcx> ItemCtxt<'tcx> {
}
pub fn to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
- <dyn AstConv<'_>>::ast_ty_to_ty(self, ast_ty)
+ self.astconv().ast_ty_to_ty(ast_ty)
}
pub fn hir_id(&self) -> hir::HirId {
@@ -420,8 +414,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
poly_trait_ref: ty::PolyTraitRef<'tcx>,
) -> Ty<'tcx> {
if let Some(trait_ref) = poly_trait_ref.no_bound_vars() {
- let item_substs = <dyn AstConv<'tcx>>::create_substs_for_associated_item(
- self,
+ let item_substs = self.astconv().create_substs_for_associated_item(
span,
item_def_id,
item_segment,
@@ -501,7 +494,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
format!(
"{}::",
// Erase named lt, we want `<A as B<'_>::C`, not `<A as B<'a>::C`.
- self.tcx.anonymize_late_bound_regions(poly_trait_ref).skip_binder(),
+ self.tcx.anonymize_bound_vars(poly_trait_ref).skip_binder(),
),
Applicability::MaybeIncorrect,
);
@@ -512,9 +505,9 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
}
}
- fn normalize_ty(&self, _span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
- // Types in item signatures are not normalized to avoid undue dependencies.
- ty
+ fn probe_adt(&self, _span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>> {
+ // FIXME(#103640): Should we handle the case where `ty` is a projection?
+ ty.ty_adt_def()
}
fn set_tainted_by_errors(&self, _: ErrorGuaranteed) {
@@ -568,7 +561,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
debug!("convert: item {} with id {}", it.ident, it.hir_id());
let def_id = item_id.owner_id.def_id;
- match it.kind {
+ match &it.kind {
// These don't define types.
hir::ItemKind::ExternCrate(_)
| hir::ItemKind::Use(..)
@@ -576,7 +569,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
| hir::ItemKind::Mod(_)
| hir::ItemKind::GlobalAsm(_) => {}
hir::ItemKind::ForeignMod { items, .. } => {
- for item in items {
+ for item in *items {
let item = tcx.hir().foreign_item(item.id);
tcx.ensure().generics_of(item.owner_id);
tcx.ensure().type_of(item.owner_id);
@@ -626,7 +619,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
tcx.at(it.span).super_predicates_of(def_id);
tcx.ensure().predicates_of(def_id);
}
- hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
+ hir::ItemKind::Struct(struct_def, _) | hir::ItemKind::Union(struct_def, _) => {
tcx.ensure().generics_of(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure().predicates_of(def_id);
@@ -851,7 +844,7 @@ fn convert_variant(
)
}
-fn adt_def<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::AdtDef<'tcx> {
+fn adt_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtDef<'_> {
use rustc_hir::*;
let def_id = def_id.expect_local();
@@ -861,14 +854,14 @@ fn adt_def<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::AdtDef<'tcx> {
};
let repr = tcx.repr_options_of_def(def_id.to_def_id());
- let (kind, variants) = match item.kind {
- ItemKind::Enum(ref def, _) => {
+ let (kind, variants) = match &item.kind {
+ ItemKind::Enum(def, _) => {
let mut distance_from_explicit = 0;
let variants = def
.variants
.iter()
.map(|v| {
- let discr = if let Some(ref e) = v.disr_expr {
+ let discr = if let Some(e) = &v.disr_expr {
distance_from_explicit = 0;
ty::VariantDiscr::Explicit(e.def_id.to_def_id())
} else {
@@ -890,7 +883,7 @@ fn adt_def<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::AdtDef<'tcx> {
(AdtKind::Enum, variants)
}
- ItemKind::Struct(ref def, _) | ItemKind::Union(ref def, _) => {
+ ItemKind::Struct(def, _) | ItemKind::Union(def, _) => {
let adt_kind = match item.kind {
ItemKind::Struct(..) => AdtKind::Struct,
_ => AdtKind::Union,
@@ -956,7 +949,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
.struct_span_err(
attr.span,
"the `#[rustc_must_implement_one_of]` attribute must be \
- used with at least 2 args",
+ used with at least 2 args",
)
.emit();
@@ -988,7 +981,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
tcx.sess
.struct_span_err(
item.span,
- "This function doesn't have a default implementation",
+ "function doesn't have a default implementation",
)
.span_note(attr_span, "required by this annotation")
.emit();
@@ -1000,17 +993,17 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
}
Some(item) => {
tcx.sess
- .struct_span_err(item.span, "Not a function")
+ .struct_span_err(item.span, "not a function")
.span_note(attr_span, "required by this annotation")
.note(
- "All `#[rustc_must_implement_one_of]` arguments \
- must be associated function names",
+ "all `#[rustc_must_implement_one_of]` arguments must be associated \
+ function names",
)
.emit();
}
None => {
tcx.sess
- .struct_span_err(ident.span, "Function not found in this trait")
+ .struct_span_err(ident.span, "function not found in this trait")
.emit();
}
}
@@ -1028,11 +1021,8 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
for ident in &*list {
if let Some(dup) = set.insert(ident.name, ident.span) {
tcx.sess
- .struct_span_err(vec![dup, ident.span], "Functions names are duplicated")
- .note(
- "All `#[rustc_must_implement_one_of]` arguments \
- must be unique",
- )
+ .struct_span_err(vec![dup, ident.span], "functions names are duplicated")
+ .note("all `#[rustc_must_implement_one_of]` arguments must be unique")
.emit();
no_dups = false;
@@ -1074,7 +1064,7 @@ fn is_suggestable_infer_ty(ty: &hir::Ty<'_>) -> bool {
is_suggestable_infer_ty(ty) || matches!(length, hir::ArrayLen::Infer(_, _))
}
Tup(tys) => tys.iter().any(is_suggestable_infer_ty),
- Ptr(mut_ty) | Rptr(_, mut_ty) => is_suggestable_infer_ty(mut_ty.ty),
+ Ptr(mut_ty) | Ref(_, mut_ty) => is_suggestable_infer_ty(mut_ty.ty),
OpaqueDef(_, generic_args, _) => are_suggestable_generic_args(generic_args),
Path(hir::QPath::TypeRelative(ty, segment)) => {
is_suggestable_infer_ty(ty) || are_suggestable_generic_args(segment.args().args)
@@ -1119,11 +1109,10 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => {
// Do not try to infer the return type for a impl method coming from a trait
if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) =
- tcx.hir().get(tcx.hir().get_parent_node(hir_id))
+ tcx.hir().get_parent(hir_id)
&& i.of_trait.is_some()
{
- <dyn AstConv<'_>>::ty_of_fn(
- &icx,
+ icx.astconv().ty_of_fn(
hir_id,
sig.header.unsafety,
sig.header.abi,
@@ -1140,15 +1129,9 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
kind: TraitItemKind::Fn(FnSig { header, decl, span: _ }, _),
generics,
..
- }) => <dyn AstConv<'_>>::ty_of_fn(
- &icx,
- hir_id,
- header.unsafety,
- header.abi,
- decl,
- Some(generics),
- None,
- ),
+ }) => {
+ icx.astconv().ty_of_fn(hir_id, header.unsafety, header.abi, decl, Some(generics), None)
+ }
ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(fn_decl, _, _), .. }) => {
let abi = tcx.hir().get_foreign_abi(hir_id);
@@ -1206,12 +1189,11 @@ fn infer_return_ty_for_fn_sig<'tcx>(
ty::ReErased => tcx.lifetimes.re_static,
_ => r,
});
- let fn_sig = ty::Binder::dummy(fn_sig);
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_ty(ty);
let mut diag = bad_placeholder(tcx, visitor.0, "return type");
- let ret_ty = fn_sig.skip_binder().output();
+ let ret_ty = fn_sig.output();
if ret_ty.is_suggestable(tcx, false) {
diag.span_suggestion(
ty.span,
@@ -1234,19 +1216,28 @@ fn infer_return_ty_for_fn_sig<'tcx>(
Applicability::MachineApplicable,
);
}
+ } else if let Some(sugg) = suggest_impl_trait(tcx, ret_ty, ty.span, hir_id, def_id) {
+ diag.span_suggestion(
+ ty.span,
+ "replace with an appropriate return type",
+ sugg,
+ Applicability::MachineApplicable,
+ );
} else if ret_ty.is_closure() {
- // We're dealing with a closure, so we should suggest using `impl Fn` or trait bounds
- // to prevent the user from getting a papercut while trying to use the unique closure
- // syntax (e.g. `[closure@src/lib.rs:2:5: 2:9]`).
diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound");
- diag.note("for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html");
+ }
+ // Also note how `Fn` traits work just in case!
+ if ret_ty.is_closure() {
+ diag.note(
+ "for more information on `Fn` traits and closure types, see \
+ https://doc.rust-lang.org/book/ch13-01-closures.html",
+ );
}
diag.emit();
- fn_sig
+ ty::Binder::dummy(fn_sig)
}
- None => <dyn AstConv<'_>>::ty_of_fn(
- icx,
+ None => icx.astconv().ty_of_fn(
hir_id,
sig.header.unsafety,
sig.header.abi,
@@ -1257,21 +1248,114 @@ fn infer_return_ty_for_fn_sig<'tcx>(
}
}
-fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::TraitRef<'_>> {
+fn suggest_impl_trait<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ ret_ty: Ty<'tcx>,
+ span: Span,
+ hir_id: hir::HirId,
+ def_id: LocalDefId,
+) -> Option<String> {
+ let format_as_assoc: fn(_, _, _, _, _) -> _ =
+ |tcx: TyCtxt<'tcx>,
+ _: ty::SubstsRef<'tcx>,
+ trait_def_id: DefId,
+ assoc_item_def_id: DefId,
+ item_ty: Ty<'tcx>| {
+ let trait_name = tcx.item_name(trait_def_id);
+ let assoc_name = tcx.item_name(assoc_item_def_id);
+ Some(format!("impl {trait_name}<{assoc_name} = {item_ty}>"))
+ };
+ let format_as_parenthesized: fn(_, _, _, _, _) -> _ =
+ |tcx: TyCtxt<'tcx>,
+ substs: ty::SubstsRef<'tcx>,
+ trait_def_id: DefId,
+ _: DefId,
+ item_ty: Ty<'tcx>| {
+ let trait_name = tcx.item_name(trait_def_id);
+ let args_tuple = substs.type_at(1);
+ let ty::Tuple(types) = *args_tuple.kind() else { return None; };
+ if !types.is_suggestable(tcx, false) {
+ return None;
+ }
+ let maybe_ret =
+ if item_ty.is_unit() { String::new() } else { format!(" -> {item_ty}") };
+ Some(format!(
+ "impl {trait_name}({}){maybe_ret}",
+ types.iter().map(|ty| ty.to_string()).collect::<Vec<_>>().join(", ")
+ ))
+ };
+
+ for (trait_def_id, assoc_item_def_id, formatter) in [
+ (
+ tcx.get_diagnostic_item(sym::Iterator),
+ tcx.get_diagnostic_item(sym::IteratorItem),
+ format_as_assoc,
+ ),
+ (
+ tcx.lang_items().future_trait(),
+ tcx.get_diagnostic_item(sym::FutureOutput),
+ format_as_assoc,
+ ),
+ (tcx.lang_items().fn_trait(), tcx.lang_items().fn_once_output(), format_as_parenthesized),
+ (
+ tcx.lang_items().fn_mut_trait(),
+ tcx.lang_items().fn_once_output(),
+ format_as_parenthesized,
+ ),
+ (
+ tcx.lang_items().fn_once_trait(),
+ tcx.lang_items().fn_once_output(),
+ format_as_parenthesized,
+ ),
+ ] {
+ let Some(trait_def_id) = trait_def_id else { continue; };
+ let Some(assoc_item_def_id) = assoc_item_def_id else { continue; };
+ if tcx.def_kind(assoc_item_def_id) != DefKind::AssocTy {
+ continue;
+ }
+ let param_env = tcx.param_env(def_id);
+ let infcx = tcx.infer_ctxt().build();
+ let substs = ty::InternalSubsts::for_item(tcx, trait_def_id, |param, _| {
+ if param.index == 0 { ret_ty.into() } else { infcx.var_for_def(span, param) }
+ });
+ if !infcx.type_implements_trait(trait_def_id, substs, param_env).must_apply_modulo_regions()
+ {
+ continue;
+ }
+ let ocx = ObligationCtxt::new_in_snapshot(&infcx);
+ let item_ty = ocx.normalize(
+ &ObligationCause::misc(span, hir_id),
+ param_env,
+ tcx.mk_projection(assoc_item_def_id, substs),
+ );
+ // FIXME(compiler-errors): We may benefit from resolving regions here.
+ if ocx.select_where_possible().is_empty()
+ && let item_ty = infcx.resolve_vars_if_possible(item_ty)
+ && item_ty.is_suggestable(tcx, false)
+ && let Some(sugg) = formatter(tcx, infcx.resolve_vars_if_possible(substs), trait_def_id, assoc_item_def_id, item_ty)
+ {
+ return Some(sugg);
+ }
+ }
+ None
+}
+
+fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::EarlyBinder<ty::TraitRef<'_>>> {
let icx = ItemCtxt::new(tcx, def_id);
let item = tcx.hir().expect_item(def_id.expect_local());
- match item.kind {
- hir::ItemKind::Impl(ref impl_) => impl_.of_trait.as_ref().map(|ast_trait_ref| {
+ let hir::ItemKind::Impl(impl_) = item.kind else { bug!() };
+ impl_
+ .of_trait
+ .as_ref()
+ .map(|ast_trait_ref| {
let selfty = tcx.type_of(def_id);
- <dyn AstConv<'_>>::instantiate_mono_trait_ref(
- &icx,
+ icx.astconv().instantiate_mono_trait_ref(
ast_trait_ref,
selfty,
check_impl_constness(tcx, impl_.constness, ast_trait_ref),
)
- }),
- _ => bug!(),
- }
+ })
+ .map(ty::EarlyBinder)
}
fn check_impl_constness(
@@ -1394,15 +1478,8 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
hir::Unsafety::Unsafe
};
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let fty = <dyn AstConv<'_>>::ty_of_fn(
- &ItemCtxt::new(tcx, def_id),
- hir_id,
- unsafety,
- abi,
- decl,
- None,
- None,
- );
+ let fty =
+ ItemCtxt::new(tcx, def_id).astconv().ty_of_fn(hir_id, unsafety, abi, decl, None, None);
// Feature gate SIMD types in FFI, since I am not sure that the
// ABIs are handled at all correctly. -huonw
@@ -1433,7 +1510,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
for (input, ty) in iter::zip(decl.inputs, fty.inputs().skip_binder()) {
check(input, *ty)
}
- if let hir::FnRetTy::Return(ref ty) = decl.output {
+ if let hir::FnRetTy::Return(ty) = decl.output {
check(ty, fty.output().skip_binder())
}
}
@@ -1460,798 +1537,6 @@ fn generator_kind(tcx: TyCtxt<'_>, def_id: DefId) -> Option<hir::GeneratorKind>
}
}
-fn from_target_feature(
- tcx: TyCtxt<'_>,
- attr: &ast::Attribute,
- supported_target_features: &FxHashMap<String, Option<Symbol>>,
- target_features: &mut Vec<Symbol>,
-) {
- let Some(list) = attr.meta_item_list() else { return };
- let bad_item = |span| {
- let msg = "malformed `target_feature` attribute input";
- let code = "enable = \"..\"";
- tcx.sess
- .struct_span_err(span, msg)
- .span_suggestion(span, "must be of the form", code, Applicability::HasPlaceholders)
- .emit();
- };
- let rust_features = tcx.features();
- for item in list {
- // Only `enable = ...` is accepted in the meta-item list.
- if !item.has_name(sym::enable) {
- bad_item(item.span());
- continue;
- }
-
- // Must be of the form `enable = "..."` (a string).
- let Some(value) = item.value_str() else {
- bad_item(item.span());
- continue;
- };
-
- // We allow comma separation to enable multiple features.
- target_features.extend(value.as_str().split(',').filter_map(|feature| {
- let Some(feature_gate) = supported_target_features.get(feature) else {
- let msg =
- format!("the feature named `{}` is not valid for this target", feature);
- let mut err = tcx.sess.struct_span_err(item.span(), &msg);
- err.span_label(
- item.span(),
- format!("`{}` is not valid for this target", feature),
- );
- if let Some(stripped) = feature.strip_prefix('+') {
- let valid = supported_target_features.contains_key(stripped);
- if valid {
- err.help("consider removing the leading `+` in the feature name");
- }
- }
- err.emit();
- return None;
- };
-
- // Only allow features whose feature gates have been enabled.
- let allowed = match feature_gate.as_ref().copied() {
- Some(sym::arm_target_feature) => rust_features.arm_target_feature,
- Some(sym::hexagon_target_feature) => rust_features.hexagon_target_feature,
- Some(sym::powerpc_target_feature) => rust_features.powerpc_target_feature,
- Some(sym::mips_target_feature) => rust_features.mips_target_feature,
- Some(sym::riscv_target_feature) => rust_features.riscv_target_feature,
- Some(sym::avx512_target_feature) => rust_features.avx512_target_feature,
- Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature,
- Some(sym::tbm_target_feature) => rust_features.tbm_target_feature,
- Some(sym::wasm_target_feature) => rust_features.wasm_target_feature,
- Some(sym::cmpxchg16b_target_feature) => rust_features.cmpxchg16b_target_feature,
- Some(sym::movbe_target_feature) => rust_features.movbe_target_feature,
- Some(sym::rtm_target_feature) => rust_features.rtm_target_feature,
- Some(sym::f16c_target_feature) => rust_features.f16c_target_feature,
- Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature,
- Some(sym::bpf_target_feature) => rust_features.bpf_target_feature,
- Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature,
- Some(name) => bug!("unknown target feature gate {}", name),
- None => true,
- };
- if !allowed {
- feature_err(
- &tcx.sess.parse_sess,
- feature_gate.unwrap(),
- item.span(),
- &format!("the target feature `{}` is currently unstable", feature),
- )
- .emit();
- }
- Some(Symbol::intern(feature))
- }));
- }
-}
-
-fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage {
- use rustc_middle::mir::mono::Linkage::*;
-
- // Use the names from src/llvm/docs/LangRef.rst here. Most types are only
- // applicable to variable declarations and may not really make sense for
- // Rust code in the first place but allow them anyway and trust that the
- // user knows what they're doing. Who knows, unanticipated use cases may pop
- // up in the future.
- //
- // ghost, dllimport, dllexport and linkonce_odr_autohide are not supported
- // and don't have to be, LLVM treats them as no-ops.
- match name {
- "appending" => Appending,
- "available_externally" => AvailableExternally,
- "common" => Common,
- "extern_weak" => ExternalWeak,
- "external" => External,
- "internal" => Internal,
- "linkonce" => LinkOnceAny,
- "linkonce_odr" => LinkOnceODR,
- "private" => Private,
- "weak" => WeakAny,
- "weak_odr" => WeakODR,
- _ => tcx.sess.span_fatal(tcx.def_span(def_id), "invalid linkage specified"),
- }
-}
-
-fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
- if cfg!(debug_assertions) {
- let def_kind = tcx.def_kind(did);
- assert!(
- def_kind.has_codegen_attrs(),
- "unexpected `def_kind` in `codegen_fn_attrs`: {def_kind:?}",
- );
- }
-
- let did = did.expect_local();
- let attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(did));
- let mut codegen_fn_attrs = CodegenFnAttrs::new();
- if tcx.should_inherit_track_caller(did) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
- }
-
- let supported_target_features = tcx.supported_target_features(LOCAL_CRATE);
-
- let mut inline_span = None;
- let mut link_ordinal_span = None;
- let mut no_sanitize_span = None;
- for attr in attrs.iter() {
- if attr.has_name(sym::cold) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD;
- } else if attr.has_name(sym::rustc_allocator) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR;
- } else if attr.has_name(sym::ffi_returns_twice) {
- if tcx.is_foreign_item(did) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE;
- } else {
- // `#[ffi_returns_twice]` is only allowed `extern fn`s.
- struct_span_err!(
- tcx.sess,
- attr.span,
- E0724,
- "`#[ffi_returns_twice]` may only be used on foreign functions"
- )
- .emit();
- }
- } else if attr.has_name(sym::ffi_pure) {
- if tcx.is_foreign_item(did) {
- if attrs.iter().any(|a| a.has_name(sym::ffi_const)) {
- // `#[ffi_const]` functions cannot be `#[ffi_pure]`
- struct_span_err!(
- tcx.sess,
- attr.span,
- E0757,
- "`#[ffi_const]` function cannot be `#[ffi_pure]`"
- )
- .emit();
- } else {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE;
- }
- } else {
- // `#[ffi_pure]` is only allowed on foreign functions
- struct_span_err!(
- tcx.sess,
- attr.span,
- E0755,
- "`#[ffi_pure]` may only be used on foreign functions"
- )
- .emit();
- }
- } else if attr.has_name(sym::ffi_const) {
- if tcx.is_foreign_item(did) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST;
- } else {
- // `#[ffi_const]` is only allowed on foreign functions
- struct_span_err!(
- tcx.sess,
- attr.span,
- E0756,
- "`#[ffi_const]` may only be used on foreign functions"
- )
- .emit();
- }
- } else if attr.has_name(sym::rustc_nounwind) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
- } else if attr.has_name(sym::rustc_reallocator) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR;
- } else if attr.has_name(sym::rustc_deallocator) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR;
- } else if attr.has_name(sym::rustc_allocator_zeroed) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED;
- } else if attr.has_name(sym::naked) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;
- } else if attr.has_name(sym::no_mangle) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
- } else if attr.has_name(sym::no_coverage) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE;
- } else if attr.has_name(sym::rustc_std_internal_symbol) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
- } else if attr.has_name(sym::used) {
- let inner = attr.meta_item_list();
- match inner.as_deref() {
- Some([item]) if item.has_name(sym::linker) => {
- if !tcx.features().used_with_arg {
- feature_err(
- &tcx.sess.parse_sess,
- sym::used_with_arg,
- attr.span,
- "`#[used(linker)]` is currently unstable",
- )
- .emit();
- }
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER;
- }
- Some([item]) if item.has_name(sym::compiler) => {
- if !tcx.features().used_with_arg {
- feature_err(
- &tcx.sess.parse_sess,
- sym::used_with_arg,
- attr.span,
- "`#[used(compiler)]` is currently unstable",
- )
- .emit();
- }
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
- }
- Some(_) => {
- tcx.sess.emit_err(errors::ExpectedUsedSymbol { span: attr.span });
- }
- None => {
- // Unfortunately, unconditionally using `llvm.used` causes
- // issues in handling `.init_array` with the gold linker,
- // but using `llvm.compiler.used` caused a nontrival amount
- // of unintentional ecosystem breakage -- particularly on
- // Mach-O targets.
- //
- // As a result, we emit `llvm.compiler.used` only on ELF
- // targets. This is somewhat ad-hoc, but actually follows
- // our pre-LLVM 13 behavior (prior to the ecosystem
- // breakage), and seems to match `clang`'s behavior as well
- // (both before and after LLVM 13), possibly because they
- // have similar compatibility concerns to us. See
- // https://github.com/rust-lang/rust/issues/47384#issuecomment-1019080146
- // and following comments for some discussion of this, as
- // well as the comments in `rustc_codegen_llvm` where these
- // flags are handled.
- //
- // Anyway, to be clear: this is still up in the air
- // somewhat, and is subject to change in the future (which
- // is a good thing, because this would ideally be a bit
- // more firmed up).
- let is_like_elf = !(tcx.sess.target.is_like_osx
- || tcx.sess.target.is_like_windows
- || tcx.sess.target.is_like_wasm);
- codegen_fn_attrs.flags |= if is_like_elf {
- CodegenFnAttrFlags::USED
- } else {
- CodegenFnAttrFlags::USED_LINKER
- };
- }
- }
- } else if attr.has_name(sym::cmse_nonsecure_entry) {
- if !matches!(tcx.fn_sig(did).abi(), abi::Abi::C { .. }) {
- struct_span_err!(
- tcx.sess,
- attr.span,
- E0776,
- "`#[cmse_nonsecure_entry]` requires C ABI"
- )
- .emit();
- }
- if !tcx.sess.target.llvm_target.contains("thumbv8m") {
- struct_span_err!(tcx.sess, attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension")
- .emit();
- }
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY;
- } else if attr.has_name(sym::thread_local) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL;
- } else if attr.has_name(sym::track_caller) {
- if !tcx.is_closure(did.to_def_id()) && tcx.fn_sig(did).abi() != abi::Abi::Rust {
- struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI")
- .emit();
- }
- if tcx.is_closure(did.to_def_id()) && !tcx.features().closure_track_caller {
- feature_err(
- &tcx.sess.parse_sess,
- sym::closure_track_caller,
- attr.span,
- "`#[track_caller]` on closures is currently unstable",
- )
- .emit();
- }
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
- } else if attr.has_name(sym::export_name) {
- if let Some(s) = attr.value_str() {
- if s.as_str().contains('\0') {
- // `#[export_name = ...]` will be converted to a null-terminated string,
- // so it may not contain any null characters.
- struct_span_err!(
- tcx.sess,
- attr.span,
- E0648,
- "`export_name` may not contain null characters"
- )
- .emit();
- }
- codegen_fn_attrs.export_name = Some(s);
- }
- } else if attr.has_name(sym::target_feature) {
- if !tcx.is_closure(did.to_def_id())
- && tcx.fn_sig(did).unsafety() == hir::Unsafety::Normal
- {
- if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
- // The `#[target_feature]` attribute is allowed on
- // WebAssembly targets on all functions, including safe
- // ones. Other targets require that `#[target_feature]` is
- // only applied to unsafe functions (pending the
- // `target_feature_11` feature) because on most targets
- // execution of instructions that are not supported is
- // considered undefined behavior. For WebAssembly which is a
- // 100% safe target at execution time it's not possible to
- // execute undefined instructions, and even if a future
- // feature was added in some form for this it would be a
- // deterministic trap. There is no undefined behavior when
- // executing WebAssembly so `#[target_feature]` is allowed
- // on safe functions (but again, only for WebAssembly)
- //
- // Note that this is also allowed if `actually_rustdoc` so
- // if a target is documenting some wasm-specific code then
- // it's not spuriously denied.
- } else if !tcx.features().target_feature_11 {
- let mut err = feature_err(
- &tcx.sess.parse_sess,
- sym::target_feature_11,
- attr.span,
- "`#[target_feature(..)]` can only be applied to `unsafe` functions",
- );
- err.span_label(tcx.def_span(did), "not an `unsafe` function");
- err.emit();
- } else {
- check_target_feature_trait_unsafe(tcx, did, attr.span);
- }
- }
- from_target_feature(
- tcx,
- attr,
- supported_target_features,
- &mut codegen_fn_attrs.target_features,
- );
- } else if attr.has_name(sym::linkage) {
- if let Some(val) = attr.value_str() {
- let linkage = Some(linkage_by_name(tcx, did, val.as_str()));
- if tcx.is_foreign_item(did) {
- codegen_fn_attrs.import_linkage = linkage;
- } else {
- codegen_fn_attrs.linkage = linkage;
- }
- }
- } else if attr.has_name(sym::link_section) {
- if let Some(val) = attr.value_str() {
- if val.as_str().bytes().any(|b| b == 0) {
- let msg = format!(
- "illegal null byte in link_section \
- value: `{}`",
- &val
- );
- tcx.sess.span_err(attr.span, &msg);
- } else {
- codegen_fn_attrs.link_section = Some(val);
- }
- }
- } else if attr.has_name(sym::link_name) {
- codegen_fn_attrs.link_name = attr.value_str();
- } else if attr.has_name(sym::link_ordinal) {
- link_ordinal_span = Some(attr.span);
- if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
- codegen_fn_attrs.link_ordinal = ordinal;
- }
- } else if attr.has_name(sym::no_sanitize) {
- no_sanitize_span = Some(attr.span);
- if let Some(list) = attr.meta_item_list() {
- for item in list.iter() {
- if item.has_name(sym::address) {
- codegen_fn_attrs.no_sanitize |= SanitizerSet::ADDRESS;
- } else if item.has_name(sym::cfi) {
- codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI;
- } else if item.has_name(sym::memory) {
- codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
- } else if item.has_name(sym::memtag) {
- codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG;
- } else if item.has_name(sym::shadow_call_stack) {
- codegen_fn_attrs.no_sanitize |= SanitizerSet::SHADOWCALLSTACK;
- } else if item.has_name(sym::thread) {
- codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD;
- } else if item.has_name(sym::hwaddress) {
- codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS;
- } else {
- tcx.sess
- .struct_span_err(item.span(), "invalid argument for `no_sanitize`")
- .note("expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, `shadow-call-stack`, or `thread`")
- .emit();
- }
- }
- }
- } else if attr.has_name(sym::instruction_set) {
- codegen_fn_attrs.instruction_set = match attr.meta_kind() {
- Some(MetaItemKind::List(ref items)) => match items.as_slice() {
- [NestedMetaItem::MetaItem(set)] => {
- let segments =
- set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
- match segments.as_slice() {
- [sym::arm, sym::a32] | [sym::arm, sym::t32] => {
- if !tcx.sess.target.has_thumb_interworking {
- struct_span_err!(
- tcx.sess.diagnostic(),
- attr.span,
- E0779,
- "target does not support `#[instruction_set]`"
- )
- .emit();
- None
- } else if segments[1] == sym::a32 {
- Some(InstructionSetAttr::ArmA32)
- } else if segments[1] == sym::t32 {
- Some(InstructionSetAttr::ArmT32)
- } else {
- unreachable!()
- }
- }
- _ => {
- struct_span_err!(
- tcx.sess.diagnostic(),
- attr.span,
- E0779,
- "invalid instruction set specified",
- )
- .emit();
- None
- }
- }
- }
- [] => {
- struct_span_err!(
- tcx.sess.diagnostic(),
- attr.span,
- E0778,
- "`#[instruction_set]` requires an argument"
- )
- .emit();
- None
- }
- _ => {
- struct_span_err!(
- tcx.sess.diagnostic(),
- attr.span,
- E0779,
- "cannot specify more than one instruction set"
- )
- .emit();
- None
- }
- },
- _ => {
- struct_span_err!(
- tcx.sess.diagnostic(),
- attr.span,
- E0778,
- "must specify an instruction set"
- )
- .emit();
- None
- }
- };
- } else if attr.has_name(sym::repr) {
- codegen_fn_attrs.alignment = match attr.meta_item_list() {
- Some(items) => match items.as_slice() {
- [item] => match item.name_value_literal() {
- Some((sym::align, literal)) => {
- let alignment = rustc_attr::parse_alignment(&literal.kind);
-
- match alignment {
- Ok(align) => Some(align),
- Err(msg) => {
- struct_span_err!(
- tcx.sess.diagnostic(),
- attr.span,
- E0589,
- "invalid `repr(align)` attribute: {}",
- msg
- )
- .emit();
-
- None
- }
- }
- }
- _ => None,
- },
- [] => None,
- _ => None,
- },
- None => None,
- };
- }
- }
-
- codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| {
- if !attr.has_name(sym::inline) {
- return ia;
- }
- match attr.meta_kind() {
- Some(MetaItemKind::Word) => InlineAttr::Hint,
- Some(MetaItemKind::List(ref items)) => {
- inline_span = Some(attr.span);
- if items.len() != 1 {
- struct_span_err!(
- tcx.sess.diagnostic(),
- attr.span,
- E0534,
- "expected one argument"
- )
- .emit();
- InlineAttr::None
- } else if list_contains_name(&items, sym::always) {
- InlineAttr::Always
- } else if list_contains_name(&items, sym::never) {
- InlineAttr::Never
- } else {
- struct_span_err!(
- tcx.sess.diagnostic(),
- items[0].span(),
- E0535,
- "invalid argument"
- )
- .help("valid inline arguments are `always` and `never`")
- .emit();
-
- InlineAttr::None
- }
- }
- Some(MetaItemKind::NameValue(_)) => ia,
- None => ia,
- }
- });
-
- codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| {
- if !attr.has_name(sym::optimize) {
- return ia;
- }
- let err = |sp, s| struct_span_err!(tcx.sess.diagnostic(), sp, E0722, "{}", s).emit();
- match attr.meta_kind() {
- Some(MetaItemKind::Word) => {
- err(attr.span, "expected one argument");
- ia
- }
- Some(MetaItemKind::List(ref items)) => {
- inline_span = Some(attr.span);
- if items.len() != 1 {
- err(attr.span, "expected one argument");
- OptimizeAttr::None
- } else if list_contains_name(&items, sym::size) {
- OptimizeAttr::Size
- } else if list_contains_name(&items, sym::speed) {
- OptimizeAttr::Speed
- } else {
- err(items[0].span(), "invalid argument");
- OptimizeAttr::None
- }
- }
- Some(MetaItemKind::NameValue(_)) => ia,
- None => ia,
- }
- });
-
- // #73631: closures inherit `#[target_feature]` annotations
- if tcx.features().target_feature_11 && tcx.is_closure(did.to_def_id()) {
- let owner_id = tcx.parent(did.to_def_id());
- if tcx.def_kind(owner_id).has_codegen_attrs() {
- codegen_fn_attrs
- .target_features
- .extend(tcx.codegen_fn_attrs(owner_id).target_features.iter().copied());
- }
- }
-
- // If a function uses #[target_feature] it can't be inlined into general
- // purpose functions as they wouldn't have the right target features
- // enabled. For that reason we also forbid #[inline(always)] as it can't be
- // respected.
- if !codegen_fn_attrs.target_features.is_empty() {
- if codegen_fn_attrs.inline == InlineAttr::Always {
- if let Some(span) = inline_span {
- tcx.sess.span_err(
- span,
- "cannot use `#[inline(always)]` with \
- `#[target_feature]`",
- );
- }
- }
- }
-
- if !codegen_fn_attrs.no_sanitize.is_empty() {
- if codegen_fn_attrs.inline == InlineAttr::Always {
- if let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) {
- let hir_id = tcx.hir().local_def_id_to_hir_id(did);
- tcx.struct_span_lint_hir(
- lint::builtin::INLINE_NO_SANITIZE,
- hir_id,
- no_sanitize_span,
- "`no_sanitize` will have no effect after inlining",
- |lint| lint.span_note(inline_span, "inlining requested here"),
- )
- }
- }
- }
-
- if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE;
- codegen_fn_attrs.inline = InlineAttr::Never;
- }
-
- // Weak lang items have the same semantics as "std internal" symbols in the
- // sense that they're preserved through all our LTO passes and only
- // strippable by the linker.
- //
- // Additionally weak lang items have predetermined symbol names.
- if WEAK_LANG_ITEMS.iter().any(|&l| tcx.lang_items().get(l) == Some(did.to_def_id())) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
- }
- if let Some((name, _)) = lang_items::extract(attrs)
- && let Some(lang_item) = LangItem::from_name(name)
- && let Some(link_name) = lang_item.link_name()
- {
- codegen_fn_attrs.export_name = Some(link_name);
- codegen_fn_attrs.link_name = Some(link_name);
- }
- check_link_name_xor_ordinal(tcx, &codegen_fn_attrs, link_ordinal_span);
-
- // Internal symbols to the standard library all have no_mangle semantics in
- // that they have defined symbol names present in the function name. This
- // also applies to weak symbols where they all have known symbol names.
- if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
- }
-
- // Any linkage to LLVM intrinsics for now forcibly marks them all as never
- // unwinds since LLVM sometimes can't handle codegen which `invoke`s
- // intrinsic functions.
- if let Some(name) = &codegen_fn_attrs.link_name {
- if name.as_str().starts_with("llvm.") {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
- }
- }
-
- codegen_fn_attrs
-}
-
-/// Computes the set of target features used in a function for the purposes of
-/// inline assembly.
-fn asm_target_features<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx FxHashSet<Symbol> {
- let mut target_features = tcx.sess.unstable_target_features.clone();
- if tcx.def_kind(did).has_codegen_attrs() {
- let attrs = tcx.codegen_fn_attrs(did);
- target_features.extend(&attrs.target_features);
- match attrs.instruction_set {
- None => {}
- Some(InstructionSetAttr::ArmA32) => {
- target_features.remove(&sym::thumb_mode);
- }
- Some(InstructionSetAttr::ArmT32) => {
- target_features.insert(sym::thumb_mode);
- }
- }
- }
-
- tcx.arena.alloc(target_features)
-}
-
-/// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
-/// applied to the method prototype.
-fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
- if let Some(impl_item) = tcx.opt_associated_item(def_id)
- && let ty::AssocItemContainer::ImplContainer = impl_item.container
- && let Some(trait_item) = impl_item.trait_item_def_id
- {
- return tcx
- .codegen_fn_attrs(trait_item)
- .flags
- .intersects(CodegenFnAttrFlags::TRACK_CALLER);
- }
-
- false
-}
-
-fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> {
- use rustc_ast::{LitIntType, LitKind, MetaItemLit};
- if !tcx.features().raw_dylib && tcx.sess.target.arch == "x86" {
- feature_err(
- &tcx.sess.parse_sess,
- sym::raw_dylib,
- attr.span,
- "`#[link_ordinal]` is unstable on x86",
- )
- .emit();
- }
- let meta_item_list = attr.meta_item_list();
- let meta_item_list = meta_item_list.as_deref();
- let sole_meta_list = match meta_item_list {
- Some([item]) => item.lit(),
- Some(_) => {
- tcx.sess
- .struct_span_err(attr.span, "incorrect number of arguments to `#[link_ordinal]`")
- .note("the attribute requires exactly one argument")
- .emit();
- return None;
- }
- _ => None,
- };
- if let Some(MetaItemLit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) =
- sole_meta_list
- {
- // According to the table at https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-header,
- // the ordinal must fit into 16 bits. Similarly, the Ordinal field in COFFShortExport (defined
- // in llvm/include/llvm/Object/COFFImportFile.h), which we use to communicate import information
- // to LLVM for `#[link(kind = "raw-dylib"_])`, is also defined to be uint16_t.
- //
- // FIXME: should we allow an ordinal of 0? The MSVC toolchain has inconsistent support for this:
- // both LINK.EXE and LIB.EXE signal errors and abort when given a .DEF file that specifies
- // a zero ordinal. However, llvm-dlltool is perfectly happy to generate an import library
- // for such a .DEF file, and MSVC's LINK.EXE is also perfectly happy to consume an import
- // library produced by LLVM with an ordinal of 0, and it generates an .EXE. (I don't know yet
- // if the resulting EXE runs, as I haven't yet built the necessary DLL -- see earlier comment
- // about LINK.EXE failing.)
- if *ordinal <= u16::MAX as u128 {
- Some(*ordinal as u16)
- } else {
- let msg = format!("ordinal value in `link_ordinal` is too large: `{}`", &ordinal);
- tcx.sess
- .struct_span_err(attr.span, &msg)
- .note("the value may not exceed `u16::MAX`")
- .emit();
- None
- }
- } else {
- tcx.sess
- .struct_span_err(attr.span, "illegal ordinal format in `link_ordinal`")
- .note("an unsuffixed integer value, e.g., `1`, is expected")
- .emit();
- None
- }
-}
-
-fn check_link_name_xor_ordinal(
- tcx: TyCtxt<'_>,
- codegen_fn_attrs: &CodegenFnAttrs,
- inline_span: Option<Span>,
-) {
- if codegen_fn_attrs.link_name.is_none() || codegen_fn_attrs.link_ordinal.is_none() {
- return;
- }
- let msg = "cannot use `#[link_name]` with `#[link_ordinal]`";
- if let Some(span) = inline_span {
- tcx.sess.span_err(span, msg);
- } else {
- tcx.sess.err(msg);
- }
-}
-
-/// Checks the function annotated with `#[target_feature]` is not a safe
-/// trait method implementation, reporting an error if it is.
-fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span: Span) {
- let hir_id = tcx.hir().local_def_id_to_hir_id(id);
- let node = tcx.hir().get(hir_id);
- if let Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) = node {
- let parent_id = tcx.hir().get_parent_item(hir_id);
- let parent_item = tcx.hir().expect_item(parent_id.def_id);
- if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = parent_item.kind {
- tcx.sess
- .struct_span_err(
- attr_span,
- "`#[target_feature(..)]` cannot be applied to safe trait method",
- )
- .span_label(attr_span, "cannot be applied to safe trait method")
- .span_label(tcx.def_span(id), "not an `unsafe` function")
- .emit();
- }
- }
-}
-
fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
match tcx.hir().get_if_local(def_id) {
Some(Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(opaque), .. })) => {
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index 639f81f20..014ee9fcc 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -79,7 +79,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
let generics = tcx.generics_of(parent_def_id.to_def_id());
let param_def_idx = generics.param_def_id_to_index[&param_id.to_def_id()];
// In the above example this would be .params[..N#0]
- let params = generics.params[..param_def_idx as usize].to_owned();
+ let params = generics.params_to(param_def_idx as usize, tcx).to_owned();
let param_def_id_to_index =
params.iter().map(|param| (param.def_id, param.index)).collect();
@@ -104,18 +104,18 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
// `min_const_generics`.
Some(parent_def_id.to_def_id())
} else {
- let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
+ let parent_node = tcx.hir().get_parent(hir_id);
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(_, ref constant), .. })
+ Node::Expr(Expr { kind: ExprKind::Repeat(_, constant), .. })
if constant.hir_id() == hir_id =>
{
Some(parent_def_id.to_def_id())
}
- Node::Variant(Variant { disr_expr: Some(ref constant), .. })
+ Node::Variant(Variant { disr_expr: Some(constant), .. })
if constant.hir_id == hir_id =>
{
Some(parent_def_id.to_def_id())
@@ -259,7 +259,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
params.extend(ast_generics.params.iter().filter_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => None,
- GenericParamKind::Type { ref default, synthetic, .. } => {
+ GenericParamKind::Type { default, synthetic, .. } => {
if default.is_some() {
match allow_defaults {
Defaults::Allowed => {}
@@ -334,7 +334,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
// provide junk type parameter defs for const blocks.
if let Node::AnonConst(_) = node {
- let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
+ let parent_node = tcx.hir().get_parent(hir_id);
if let Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) = parent_node {
params.push(ty::GenericParamDef {
index: next_index(),
@@ -426,26 +426,22 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
}
match node {
- Node::TraitItem(item) => match item.kind {
- hir::TraitItemKind::Fn(ref sig, _) => {
- has_late_bound_regions(tcx, &item.generics, sig.decl)
- }
+ Node::TraitItem(item) => match &item.kind {
+ hir::TraitItemKind::Fn(sig, _) => has_late_bound_regions(tcx, &item.generics, sig.decl),
_ => None,
},
- Node::ImplItem(item) => match item.kind {
- hir::ImplItemKind::Fn(ref sig, _) => {
- has_late_bound_regions(tcx, &item.generics, sig.decl)
- }
+ Node::ImplItem(item) => match &item.kind {
+ hir::ImplItemKind::Fn(sig, _) => has_late_bound_regions(tcx, &item.generics, sig.decl),
_ => None,
},
Node::ForeignItem(item) => match item.kind {
- hir::ForeignItemKind::Fn(fn_decl, _, ref generics) => {
+ hir::ForeignItemKind::Fn(fn_decl, _, generics) => {
has_late_bound_regions(tcx, generics, fn_decl)
}
_ => None,
},
- Node::Item(item) => match item.kind {
- hir::ItemKind::Fn(ref sig, .., ref generics, _) => {
+ Node::Item(item) => match &item.kind {
+ hir::ItemKind::Fn(sig, .., generics, _) => {
has_late_bound_regions(tcx, generics, sig.decl)
}
_ => None,
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 0542e2c8f..8d479f1c3 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -26,9 +26,9 @@ fn associated_type_bounds<'tcx>(
);
let icx = ItemCtxt::new(tcx, assoc_item_def_id);
- let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, ast_bounds);
+ let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds);
// Associated types are implicitly sized unless a `?Sized` bound is found
- <dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span);
+ icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span);
let trait_def_id = tcx.parent(assoc_item_def_id);
let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id.expect_local());
@@ -44,9 +44,7 @@ fn associated_type_bounds<'tcx>(
}
});
- let all_bounds = tcx
- .arena
- .alloc_from_iter(bounds.predicates(tcx, item_ty).into_iter().chain(bounds_from_parent));
+ let all_bounds = tcx.arena.alloc_from_iter(bounds.predicates().chain(bounds_from_parent));
debug!("associated_type_bounds({}) = {:?}", tcx.def_path_str(assoc_item_def_id), all_bounds);
all_bounds
}
@@ -72,12 +70,12 @@ fn opaque_type_bounds<'tcx>(
};
let icx = ItemCtxt::new(tcx, opaque_def_id);
- let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, ast_bounds);
+ let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds);
// Opaque types are implicitly sized unless a `?Sized` bound is found
- <dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span);
+ icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span);
debug!(?bounds);
- tcx.arena.alloc_from_iter(bounds.predicates(tcx, item_ty))
+ tcx.arena.alloc_from_iter(bounds.predicates())
})
}
@@ -101,12 +99,16 @@ pub(super) fn explicit_item_bounds(
}
}
-pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> &'_ ty::List<ty::Predicate<'_>> {
- tcx.mk_predicates(
+pub(super) fn item_bounds(
+ tcx: TyCtxt<'_>,
+ def_id: DefId,
+) -> ty::EarlyBinder<&'_ ty::List<ty::Predicate<'_>>> {
+ let bounds = tcx.mk_predicates(
util::elaborate_predicates(
tcx,
tcx.explicit_item_bounds(def_id).iter().map(|&(bound, _span)| bound),
)
.map(|obligation| obligation.predicate),
- )
+ );
+ ty::EarlyBinder(bounds)
}
diff --git a/compiler/rustc_hir_analysis/src/collect/lifetimes.rs b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs
index e4fe3e90e..359122d4e 100644
--- a/compiler/rustc_hir_analysis/src/collect/lifetimes.rs
+++ b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs
@@ -1,9 +1,9 @@
//! Resolution of early vs late bound lifetimes.
//!
-//! Name resolution for lifetimes is performed on the AST and embedded into HIR. From this
+//! Name resolution for lifetimes is performed on the AST and embedded into HIR. From this
//! information, typechecking needs to transform the lifetime parameters into bound lifetimes.
-//! Lifetimes can be early-bound or late-bound. Construction of typechecking terms needs to visit
-//! the types in HIR to identify late-bound lifetimes and assign their Debruijn indices. This file
+//! Lifetimes can be early-bound or late-bound. Construction of typechecking terms needs to visit
+//! the types in HIR to identify late-bound lifetimes and assign their Debruijn indices. This file
//! is also responsible for assigning their semantics to implicit lifetimes in trait objects.
use rustc_ast::walk_list;
@@ -70,7 +70,7 @@ impl RegionExt for Region {
/// that it corresponds to.
///
/// FIXME. This struct gets converted to a `ResolveLifetimes` for
-/// actual use. It has the same data, but indexed by `LocalDefId`. This
+/// actual use. It has the same data, but indexed by `LocalDefId`. This
/// is silly.
#[derive(Debug, Default)]
struct NamedRegionMap {
@@ -276,7 +276,7 @@ fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveLife
rl
}
-fn late_region_as_bound_region<'tcx>(tcx: TyCtxt<'tcx>, region: &Region) -> ty::BoundVariableKind {
+fn late_region_as_bound_region(tcx: TyCtxt<'_>, region: &Region) -> ty::BoundVariableKind {
match region {
Region::LateBound(_, _, def_id) => {
let name = tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id.expect_local()));
@@ -428,7 +428,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
_ => {}
}
match item.kind {
- hir::ItemKind::Fn(_, ref generics, _) => {
+ hir::ItemKind::Fn(_, generics, _) => {
self.visit_early_late(item.hir_id(), generics, |this| {
intravisit::walk_item(this, item);
});
@@ -508,13 +508,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
this.with(scope, |this| intravisit::walk_item(this, item))
});
}
- hir::ItemKind::TyAlias(_, ref generics)
- | hir::ItemKind::Enum(_, ref generics)
- | hir::ItemKind::Struct(_, ref generics)
- | hir::ItemKind::Union(_, ref generics)
- | hir::ItemKind::Trait(_, _, ref generics, ..)
- | hir::ItemKind::TraitAlias(ref generics, ..)
- | hir::ItemKind::Impl(hir::Impl { ref generics, .. }) => {
+ hir::ItemKind::TyAlias(_, generics)
+ | hir::ItemKind::Enum(_, generics)
+ | hir::ItemKind::Struct(_, generics)
+ | hir::ItemKind::Union(_, generics)
+ | hir::ItemKind::Trait(_, _, generics, ..)
+ | hir::ItemKind::TraitAlias(generics, ..)
+ | hir::ItemKind::Impl(&hir::Impl { generics, .. }) => {
// These kinds of items have only early-bound lifetime parameters.
let lifetimes = generics
.params
@@ -544,7 +544,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
match item.kind {
- hir::ForeignItemKind::Fn(_, _, ref generics) => {
+ hir::ForeignItemKind::Fn(_, _, generics) => {
self.visit_early_late(item.hir_id(), generics, |this| {
intravisit::walk_foreign_item(this, item);
})
@@ -561,7 +561,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
#[instrument(level = "debug", skip(self))]
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
match ty.kind {
- hir::TyKind::BareFn(ref c) => {
+ hir::TyKind::BareFn(c) => {
let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) = c
.generic_params
.iter()
@@ -587,7 +587,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
intravisit::walk_ty(this, ty);
});
}
- hir::TyKind::TraitObject(bounds, ref lifetime, _) => {
+ hir::TyKind::TraitObject(bounds, lifetime, _) => {
debug!(?bounds, ?lifetime, "TraitObject");
let scope = Scope::TraitRefBoundary { s: self.scope };
self.with(scope, |this| {
@@ -617,7 +617,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
LifetimeName::Error => {}
}
}
- hir::TyKind::Rptr(ref lifetime_ref, ref mt) => {
+ hir::TyKind::Ref(lifetime_ref, ref mt) => {
self.visit_lifetime(lifetime_ref);
let scope = Scope::ObjectLifetimeDefault {
lifetime: self.map.defs.get(&lifetime_ref.hir_id).cloned(),
@@ -632,7 +632,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
// ^ ^ this gets resolved in the scope of
// the opaque_ty generics
let opaque_ty = self.tcx.hir().item(item_id);
- match opaque_ty.kind {
+ match &opaque_ty.kind {
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
origin: hir::OpaqueTyOrigin::TyAlias,
..
@@ -655,7 +655,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
origin: hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..),
..
}) => {}
- ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
+ i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
};
// Resolve the lifetimes that are applied to the opaque type.
@@ -682,7 +682,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
};
let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
// Ensure that the parent of the def is an item, not HRTB
- let parent_id = self.tcx.hir().get_parent_node(hir_id);
+ let parent_id = self.tcx.hir().parent_id(hir_id);
if !parent_id.is_owner() {
struct_span_err!(
self.tcx.sess,
@@ -720,7 +720,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
intravisit::walk_trait_item(this, trait_item)
});
}
- Type(bounds, ref ty) => {
+ Type(bounds, ty) => {
let generics = &trait_item.generics;
let lifetimes = generics
.params
@@ -766,7 +766,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
Fn(..) => self.visit_early_late(impl_item.hir_id(), &impl_item.generics, |this| {
intravisit::walk_impl_item(this, impl_item)
}),
- Type(ref ty) => {
+ Type(ty) => {
let generics = &impl_item.generics;
let lifetimes: FxIndexMap<LocalDefId, Region> = generics
.params
@@ -817,7 +817,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) {
for (i, segment) in path.segments.iter().enumerate() {
let depth = path.segments.len() - i - 1;
- if let Some(ref args) = segment.args {
+ if let Some(args) = segment.args {
self.visit_segment_args(path.res, depth, args);
}
}
@@ -833,7 +833,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
) {
let output = match fd.output {
hir::FnRetTy::DefaultReturn(_) => None,
- hir::FnRetTy::Return(ref ty) => Some(&**ty),
+ hir::FnRetTy::Return(ty) => Some(ty),
};
self.visit_fn_like_elision(&fd.inputs, output, matches!(fk, intravisit::FnKind::Closure));
intravisit::walk_fn_kind(self, fk);
@@ -846,13 +846,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
for param in generics.params {
match param.kind {
GenericParamKind::Lifetime { .. } => {}
- GenericParamKind::Type { ref default, .. } => {
- if let Some(ref ty) = default {
- this.visit_ty(&ty);
+ GenericParamKind::Type { default, .. } => {
+ if let Some(ty) = default {
+ this.visit_ty(ty);
}
}
- GenericParamKind::Const { ref ty, default } => {
- this.visit_ty(&ty);
+ GenericParamKind::Const { ty, default } => {
+ this.visit_ty(ty);
if let Some(default) = default {
this.visit_body(this.tcx.hir().body(default.body));
}
@@ -863,9 +863,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
match predicate {
&hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
hir_id,
- ref bounded_ty,
+ bounded_ty,
bounds,
- ref bound_generic_params,
+ bound_generic_params,
origin,
..
}) => {
@@ -905,7 +905,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
})
}
&hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
- ref lifetime,
+ lifetime,
bounds,
..
}) => {
@@ -914,7 +914,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
if lifetime.res != hir::LifetimeName::Static {
for bound in bounds {
- let hir::GenericBound::Outlives(ref lt) = bound else {
+ let hir::GenericBound::Outlives(lt) = bound else {
continue;
};
if lt.res != hir::LifetimeName::Static {
@@ -939,8 +939,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
}
}
&hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
- ref lhs_ty,
- ref rhs_ty,
+ lhs_ty,
+ rhs_ty,
..
}) => {
this.visit_ty(lhs_ty);
@@ -1018,7 +1018,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
}
}
-fn object_lifetime_default<'tcx>(tcx: TyCtxt<'tcx>, param_def_id: DefId) -> ObjectLifetimeDefault {
+fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: DefId) -> ObjectLifetimeDefault {
debug_assert_eq!(tcx.def_kind(param_def_id), DefKind::TyParam);
let param_def_id = param_def_id.expect_local();
let parent_def_id = tcx.local_parent(param_def_id);
@@ -1042,7 +1042,7 @@ fn object_lifetime_default<'tcx>(tcx: TyCtxt<'tcx>, param_def_id: DefId) -> Obje
}
for bound in bound.bounds {
- if let hir::GenericBound::Outlives(ref lifetime) = *bound {
+ if let hir::GenericBound::Outlives(lifetime) = bound {
set.insert(lifetime.res);
}
}
@@ -1283,7 +1283,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
// We may fail to resolve higher-ranked lifetimes that are mentioned by APIT.
// AST-based resolution does not care for impl-trait desugaring, which are the
- // responibility of lowering. This may create a mismatch between the resolution
+ // responibility of lowering. This may create a mismatch between the resolution
// AST found (`region_def_id`) which points to HRTB, and what HIR allows.
// ```
// fn foo(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {}
@@ -1434,7 +1434,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
DefKind::ConstParam => Some(ObjectLifetimeDefault::Empty),
DefKind::TyParam => Some(self.tcx.object_lifetime_default(param.def_id)),
// We may also get a `Trait` or `TraitAlias` because of how generics `Self` parameter
- // works. Ignore it because it can't have a meaningful lifetime default.
+ // works. Ignore it because it can't have a meaningful lifetime default.
DefKind::LifetimeParam | DefKind::Trait | DefKind::TraitAlias => None,
dk => bug!("unexpected def_kind {:?}", dk),
}
@@ -1751,7 +1751,7 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<
ty::Param(param_ty) => {
self.arg_is_constrained[param_ty.index as usize] = true;
}
- ty::Projection(_) => return ControlFlow::Continue(()),
+ ty::Alias(ty::Projection, _) => return ControlFlow::Continue(()),
_ => (),
}
t.super_visit_with(self)
@@ -1828,7 +1828,7 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<
}
}
- hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
+ hir::TyKind::Path(hir::QPath::Resolved(None, path)) => {
// consider only the lifetimes on the final
// segment; I am not sure it's even currently
// valid to have them elsewhere, but even if it
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 45e241f4e..46b277d98 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -75,7 +75,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
const NO_GENERICS: &hir::Generics<'_> = hir::Generics::empty();
- // We use an `IndexSet` to preserves order of insertion.
+ // We use an `IndexSet` to preserve order of insertion.
// Preserving the order of insertion is important here so as not to break UI tests.
let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default();
@@ -85,33 +85,30 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
Node::ImplItem(item) => item.generics,
Node::Item(item) => match item.kind {
- ItemKind::Impl(ref impl_) => {
+ ItemKind::Impl(impl_) => {
if impl_.defaultness.is_default() {
- is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy);
+ is_default_impl_trait =
+ tcx.impl_trait_ref(def_id).map(|t| ty::Binder::dummy(t.subst_identity()));
}
- &impl_.generics
+ impl_.generics
}
- ItemKind::Fn(.., ref generics, _)
- | ItemKind::TyAlias(_, ref generics)
- | ItemKind::Enum(_, ref generics)
- | ItemKind::Struct(_, ref generics)
- | ItemKind::Union(_, ref generics) => *generics,
+ ItemKind::Fn(.., generics, _)
+ | ItemKind::TyAlias(_, generics)
+ | ItemKind::Enum(_, generics)
+ | ItemKind::Struct(_, generics)
+ | ItemKind::Union(_, generics) => generics,
- ItemKind::Trait(_, _, ref generics, ..) => {
+ ItemKind::Trait(_, _, generics, ..) | ItemKind::TraitAlias(generics, _) => {
is_trait = Some(ty::TraitRef::identity(tcx, def_id));
- *generics
+ generics
}
- ItemKind::TraitAlias(ref generics, _) => {
- is_trait = Some(ty::TraitRef::identity(tcx, def_id));
- *generics
- }
- ItemKind::OpaqueTy(OpaqueTy { ref generics, .. }) => generics,
+ ItemKind::OpaqueTy(OpaqueTy { generics, .. }) => generics,
_ => NO_GENERICS,
},
Node::ForeignItem(item) => match item.kind {
ForeignItemKind::Static(..) => NO_GENERICS,
- ForeignItemKind::Fn(_, _, ref generics) => *generics,
+ ForeignItemKind::Fn(_, _, generics) => generics,
ForeignItemKind::Type => NO_GENERICS,
},
@@ -166,15 +163,15 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
let mut bounds = Bounds::default();
// Params are implicitly sized unless a `?Sized` bound is found
- <dyn AstConv<'_>>::add_implicitly_sized(
- &icx,
+ icx.astconv().add_implicitly_sized(
&mut bounds,
+ param_ty,
&[],
Some((param.def_id, ast_generics.predicates)),
param.span,
);
trace!(?bounds);
- predicates.extend(bounds.predicates(tcx, param_ty));
+ predicates.extend(bounds.predicates());
trace!(?predicates);
}
GenericParamKind::Const { .. } => {
@@ -214,22 +211,16 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
}
let mut bounds = Bounds::default();
- <dyn AstConv<'_>>::add_bounds(
- &icx,
- ty,
- bound_pred.bounds.iter(),
- &mut bounds,
- bound_vars,
- );
- predicates.extend(bounds.predicates(tcx, ty));
+ icx.astconv().add_bounds(ty, bound_pred.bounds.iter(), &mut bounds, bound_vars);
+ predicates.extend(bounds.predicates());
}
hir::WherePredicate::RegionPredicate(region_pred) => {
- let r1 = <dyn AstConv<'_>>::ast_region_to_region(&icx, &region_pred.lifetime, None);
+ let r1 = icx.astconv().ast_region_to_region(&region_pred.lifetime, None);
predicates.extend(region_pred.bounds.iter().map(|bound| {
let (r2, span) = match bound {
hir::GenericBound::Outlives(lt) => {
- (<dyn AstConv<'_>>::ast_region_to_region(&icx, lt, None), lt.ident.span)
+ (icx.astconv().ast_region_to_region(lt, None), lt.ident.span)
}
_ => bug!(),
};
@@ -256,12 +247,12 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
// Subtle: before we store the predicates into the tcx, we
// sort them so that predicates like `T: Foo<Item=U>` come
- // before uses of `U`. This avoids false ambiguity errors
+ // before uses of `U`. This avoids false ambiguity errors
// in trait checking. See `setup_constraining_predicates`
// for details.
if let Node::Item(&Item { kind: ItemKind::Impl { .. }, .. }) = node {
let self_ty = tcx.type_of(def_id);
- let trait_ref = tcx.impl_trait_ref(def_id);
+ let trait_ref = tcx.impl_trait_ref(def_id).map(ty::EarlyBinder::subst_identity);
cgp::setup_constraining_predicates(
tcx,
&mut predicates,
@@ -274,7 +265,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
// We create bi-directional Outlives predicates between the original
// and the duplicated parameter, to ensure that they do not get out of sync.
if let Node::Item(&Item { kind: ItemKind::OpaqueTy(..), .. }) = node {
- let opaque_ty_id = tcx.hir().get_parent_node(hir_id);
+ let opaque_ty_id = tcx.hir().parent_id(hir_id);
let opaque_ty_node = tcx.hir().get(opaque_ty_id);
let Node::Ty(&Ty { kind: TyKind::OpaqueDef(_, lifetimes, _), .. }) = opaque_ty_node else {
bug!("unexpected {opaque_ty_node:?}")
@@ -282,7 +273,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
debug!(?lifetimes);
for (arg, duplicate) in std::iter::zip(lifetimes, ast_generics.params) {
let hir::GenericArg::Lifetime(arg) = arg else { bug!() };
- let orig_region = <dyn AstConv<'_>>::ast_region_to_region(&icx, &arg, None);
+ let orig_region = icx.astconv().ast_region_to_region(&arg, None);
if !matches!(orig_region.kind(), ty::ReEarlyBound(..)) {
// Only early-bound regions can point to the original generic parameter.
continue;
@@ -322,10 +313,10 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
}
}
-fn const_evaluatable_predicates_of<'tcx>(
- tcx: TyCtxt<'tcx>,
+fn const_evaluatable_predicates_of(
+ tcx: TyCtxt<'_>,
def_id: LocalDefId,
-) -> FxIndexSet<(ty::Predicate<'tcx>, Span)> {
+) -> FxIndexSet<(ty::Predicate<'_>, Span)> {
struct ConstCollector<'tcx> {
tcx: TyCtxt<'tcx>,
preds: FxIndexSet<(ty::Predicate<'tcx>, Span)>,
@@ -359,7 +350,7 @@ fn const_evaluatable_predicates_of<'tcx>(
let node = tcx.hir().get(hir_id);
let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() };
- if let hir::Node::Item(item) = node && let hir::ItemKind::Impl(ref impl_) = item.kind {
+ if let hir::Node::Item(item) = node && let hir::ItemKind::Impl(impl_) = item.kind {
if let Some(of_trait) = &impl_.of_trait {
debug!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id);
collector.visit_trait_ref(of_trait);
@@ -406,14 +397,15 @@ pub(super) fn explicit_predicates_of<'tcx>(
// For a predicate from a where clause to become a bound on an
// associated type:
// * It must use the identity substs of the item.
- // * Since any generic parameters on the item are not in scope,
- // this means that the item is not a GAT, and its identity
- // substs are the same as the trait's.
+ // * We're in the scope of the trait, so we can't name any
+ // parameters of the GAT. That means that all we need to
+ // check are that the substs of the projection are the
+ // identity substs of the trait.
// * It must be an associated type for this trait (*not* a
// supertrait).
- if let ty::Projection(projection) = ty.kind() {
+ if let ty::Alias(ty::Projection, projection) = ty.kind() {
projection.substs == trait_identity_substs
- && tcx.associated_item(projection.item_def_id).container_id(tcx) == def_id
+ && tcx.associated_item(projection.def_id).container_id(tcx) == def_id
} else {
false
}
@@ -519,8 +511,8 @@ pub(super) fn super_predicates_that_define_assoc_type(
};
let (generics, bounds) = match item.kind {
- hir::ItemKind::Trait(.., ref generics, ref supertraits, _) => (generics, supertraits),
- hir::ItemKind::TraitAlias(ref generics, ref supertraits) => (generics, supertraits),
+ hir::ItemKind::Trait(.., generics, supertraits, _) => (generics, supertraits),
+ hir::ItemKind::TraitAlias(generics, supertraits) => (generics, supertraits),
_ => span_bug!(item.span, "super_predicates invoked on non-trait"),
};
@@ -529,17 +521,12 @@ pub(super) fn super_predicates_that_define_assoc_type(
// Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`.
let self_param_ty = tcx.types.self_param;
let superbounds1 = if let Some(assoc_name) = assoc_name {
- <dyn AstConv<'_>>::compute_bounds_that_match_assoc_type(
- &icx,
- self_param_ty,
- bounds,
- assoc_name,
- )
+ icx.astconv().compute_bounds_that_match_assoc_type(self_param_ty, bounds, assoc_name)
} else {
- <dyn AstConv<'_>>::compute_bounds(&icx, self_param_ty, bounds)
+ icx.astconv().compute_bounds(self_param_ty, bounds)
};
- let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
+ let superbounds1 = superbounds1.predicates();
// Convert any explicit superbounds in the where-clause,
// e.g., `trait Foo where Self: Bar`.
@@ -625,18 +612,18 @@ pub(super) fn type_param_predicates(
Node::Item(item) => {
match item.kind {
- ItemKind::Fn(.., ref generics, _)
- | ItemKind::Impl(hir::Impl { ref generics, .. })
- | ItemKind::TyAlias(_, ref generics)
+ ItemKind::Fn(.., generics, _)
+ | ItemKind::Impl(&hir::Impl { generics, .. })
+ | ItemKind::TyAlias(_, generics)
| ItemKind::OpaqueTy(OpaqueTy {
- ref generics,
+ generics,
origin: hir::OpaqueTyOrigin::TyAlias,
..
})
- | ItemKind::Enum(_, ref generics)
- | ItemKind::Struct(_, ref generics)
- | ItemKind::Union(_, ref generics) => generics,
- ItemKind::Trait(_, _, ref generics, ..) => {
+ | ItemKind::Enum(_, generics)
+ | ItemKind::Struct(_, generics)
+ | ItemKind::Union(_, generics) => generics,
+ ItemKind::Trait(_, _, generics, ..) => {
// Implied `Self: Trait` and supertrait bounds.
if param_id == item_hir_id {
let identity_trait_ref = ty::TraitRef::identity(tcx, item_def_id);
@@ -650,7 +637,7 @@ pub(super) fn type_param_predicates(
}
Node::ForeignItem(item) => match item.kind {
- ForeignItemKind::Fn(_, _, ref generics) => generics,
+ ForeignItemKind::Fn(_, _, generics) => generics,
_ => return result,
},
@@ -694,8 +681,8 @@ impl<'tcx> ItemCtxt<'tcx> {
ast_generics
.predicates
.iter()
- .filter_map(|wp| match *wp {
- hir::WherePredicate::BoundPredicate(ref bp) => Some(bp),
+ .filter_map(|wp| match wp {
+ hir::WherePredicate::BoundPredicate(bp) => Some(bp),
_ => None,
})
.flat_map(|bp| {
@@ -748,5 +735,5 @@ fn predicates_from_bound<'tcx>(
) -> Vec<(ty::Predicate<'tcx>, Span)> {
let mut bounds = Bounds::default();
astconv.add_bounds(param_ty, [bound].into_iter(), &mut bounds, bound_vars);
- bounds.predicates(astconv.tcx(), param_ty).collect()
+ bounds.predicates().collect()
}
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 9bd1715ce..5e388a2f2 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -5,6 +5,7 @@ use rustc_hir::intravisit;
use rustc_hir::intravisit::Visitor;
use rustc_hir::{HirId, Node};
use rustc_middle::hir::nested_filter;
+use rustc_middle::ty::print::with_forced_trimmed_paths;
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable};
@@ -27,7 +28,7 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
_ => return None,
};
- let parent_node_id = tcx.hir().get_parent_node(hir_id);
+ let parent_node_id = tcx.hir().parent_id(hir_id);
let parent_node = tcx.hir().get(parent_node_id);
let (generics, arg_idx) = match parent_node {
@@ -52,7 +53,7 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
// Using the ItemCtxt convert the HIR for the unresolved assoc type into a
// ty which is a fully resolved projection.
// For the code example above, this would mean converting Self::Assoc<3>
- // into a ty::Projection(<Self as Foo>::Assoc<3>)
+ // into a ty::Alias(ty::Projection, <Self as Foo>::Assoc<3>)
let item_hir_id = tcx
.hir()
.parent_iter(hir_id)
@@ -68,8 +69,8 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
// the def_id that this query was called with. We filter to only type and const args here
// as a precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't
// but it can't hurt to be safe ^^
- if let ty::Projection(projection) = ty.kind() {
- let generics = tcx.generics_of(projection.item_def_id);
+ if let ty::Alias(ty::Projection, projection) = ty.kind() {
+ let generics = tcx.generics_of(projection.def_id);
let arg_index = segment
.args
@@ -378,7 +379,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
ForeignItemKind::Type => tcx.mk_foreign(def_id.to_def_id()),
},
- Node::Ctor(&ref def) | Node::Variant(Variant { data: ref def, .. }) => match *def {
+ Node::Ctor(def) | Node::Variant(Variant { data: def, .. }) => match def {
VariantData::Unit(..) | VariantData::Struct(..) => {
tcx.type_of(tcx.hir().get_parent_item(hir_id))
}
@@ -401,19 +402,19 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
}
Node::AnonConst(_) => {
- let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
+ let parent_node = tcx.hir().get_parent(hir_id);
match parent_node {
- Node::Ty(&Ty { kind: TyKind::Array(_, ref constant), .. })
- | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
+ Node::Ty(Ty { kind: TyKind::Array(_, constant), .. })
+ | Node::Expr(Expr { kind: ExprKind::Repeat(_, constant), .. })
if constant.hir_id() == hir_id =>
{
tcx.types.usize
}
- Node::Ty(&Ty { kind: TyKind::Typeof(ref e), .. }) if e.hir_id == hir_id => {
+ Node::Ty(Ty { kind: TyKind::Typeof(e), .. }) if e.hir_id == hir_id => {
tcx.typeck(def_id).node_type(e.hir_id)
}
- Node::Expr(&Expr { kind: ExprKind::ConstBlock(ref anon_const), .. })
+ Node::Expr(Expr { kind: ExprKind::ConstBlock(anon_const), .. })
if anon_const.hir_id == hir_id =>
{
let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
@@ -433,18 +434,19 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
tcx.typeck(def_id).node_type(hir_id)
}
- Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => {
+ Node::Variant(Variant { disr_expr: Some(e), .. }) if e.hir_id == hir_id => {
tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx)
}
Node::TypeBinding(
- binding @ &TypeBinding {
+ TypeBinding {
hir_id: binding_id,
- kind: TypeBindingKind::Equality { term: Term::Const(ref e) },
+ kind: TypeBindingKind::Equality { term: Term::Const(e) },
+ ident,
..
},
) if let Node::TraitRef(trait_ref) =
- tcx.hir().get(tcx.hir().get_parent_node(binding_id))
+ tcx.hir().get_parent(*binding_id)
&& e.hir_id == hir_id =>
{
let Some(trait_def_id) = trait_ref.trait_def_id() else {
@@ -453,7 +455,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
let assoc_items = tcx.associated_items(trait_def_id);
let assoc_item = assoc_items.find_by_name_and_kind(
tcx,
- binding.ident,
+ *ident,
ty::AssocKind::Const,
def_id.to_def_id(),
);
@@ -469,9 +471,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
}
Node::TypeBinding(
- binding @ &TypeBinding { hir_id: binding_id, gen_args, ref kind, .. },
+ TypeBinding { hir_id: binding_id, gen_args, kind, ident, .. },
) if let Node::TraitRef(trait_ref) =
- tcx.hir().get(tcx.hir().get_parent_node(binding_id))
+ tcx.hir().get_parent(*binding_id)
&& let Some((idx, _)) =
gen_args.args.iter().enumerate().find(|(_, arg)| {
if let GenericArg::Const(ct) = arg {
@@ -487,7 +489,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
let assoc_items = tcx.associated_items(trait_def_id);
let assoc_item = assoc_items.find_by_name_and_kind(
tcx,
- binding.ident,
+ *ident,
match kind {
// I think `<A: T>` type bindings requires that `A` is a type
TypeBindingKind::Constraint { .. }
@@ -666,7 +668,7 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let scope = tcx.hir().get_defining_scope(hir_id);
- let mut locator = ConstraintLocator { def_id: def_id, tcx, found: None, typeck_types: vec![] };
+ let mut locator = ConstraintLocator { def_id, tcx, found: None, typeck_types: vec![] };
debug!(?scope);
@@ -803,7 +805,7 @@ fn find_opaque_ty_constraints_for_rpit(
if let Some(concrete) = concrete {
let scope = tcx.hir().local_def_id_to_hir_id(owner_def_id);
debug!(?scope);
- let mut locator = ConstraintChecker { def_id: def_id, tcx, found: concrete };
+ let mut locator = ConstraintChecker { def_id, tcx, found: concrete };
match tcx.hir().get(scope) {
Node::Item(it) => intravisit::walk_item(&mut locator, it),
@@ -907,10 +909,10 @@ fn infer_placeholder_type<'a>(
Applicability::MachineApplicable,
);
} else {
- err.span_note(
+ with_forced_trimmed_paths!(err.span_note(
tcx.hir().body(body_id).value.span,
- &format!("however, the inferred type `{}` cannot be named", ty),
- );
+ &format!("however, the inferred type `{ty}` cannot be named"),
+ ));
}
}
@@ -931,10 +933,10 @@ fn infer_placeholder_type<'a>(
Applicability::MaybeIncorrect,
);
} else {
- diag.span_note(
+ with_forced_trimmed_paths!(diag.span_note(
tcx.hir().body(body_id).value.span,
- &format!("however, the inferred type `{}` cannot be named", ty),
- );
+ &format!("however, the inferred type `{ty}` cannot be named"),
+ ));
}
}
diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
index b4057df78..56cc1d8fa 100644
--- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
+++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
@@ -59,9 +59,9 @@ struct ParameterCollector {
impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match *t.kind() {
- ty::Projection(..) if !self.include_nonconstraining => {
+ ty::Alias(ty::Projection, ..) if !self.include_nonconstraining => {
// projections are not injective
- return ControlFlow::CONTINUE;
+ return ControlFlow::Continue(());
}
ty::Param(data) => {
self.parameters.push(Parameter::from(data));
@@ -76,7 +76,7 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {
if let ty::ReEarlyBound(data) = *r {
self.parameters.push(Parameter::from(data));
}
- ControlFlow::CONTINUE
+ ControlFlow::Continue(())
}
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index c92ab749b..04f5f3f62 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -52,6 +52,17 @@ pub struct LifetimesOrBoundsMismatchOnTrait {
}
#[derive(Diagnostic)]
+#[diag(hir_analysis_async_trait_impl_should_be_async)]
+pub struct AsyncTraitImplShouldBeAsync {
+ #[primary_span]
+ // #[label]
+ pub span: Span,
+ #[label(trait_item_label)]
+ pub trait_item_span: Option<Span>,
+ pub method_name: Symbol,
+}
+
+#[derive(Diagnostic)]
#[diag(hir_analysis_drop_impl_on_wrong_item, code = "E0120")]
pub struct DropImplOnWrongItem {
#[primary_span]
@@ -254,13 +265,6 @@ pub struct ExternCrateNotIdiomatic {
}
#[derive(Diagnostic)]
-#[diag(hir_analysis_expected_used_symbol)]
-pub struct ExpectedUsedSymbol {
- #[primary_span]
- pub span: Span,
-}
-
-#[derive(Diagnostic)]
#[diag(hir_analysis_const_impl_for_non_const_trait)]
pub struct ConstImplForNonConstTrait {
#[primary_span]
@@ -296,3 +300,15 @@ pub(crate) struct LinkageType {
#[primary_span]
pub span: Span,
}
+
+#[derive(Diagnostic)]
+#[help]
+#[diag(hir_analysis_auto_deref_reached_recursion_limit, code = "E0055")]
+pub struct AutoDerefReachedRecursionLimit<'a> {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ pub ty: Ty<'a>,
+ pub suggested_limit: rustc_session::Limit,
+ pub crate_name: Symbol,
+}
diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
index 4f9d58265..17dbb126b 100644
--- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
@@ -114,34 +114,46 @@ fn diagnostic_hir_wf_check<'tcx>(
// Get the starting `hir::Ty` using our `WellFormedLoc`.
// We will walk 'into' this type to try to find
// a more precise span for our predicate.
- let ty = match loc {
+ let tys = match loc {
WellFormedLoc::Ty(_) => match hir.get(hir_id) {
hir::Node::ImplItem(item) => match item.kind {
- hir::ImplItemKind::Type(ty) => Some(ty),
- hir::ImplItemKind::Const(ty, _) => Some(ty),
+ hir::ImplItemKind::Type(ty) => vec![ty],
+ hir::ImplItemKind::Const(ty, _) => vec![ty],
ref item => bug!("Unexpected ImplItem {:?}", item),
},
hir::Node::TraitItem(item) => match item.kind {
- hir::TraitItemKind::Type(_, ty) => ty,
- hir::TraitItemKind::Const(ty, _) => Some(ty),
+ hir::TraitItemKind::Type(_, ty) => ty.into_iter().collect(),
+ hir::TraitItemKind::Const(ty, _) => vec![ty],
ref item => bug!("Unexpected TraitItem {:?}", item),
},
hir::Node::Item(item) => match item.kind {
- hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _) => Some(ty),
- hir::ItemKind::Impl(ref impl_) => {
- assert!(impl_.of_trait.is_none(), "Unexpected trait impl: {:?}", impl_);
- Some(impl_.self_ty)
- }
+ hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _) => vec![ty],
+ hir::ItemKind::Impl(impl_) => match &impl_.of_trait {
+ Some(t) => t
+ .path
+ .segments
+ .last()
+ .iter()
+ .flat_map(|seg| seg.args().args)
+ .filter_map(|arg| {
+ if let hir::GenericArg::Type(ty) = arg { Some(*ty) } else { None }
+ })
+ .chain([impl_.self_ty])
+ .collect(),
+ None => {
+ vec![impl_.self_ty]
+ }
+ },
ref item => bug!("Unexpected item {:?}", item),
},
- hir::Node::Field(field) => Some(field.ty),
+ hir::Node::Field(field) => vec![field.ty],
hir::Node::ForeignItem(ForeignItem {
kind: ForeignItemKind::Static(ty, _), ..
- }) => Some(*ty),
+ }) => vec![*ty],
hir::Node::GenericParam(hir::GenericParam {
kind: hir::GenericParamKind::Type { default: Some(ty), .. },
..
- }) => Some(*ty),
+ }) => vec![*ty],
ref node => bug!("Unexpected node {:?}", node),
},
WellFormedLoc::Param { function: _, param_idx } => {
@@ -149,16 +161,16 @@ fn diagnostic_hir_wf_check<'tcx>(
// Get return type
if param_idx as usize == fn_decl.inputs.len() {
match fn_decl.output {
- hir::FnRetTy::Return(ty) => Some(ty),
+ hir::FnRetTy::Return(ty) => vec![ty],
// The unit type `()` is always well-formed
- hir::FnRetTy::DefaultReturn(_span) => None,
+ hir::FnRetTy::DefaultReturn(_span) => vec![],
}
} else {
- Some(&fn_decl.inputs[param_idx as usize])
+ vec![&fn_decl.inputs[param_idx as usize]]
}
}
};
- if let Some(ty) = ty {
+ for ty in tys {
visitor.visit_ty(ty);
}
visitor.cause
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
index 136f61999..4fe893442 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
@@ -85,7 +85,7 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId)
}
let impl_generics = tcx.generics_of(impl_def_id);
let impl_predicates = tcx.predicates_of(impl_def_id);
- let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
+ let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).map(ty::EarlyBinder::subst_identity);
let mut input_parameters = cgp::parameters_for_impl(impl_self_ty, impl_trait_ref);
cgp::identify_constrained_generic_params(
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index fd8e8ed7b..bcda26c4c 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -81,7 +81,6 @@ use rustc_span::Span;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
use rustc_trait_selection::traits::{self, translate_substs, wf, ObligationCtxt};
-use tracing::instrument;
pub(super) fn check_min_specialization(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) {
if let Some(node) = parent_specialization_node(tcx, impl_def_id) {
@@ -91,7 +90,7 @@ pub(super) fn check_min_specialization(tcx: TyCtxt<'_>, impl_def_id: LocalDefId)
fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Option<Node> {
let trait_ref = tcx.impl_trait_ref(impl1_def_id)?;
- let trait_def = tcx.trait_def(trait_ref.def_id);
+ let trait_def = tcx.trait_def(trait_ref.skip_binder().def_id);
let impl2_node = trait_def.ancestors(tcx, impl1_def_id.to_def_id()).ok()?.nth(1)?;
@@ -157,11 +156,11 @@ fn check_constness(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node,
/// ```
///
/// Would return `S1 = [C]` and `S2 = [Vec<C>, C]`.
-fn get_impl_substs<'tcx>(
- tcx: TyCtxt<'tcx>,
+fn get_impl_substs(
+ tcx: TyCtxt<'_>,
impl1_def_id: LocalDefId,
impl2_node: Node,
-) -> Option<(SubstsRef<'tcx>, SubstsRef<'tcx>)> {
+) -> Option<(SubstsRef<'_>, SubstsRef<'_>)> {
let infcx = &tcx.infer_ctxt().build();
let ocx = ObligationCtxt::new(infcx);
let param_env = tcx.param_env(impl1_def_id);
@@ -182,7 +181,8 @@ fn get_impl_substs<'tcx>(
let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_hir_id, assumed_wf_types);
let outlives_env = OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
- infcx.check_region_obligations_and_report_errors(impl1_def_id, &outlives_env);
+ let _ =
+ infcx.err_ctxt().check_region_obligations_and_report_errors(impl1_def_id, &outlives_env);
let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {
let span = tcx.def_span(impl1_def_id);
tcx.sess.emit_err(SubstsOnOverriddenImpl { span });
@@ -207,7 +207,7 @@ fn unconstrained_parent_impl_substs<'tcx>(
let impl_generic_predicates = tcx.predicates_of(impl_def_id);
let mut unconstrained_parameters = FxHashSet::default();
let mut constrained_params = FxHashSet::default();
- let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
+ let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).map(ty::EarlyBinder::subst_identity);
// Unfortunately the functions in `constrained_generic_parameters` don't do
// what we want here. We want only a list of constrained parameters while
@@ -370,7 +370,7 @@ fn check_predicates<'tcx>(
});
// Include the well-formed predicates of the type parameters of the impl.
- for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().substs {
+ for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().subst_identity().substs {
let infcx = &tcx.infer_ctxt().build();
let obligations = wf::obligations(
infcx,
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 2058832d5..02548ae89 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -22,7 +22,7 @@ several major phases:
4. Finally, the check phase then checks function bodies and so forth.
Within the check phase, we check each function body one at a time
(bodies of function expressions are checked as part of the
- containing function). Inference is used to supply types wherever
+ containing function). Inference is used to supply types wherever
they are unknown. The actual checking of a function itself has
several phases (check, regionck, writeback), as discussed in the
documentation for the [`check`] module.
@@ -46,7 +46,7 @@ independently:
local variables, type parameters, etc as necessary.
- infer: finds the types to use for each type variable such that
- all subtyping and assignment constraints are met. In essence, the check
+ all subtyping and assignment constraints are met. In essence, the check
module specifies the constraints, and the infer module solves them.
## Note
@@ -84,6 +84,7 @@ extern crate rustc_middle;
pub mod check;
pub mod astconv;
+pub mod autoderef;
mod bounds;
mod check_unused;
mod coherence;
@@ -113,6 +114,7 @@ use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
use std::iter;
+use std::ops::Not;
use astconv::AstConv;
use bounds::Bounds;
@@ -202,12 +204,8 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
}
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
match tcx.hir().find(hir_id) {
- Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, ref generics, _), .. })) => {
- if !generics.params.is_empty() {
- Some(generics.span)
- } else {
- None
- }
+ Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. })) => {
+ generics.params.is_empty().not().then(|| generics.span)
}
_ => {
span_bug!(tcx.def_span(def_id), "main has a non-function type");
@@ -221,7 +219,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
}
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
match tcx.hir().find(hir_id) {
- Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, ref generics, _), .. })) => {
+ Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. })) => {
Some(generics.where_clause_span)
}
_ => {
@@ -243,7 +241,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
}
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
match tcx.hir().find(hir_id) {
- Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(ref fn_sig, _, _), .. })) => {
+ Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(fn_sig, _, _), .. })) => {
Some(fn_sig.decl.output.span())
}
_ => {
@@ -373,7 +371,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
match start_t.kind() {
ty::FnDef(..) => {
if let Some(Node::Item(it)) = tcx.hir().find(start_id) {
- if let hir::ItemKind::Fn(ref sig, ref generics, _) = it.kind {
+ if let hir::ItemKind::Fn(sig, generics, _) = &it.kind {
let mut error = false;
if !generics.params.is_empty() {
struct_span_err!(
@@ -541,10 +539,10 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
pub fn hir_ty_to_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'_>) -> Ty<'tcx> {
// In case there are any projections, etc., find the "environment"
// def-ID that will be used to determine the traits/predicates in
- // scope. This is derived from the enclosing item-like thing.
+ // scope. This is derived from the enclosing item-like thing.
let env_def_id = tcx.hir().get_parent_item(hir_ty.hir_id);
let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id());
- <dyn AstConv<'_>>::ast_ty_to_ty(&item_cx, hir_ty)
+ item_cx.astconv().ast_ty_to_ty(hir_ty)
}
pub fn hir_trait_to_predicates<'tcx>(
@@ -554,12 +552,11 @@ pub fn hir_trait_to_predicates<'tcx>(
) -> Bounds<'tcx> {
// In case there are any projections, etc., find the "environment"
// def-ID that will be used to determine the traits/predicates in
- // scope. This is derived from the enclosing item-like thing.
+ // scope. This is derived from the enclosing item-like thing.
let env_def_id = tcx.hir().get_parent_item(hir_trait.hir_ref_id);
let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id());
let mut bounds = Bounds::default();
- let _ = <dyn AstConv<'_>>::instantiate_poly_trait_ref(
- &item_cx,
+ let _ = &item_cx.astconv().instantiate_poly_trait_ref(
hir_trait,
DUMMY_SP,
ty::BoundConstness::NotConst,
diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
index 90c6edb65..925042436 100644
--- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
@@ -13,9 +13,9 @@ use super::utils::*;
/// `global_inferred_outlives`: this is initially the empty map that
/// was generated by walking the items in the crate. This will
/// now be filled with inferred predicates.
-pub(super) fn infer_predicates<'tcx>(
- tcx: TyCtxt<'tcx>,
-) -> FxHashMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>> {
+pub(super) fn infer_predicates(
+ tcx: TyCtxt<'_>,
+) -> FxHashMap<DefId, ty::EarlyBinder<RequiredPredicates<'_>>> {
debug!("infer_predicates");
let mut explicit_map = ExplicitPredicatesMap::new();
@@ -139,7 +139,7 @@ fn insert_required_predicates_to_be_wf<'tcx>(
if let Some(unsubstituted_predicates) = global_inferred_outlives.get(&def.did()) {
for (unsubstituted_predicate, &span) in &unsubstituted_predicates.0 {
// `unsubstituted_predicate` is `U: 'b` in the
- // example above. So apply the substitution to
+ // example above. So apply the substitution to
// get `T: 'a` (or `predicate`):
let predicate = unsubstituted_predicates
.rebind(*unsubstituted_predicate)
@@ -196,13 +196,13 @@ fn insert_required_predicates_to_be_wf<'tcx>(
}
}
- ty::Projection(obj) => {
+ ty::Alias(ty::Projection, obj) => {
// This corresponds to `<T as Foo<'a>>::Bar`. In this case, we should use the
// explicit predicates as well.
debug!("Projection");
check_explicit_predicates(
tcx,
- tcx.parent(obj.item_def_id),
+ tcx.parent(obj.def_id),
obj.substs,
required_predicates,
explicit_map,
diff --git a/compiler/rustc_hir_analysis/src/outlives/utils.rs b/compiler/rustc_hir_analysis/src/outlives/utils.rs
index 0409c7081..9459c5f54 100644
--- a/compiler/rustc_hir_analysis/src/outlives/utils.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/utils.rs
@@ -48,7 +48,7 @@ pub(crate) fn insert_outlives_predicate<'tcx>(
// ```
//
// Here `outlived_region = 'a` and `kind = &'b
- // u32`. Decomposing `&'b u32` into
+ // u32`. Decomposing `&'b u32` into
// components would yield `'b`, and we add the
// where clause that `'b: 'a`.
insert_outlives_predicate(
@@ -71,7 +71,7 @@ pub(crate) fn insert_outlives_predicate<'tcx>(
// ```
//
// Here `outlived_region = 'a` and `kind =
- // Vec<U>`. Decomposing `Vec<U>` into
+ // Vec<U>`. Decomposing `Vec<U>` into
// components would yield `U`, and we add the
// where clause that `U: 'a`.
let ty: Ty<'tcx> = param_ty.to_ty(tcx);
@@ -80,8 +80,8 @@ pub(crate) fn insert_outlives_predicate<'tcx>(
.or_insert(span);
}
- Component::Projection(proj_ty) => {
- // This would arise from something like:
+ Component::Alias(alias_ty) => {
+ // This would either arise from something like:
//
// ```
// struct Foo<'a, T: Iterator> {
@@ -89,15 +89,7 @@ pub(crate) fn insert_outlives_predicate<'tcx>(
// }
// ```
//
- // Here we want to add an explicit `where <T as Iterator>::Item: 'a`.
- let ty: Ty<'tcx> = tcx.mk_projection(proj_ty.item_def_id, proj_ty.substs);
- required_predicates
- .entry(ty::OutlivesPredicate(ty.into(), outlived_region))
- .or_insert(span);
- }
-
- Component::Opaque(def_id, substs) => {
- // This would arise from something like:
+ // or:
//
// ```rust
// type Opaque<T> = impl Sized;
@@ -105,17 +97,17 @@ pub(crate) fn insert_outlives_predicate<'tcx>(
// struct Ss<'a, T>(&'a Opaque<T>);
// ```
//
- // Here we want to have an implied bound `Opaque<T>: 'a`
-
- let ty = tcx.mk_opaque(def_id, substs);
+ // Here we want to add an explicit `where <T as Iterator>::Item: 'a`
+ // or `Opaque<T>: 'a` depending on the alias kind.
+ let ty = alias_ty.to_ty(tcx);
required_predicates
.entry(ty::OutlivesPredicate(ty.into(), outlived_region))
.or_insert(span);
}
- Component::EscapingProjection(_) => {
+ Component::EscapingAlias(_) => {
// As above, but the projection involves
- // late-bound regions. Therefore, the WF
+ // late-bound regions. Therefore, the WF
// requirement is not checked in type definition
// but at fn call site, so ignore it.
//
@@ -175,7 +167,7 @@ fn is_free_region(region: Region<'_>) -> bool {
// }
//
// The type above might generate a `T: 'b` bound, but we can
- // ignore it. We can't put it on the struct header anyway.
+ // ignore it. We can't put it on the struct header anyway.
ty::ReLateBound(..) => false,
// These regions don't appear in types from type declarations:
diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
index 4451db19f..9133e6540 100644
--- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
@@ -597,11 +597,15 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
let span = self.path_segment.ident.span;
// insert a suggestion of the form "Y<'a, 'b>"
- let ident = self.path_segment.ident.name.to_ident_string();
- let sugg = format!("{}<{}>", ident, suggested_args);
+ let sugg = format!("<{}>", suggested_args);
debug!("sugg: {:?}", sugg);
- err.span_suggestion_verbose(span, &msg, sugg, Applicability::HasPlaceholders);
+ err.span_suggestion_verbose(
+ span.shrink_to_hi(),
+ &msg,
+ sugg,
+ Applicability::HasPlaceholders,
+ );
}
AngleBrackets::Available => {
@@ -643,11 +647,15 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
let span = self.path_segment.ident.span;
// insert a suggestion of the form "Y<T, U>"
- let ident = self.path_segment.ident.name.to_ident_string();
- let sugg = format!("{}<{}>", ident, suggested_args);
+ let sugg = format!("<{}>", suggested_args);
debug!("sugg: {:?}", sugg);
- err.span_suggestion_verbose(span, &msg, sugg, Applicability::HasPlaceholders);
+ err.span_suggestion_verbose(
+ span.shrink_to_hi(),
+ &msg,
+ sugg,
+ Applicability::HasPlaceholders,
+ );
}
AngleBrackets::Available => {
let gen_args_span = self.gen_args.span().unwrap();
@@ -716,11 +724,11 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
num = num_trait_generics_except_self,
);
- if let Some(parent_node) = self.tcx.hir().find_parent_node(self.path_segment.hir_id)
+ if let Some(parent_node) = self.tcx.hir().opt_parent_id(self.path_segment.hir_id)
&& let Some(parent_node) = self.tcx.hir().find(parent_node)
&& let hir::Node::Expr(expr) = parent_node {
- match expr.kind {
- hir::ExprKind::Path(ref qpath) => {
+ match &expr.kind {
+ hir::ExprKind::Path(qpath) => {
self.suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path(
err,
qpath,
diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs
index 6ce0c18bf..5e4d82b6f 100644
--- a/compiler/rustc_hir_analysis/src/variance/constraints.rs
+++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs
@@ -249,14 +249,10 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
self.add_constraints_from_substs(current, def.did(), substs, variance);
}
- ty::Projection(ref data) => {
+ ty::Alias(_, ref data) => {
self.add_constraints_from_invariant_substs(current, data.substs, variance);
}
- ty::Opaque(_, substs) => {
- self.add_constraints_from_invariant_substs(current, substs, variance);
- }
-
ty::Dynamic(data, r, _) => {
// The type `Foo<T+'a>` is contravariant w/r/t `'a`:
let contra = self.contravariant(variance);
diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs
index 8b2719c2f..079070be2 100644
--- a/compiler/rustc_hir_analysis/src/variance/mod.rs
+++ b/compiler/rustc_hir_analysis/src/variance/mod.rs
@@ -92,7 +92,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
a.visit_with(self)?;
}
}
- ControlFlow::CONTINUE
+ ControlFlow::Continue(())
} else {
substs.visit_with(self)
}
@@ -111,11 +111,13 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
#[instrument(level = "trace", skip(self), ret)]
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match t.kind() {
- ty::Opaque(def_id, substs) => self.visit_opaque(*def_id, substs),
- ty::Projection(proj)
- if self.tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder =>
+ ty::Alias(_, ty::AliasTy { def_id, substs, .. })
+ if matches!(
+ self.tcx.def_kind(*def_id),
+ DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder
+ ) =>
{
- self.visit_opaque(proj.item_def_id, proj.substs)
+ self.visit_opaque(*def_id, substs)
}
_ => t.super_visit_with(self),
}
@@ -158,7 +160,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
// instead of requiring an additional `+ 'a`.
match pred.kind().skip_binder() {
ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate {
- trait_ref: ty::TraitRef { def_id: _, substs },
+ trait_ref: ty::TraitRef { def_id: _, substs, .. },
constness: _,
polarity: _,
})) => {
@@ -167,7 +169,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
}
}
ty::PredicateKind::Clause(ty::Clause::Projection(ty::ProjectionPredicate {
- projection_ty: ty::ProjectionTy { substs, item_def_id: _ },
+ projection_ty: ty::AliasTy { substs, .. },
term,
})) => {
for subst in &substs[1..] {
diff --git a/compiler/rustc_hir_analysis/src/variance/solve.rs b/compiler/rustc_hir_analysis/src/variance/solve.rs
index 97aca621a..a17edb598 100644
--- a/compiler/rustc_hir_analysis/src/variance/solve.rs
+++ b/compiler/rustc_hir_analysis/src/variance/solve.rs
@@ -5,8 +5,7 @@
//! optimal solution to the constraints. The final variance for each
//! inferred is then written into the `variance_map` in the tcx.
-use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::DefIdMap;
use rustc_middle::ty;
use super::constraints::*;
@@ -28,8 +27,8 @@ pub fn solve_constraints<'tcx>(
let ConstraintContext { terms_cx, constraints, .. } = constraints_cx;
let mut solutions = vec![ty::Bivariant; terms_cx.inferred_terms.len()];
- for &(id, ref variances) in &terms_cx.lang_items {
- let InferredIndex(start) = terms_cx.inferred_starts[&id];
+ for (id, variances) in &terms_cx.lang_items {
+ let InferredIndex(start) = terms_cx.inferred_starts[id];
for (i, &variance) in variances.iter().enumerate() {
solutions[start + i] = variance;
}
@@ -44,7 +43,7 @@ pub fn solve_constraints<'tcx>(
impl<'a, 'tcx> SolveContext<'a, 'tcx> {
fn solve(&mut self) {
- // Propagate constraints until a fixed point is reached. Note
+ // Propagate constraints until a fixed point is reached. Note
// that the maximum number of iterations is 2C where C is the
// number of constraints (each variable can change values at most
// twice). Since number of constraints is linear in size of the
@@ -89,14 +88,12 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> {
}
}
- fn create_map(&self) -> FxHashMap<DefId, &'tcx [ty::Variance]> {
+ fn create_map(&self) -> DefIdMap<&'tcx [ty::Variance]> {
let tcx = self.terms_cx.tcx;
let solutions = &self.solutions;
- self.terms_cx
- .inferred_starts
- .iter()
- .map(|(&def_id, &InferredIndex(start))| {
+ DefIdMap::from(self.terms_cx.inferred_starts.items().map(
+ |(&def_id, &InferredIndex(start))| {
let generics = tcx.generics_of(def_id);
let count = generics.count();
@@ -115,8 +112,8 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> {
}
(def_id.to_def_id(), &*variances)
- })
- .collect()
+ },
+ ))
}
fn evaluate(&self, term: VarianceTermPtr<'a>) -> ty::Variance {
diff --git a/compiler/rustc_hir_analysis/src/variance/test.rs b/compiler/rustc_hir_analysis/src/variance/test.rs
index 83ed3e44b..5feeb92d3 100644
--- a/compiler/rustc_hir_analysis/src/variance/test.rs
+++ b/compiler/rustc_hir_analysis/src/variance/test.rs
@@ -1,4 +1,3 @@
-use rustc_errors::struct_span_err;
use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::sym;
@@ -8,8 +7,8 @@ pub fn test_variance(tcx: TyCtxt<'_>) {
for id in tcx.hir().items() {
if tcx.has_attr(id.owner_id.to_def_id(), sym::rustc_variance) {
let variances_of = tcx.variances_of(id.owner_id);
- struct_span_err!(tcx.sess, tcx.def_span(id.owner_id), E0208, "{:?}", variances_of)
- .emit();
+
+ tcx.sess.struct_span_err(tcx.def_span(id.owner_id), format!("{variances_of:?}")).emit();
}
}
}