summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_analysis/src/astconv
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
commit9918693037dce8aa4bb6f08741b6812923486c18 (patch)
tree21d2b40bec7e6a7ea664acee056eb3d08e15a1cf /compiler/rustc_hir_analysis/src/astconv
parentReleasing progress-linux version 1.75.0+dfsg1-5~progress7.99u1. (diff)
downloadrustc-9918693037dce8aa4bb6f08741b6812923486c18.tar.xz
rustc-9918693037dce8aa4bb6f08741b6812923486c18.zip
Merging upstream version 1.76.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_hir_analysis/src/astconv')
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/bounds.rs151
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/errors.rs313
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/generics.rs27
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/lint.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs618
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/object_safety.rs11
6 files changed, 535 insertions, 592 deletions
diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
index 3e700f2da..0748644cc 100644
--- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
@@ -3,8 +3,7 @@ use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_lint_defs::Applicability;
-use rustc_middle::ty::{self as ty, Ty, TypeVisitableExt};
+use rustc_middle::ty::{self as ty, Ty};
use rustc_span::symbol::Ident;
use rustc_span::{ErrorGuaranteed, Span};
use rustc_trait_selection::traits;
@@ -135,17 +134,6 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
only_self_bounds,
);
}
- &hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => {
- self.instantiate_lang_item_trait_ref(
- lang_item,
- span,
- hir_id,
- args,
- param_ty,
- bounds,
- only_self_bounds,
- );
- }
hir::GenericBound::Outlives(lifetime) => {
let region = self.ast_region_to_region(lifetime, None);
bounds.push_region_bound(
@@ -194,8 +182,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
self.add_bounds(
param_ty,
- ast_bounds.iter().filter(|bound| {
- match filter {
+ ast_bounds.iter().filter(|bound| match filter {
PredicateFilter::All
| PredicateFilter::SelfOnly
| PredicateFilter::SelfAndAssociatedTypeBounds => true,
@@ -209,7 +196,6 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
false
}
}
- }
}),
&mut bounds,
ty::List::empty(),
@@ -258,64 +244,49 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
let tcx = self.tcx();
- let return_type_notation =
- binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation;
-
- let candidate = if return_type_notation {
- if self.trait_defines_associated_item_named(
- trait_ref.def_id(),
- ty::AssocKind::Fn,
- binding.item_name,
- ) {
- trait_ref
+ let assoc_kind =
+ if binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation {
+ ty::AssocKind::Fn
+ } else if let ConvertedBindingKind::Equality(term) = binding.kind
+ && let ty::TermKind::Const(_) = term.node.unpack()
+ {
+ ty::AssocKind::Const
} else {
- self.one_bound_for_assoc_method(
- traits::supertraits(tcx, trait_ref),
- trait_ref.print_only_trait_path(),
- binding.item_name,
- path_span,
- )?
- }
- } else if self.trait_defines_associated_item_named(
+ ty::AssocKind::Type
+ };
+
+ let candidate = if self.trait_defines_associated_item_named(
trait_ref.def_id(),
- ty::AssocKind::Type,
+ assoc_kind,
binding.item_name,
) {
- // Simple case: X is defined in the current trait.
+ // Simple case: The assoc item is defined in the current trait.
trait_ref
} else {
// Otherwise, we have to walk through the supertraits to find
- // those that do.
- self.one_bound_for_assoc_type(
+ // one that does define it.
+ self.one_bound_for_assoc_item(
|| traits::supertraits(tcx, trait_ref),
trait_ref.skip_binder().print_only_trait_name(),
None,
+ assoc_kind,
binding.item_name,
path_span,
- match binding.kind {
- ConvertedBindingKind::Equality(term) => Some(term),
- _ => None,
- },
+ Some(&binding),
)?
};
let (assoc_ident, def_scope) =
tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id);
- // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead
- // of calling `filter_by_name_and_kind`.
- let find_item_of_kind = |kind| {
- tcx.associated_items(candidate.def_id())
- .filter_by_name_unhygienic(assoc_ident.name)
- .find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident)
- };
- let assoc_item = if return_type_notation {
- find_item_of_kind(ty::AssocKind::Fn)
- } else {
- find_item_of_kind(ty::AssocKind::Type)
- .or_else(|| find_item_of_kind(ty::AssocKind::Const))
- }
- .expect("missing associated type");
+ // We have already adjusted the item name above, so compare with `.normalize_to_macros_2_0()`
+ // instead of calling `filter_by_name_and_kind` which would needlessly normalize the
+ // `assoc_ident` again and again.
+ let assoc_item = tcx
+ .associated_items(candidate.def_id())
+ .filter_by_name_unhygienic(assoc_ident.name)
+ .find(|i| i.kind == assoc_kind && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident)
+ .expect("missing associated item");
if !assoc_item.visibility(tcx).is_accessible_from(def_scope, tcx) {
tcx.sess
@@ -342,7 +313,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
.or_insert(binding.span);
}
- let projection_ty = if return_type_notation {
+ let projection_ty = if let ty::AssocKind::Fn = assoc_kind {
let mut emitted_bad_param_err = false;
// If we have an method return type bound, then we need to substitute
// the method's early bound params with suitable late-bound params.
@@ -350,7 +321,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
let args =
candidate.skip_binder().args.extend_to(tcx, assoc_item.def_id, |param, _| {
let subst = match param.kind {
- ty::GenericParamDefKind::Lifetime => ty::Region::new_late_bound(
+ ty::GenericParamDefKind::Lifetime => ty::Region::new_bound(
tcx,
ty::INNERMOST,
ty::BoundRegion {
@@ -469,7 +440,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
let late_bound_in_trait_ref =
tcx.collect_constrained_late_bound_regions(&projection_ty);
let late_bound_in_ty =
- tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(ty));
+ tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(ty.node));
debug!(?late_bound_in_trait_ref);
debug!(?late_bound_in_ty);
@@ -494,77 +465,27 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
}
}
- let assoc_item_def_id = projection_ty.skip_binder().def_id;
- let def_kind = tcx.def_kind(assoc_item_def_id);
match binding.kind {
- ConvertedBindingKind::Equality(..) if return_type_notation => {
+ ConvertedBindingKind::Equality(..) if let ty::AssocKind::Fn = assoc_kind => {
return Err(self.tcx().sess.emit_err(
crate::errors::ReturnTypeNotationEqualityBound { span: binding.span },
));
}
- ConvertedBindingKind::Equality(mut term) => {
+ ConvertedBindingKind::Equality(term) => {
// "Desugar" a constraint like `T: Iterator<Item = u32>` this to
// the "projection predicate" for:
//
// `<T as Iterator>::Item = u32`
- match (def_kind, term.unpack()) {
- (DefKind::AssocTy, ty::TermKind::Ty(_))
- | (DefKind::AssocConst, ty::TermKind::Const(_)) => (),
- (_, _) => {
- let got = if let Some(_) = term.ty() { "type" } else { "constant" };
- let expected = tcx.def_descr(assoc_item_def_id);
- 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 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,
- "if equating a const, try wrapping with braces",
- format!("{} = {{ const }}", binding.item_name),
- Applicability::HasPlaceholders,
- );
- }
- let reported = err.emit();
- term = match def_kind {
- DefKind::AssocTy => Ty::new_error(tcx, reported).into(),
- DefKind::AssocConst => ty::Const::new_error(
- tcx,
- reported,
- tcx.type_of(assoc_item_def_id)
- .instantiate(tcx, projection_ty.skip_binder().args),
- )
- .into(),
- _ => unreachable!(),
- };
- }
- }
bounds.push_projection_bound(
tcx,
- projection_ty
- .map_bound(|projection_ty| ty::ProjectionPredicate { projection_ty, term }),
+ projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate {
+ projection_ty,
+ term: term.node,
+ }),
binding.span,
);
}
ConvertedBindingKind::Constraint(ast_bounds) => {
- match def_kind {
- DefKind::AssocTy => {}
- _ => {
- return Err(tcx.sess.emit_err(errors::AssocBoundOnConst {
- span: assoc_ident.span,
- descr: tcx.def_descr(assoc_item_def_id),
- }));
- }
- }
// "Desugar" a constraint like `T: Iterator<Item: Debug>` to
//
// `<T as Iterator>::Item: Debug`
diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs
index 32be7e083..13ad9a453 100644
--- a/compiler/rustc_hir_analysis/src/astconv/errors.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs
@@ -1,23 +1,22 @@
-use crate::astconv::AstConv;
+use crate::astconv::{AstConv, ConvertedBindingKind};
use crate::errors::{
- AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
+ self, AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
ParenthesizedFnTraitExpansion,
};
+use crate::fluent_generated as fluent;
use crate::traits::error_reporting::report_object_safety_error;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_infer::traits::FulfillmentError;
-use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TyCtxt};
+use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TyCtxt, TypeVisitableExt};
use rustc_session::parse::feature_err;
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::symbol::{sym, Ident};
use rustc_span::{Span, Symbol, DUMMY_SP};
use rustc_trait_selection::traits::object_safety_violations_for_assoc_item;
-use std::collections::BTreeSet;
-
impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
/// On missing type parameters, emit an E0393 error and provide a structured suggestion using
/// the type parameter's name as a placeholder.
@@ -99,83 +98,88 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
}
- pub(crate) fn complain_about_assoc_type_not_found<I>(
+ pub(super) fn complain_about_assoc_item_not_found<I>(
&self,
all_candidates: impl Fn() -> I,
ty_param_name: &str,
ty_param_def_id: Option<LocalDefId>,
+ assoc_kind: ty::AssocKind,
assoc_name: Ident,
span: Span,
+ binding: Option<&super::ConvertedBinding<'_, 'tcx>>,
) -> ErrorGuaranteed
where
I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
{
+ let tcx = self.tcx();
+
+ // First and foremost, provide a more user-friendly & “intuitive” error on kind mismatches.
+ if let Some(assoc_item) = all_candidates().find_map(|r| {
+ tcx.associated_items(r.def_id())
+ .filter_by_name_unhygienic(assoc_name.name)
+ .find(|item| tcx.hygienic_eq(assoc_name, item.ident(tcx), r.def_id()))
+ }) {
+ return self.complain_about_assoc_kind_mismatch(
+ assoc_item, assoc_kind, assoc_name, span, binding,
+ );
+ }
+
+ let assoc_kind_str = super::assoc_kind_str(assoc_kind);
+
// The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a
// valid span, so we point at the whole path segment instead.
let is_dummy = assoc_name.span == DUMMY_SP;
- let mut err = struct_span_err!(
- self.tcx().sess,
- if is_dummy { span } else { assoc_name.span },
- E0220,
- "associated type `{}` not found for `{}`",
+ let mut err = errors::AssocItemNotFound {
+ span: if is_dummy { span } else { assoc_name.span },
assoc_name,
- ty_param_name
- );
+ assoc_kind: assoc_kind_str,
+ ty_param_name,
+ label: None,
+ sugg: None,
+ };
if is_dummy {
- err.span_label(span, format!("associated type `{assoc_name}` not found"));
- return err.emit();
+ err.label = Some(errors::AssocItemNotFoundLabel::NotFound { span });
+ return tcx.sess.emit_err(err);
}
let all_candidate_names: Vec<_> = all_candidates()
- .flat_map(|r| self.tcx().associated_items(r.def_id()).in_definition_order())
+ .flat_map(|r| tcx.associated_items(r.def_id()).in_definition_order())
.filter_map(|item| {
- if !item.is_impl_trait_in_trait() && item.kind == ty::AssocKind::Type {
- Some(item.name)
- } else {
- None
- }
+ (!item.is_impl_trait_in_trait() && item.kind == assoc_kind).then_some(item.name)
})
.collect();
if let Some(suggested_name) =
find_best_match_for_name(&all_candidate_names, assoc_name.name, None)
{
- err.span_suggestion(
- assoc_name.span,
- "there is an associated type with a similar name",
+ err.sugg = Some(errors::AssocItemNotFoundSugg::Similar {
+ span: assoc_name.span,
+ assoc_kind: assoc_kind_str,
suggested_name,
- Applicability::MaybeIncorrect,
- );
- return err.emit();
+ });
+ return tcx.sess.emit_err(err);
}
// If we didn't find a good item in the supertraits (or couldn't get
// the supertraits), like in ItemCtxt, then look more generally from
// all visible traits. If there's one clear winner, just suggest that.
- let visible_traits: Vec<_> = self
- .tcx()
+ let visible_traits: Vec<_> = tcx
.all_traits()
.filter(|trait_def_id| {
- let viz = self.tcx().visibility(*trait_def_id);
+ let viz = tcx.visibility(*trait_def_id);
let def_id = self.item_def_id();
- viz.is_accessible_from(def_id, self.tcx())
+ viz.is_accessible_from(def_id, tcx)
})
.collect();
let wider_candidate_names: Vec<_> = visible_traits
.iter()
- .flat_map(|trait_def_id| {
- self.tcx().associated_items(*trait_def_id).in_definition_order()
- })
+ .flat_map(|trait_def_id| tcx.associated_items(*trait_def_id).in_definition_order())
.filter_map(|item| {
- if !item.is_impl_trait_in_trait() && item.kind == ty::AssocKind::Type {
- Some(item.name)
- } else {
- None
- }
+ (!item.is_impl_trait_in_trait() && item.kind == assoc_kind).then_some(item.name)
})
.collect();
@@ -184,96 +188,155 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
{
if let [best_trait] = visible_traits
.iter()
+ .copied()
.filter(|trait_def_id| {
- self.tcx()
- .associated_items(*trait_def_id)
+ tcx.associated_items(trait_def_id)
.filter_by_name_unhygienic(suggested_name)
- .any(|item| item.kind == ty::AssocKind::Type)
+ .any(|item| item.kind == assoc_kind)
})
.collect::<Vec<_>>()[..]
{
- let trait_name = self.tcx().def_path_str(*best_trait);
- let an = if suggested_name != assoc_name.name { "a similarly named" } else { "an" };
- err.span_label(
- assoc_name.span,
- format!(
- "there is {an} associated type `{suggested_name}` in the \
- trait `{trait_name}`",
- ),
- );
- let hir = self.tcx().hir();
+ let trait_name = tcx.def_path_str(best_trait);
+ err.label = Some(errors::AssocItemNotFoundLabel::FoundInOtherTrait {
+ span: assoc_name.span,
+ assoc_kind: assoc_kind_str,
+ trait_name: &trait_name,
+ suggested_name,
+ identically_named: suggested_name == assoc_name.name,
+ });
+ let hir = tcx.hir();
if let Some(def_id) = ty_param_def_id
- && let parent = hir.get_parent_item(hir.local_def_id_to_hir_id(def_id))
+ && let parent = hir.get_parent_item(tcx.local_def_id_to_hir_id(def_id))
&& let Some(generics) = hir.get_generics(parent.def_id)
{
- if generics.bounds_for_param(def_id)
- .flat_map(|pred| pred.bounds.iter())
- .any(|b| match b {
+ if generics.bounds_for_param(def_id).flat_map(|pred| pred.bounds.iter()).any(
+ |b| match b {
hir::GenericBound::Trait(t, ..) => {
- t.trait_ref.trait_def_id().as_ref() == Some(best_trait)
+ t.trait_ref.trait_def_id() == Some(best_trait)
}
_ => false,
- })
- {
+ },
+ ) {
// The type param already has a bound for `trait_name`, we just need to
- // change the associated type.
- err.span_suggestion_verbose(
- assoc_name.span,
- format!(
- "change the associated type name to use `{suggested_name}` from \
- `{trait_name}`",
- ),
- suggested_name.to_string(),
- Applicability::MaybeIncorrect,
- );
- } else if suggest_constraining_type_param(
- self.tcx(),
- generics,
- &mut err,
- &ty_param_name,
- &trait_name,
- None,
- None,
- )
- && suggested_name != assoc_name.name
+ // change the associated item.
+ err.sugg = Some(errors::AssocItemNotFoundSugg::SimilarInOtherTrait {
+ span: assoc_name.span,
+ assoc_kind: assoc_kind_str,
+ suggested_name,
+ });
+ return tcx.sess.emit_err(err);
+ }
+
+ let mut err = tcx.sess.create_err(err);
+ if suggest_constraining_type_param(
+ tcx,
+ generics,
+ &mut err,
+ &ty_param_name,
+ &trait_name,
+ None,
+ None,
+ ) && suggested_name != assoc_name.name
{
// We suggested constraining a type parameter, but the associated type on it
// was also not an exact match, so we also suggest changing it.
err.span_suggestion_verbose(
assoc_name.span,
- "and also change the associated type name",
+ fluent::hir_analysis_assoc_item_not_found_similar_in_other_trait_with_bound_sugg,
suggested_name.to_string(),
Applicability::MaybeIncorrect,
);
}
+ return err.emit();
}
- return err.emit();
+ return tcx.sess.emit_err(err);
}
}
// If we still couldn't find any associated type, and only one associated type exists,
// suggests using it.
-
- if all_candidate_names.len() == 1 {
+ if let [candidate_name] = all_candidate_names.as_slice() {
// this should still compile, except on `#![feature(associated_type_defaults)]`
// where it could suggests `type A = Self::A`, thus recursing infinitely
- let applicability = if self.tcx().features().associated_type_defaults {
+ let applicability = if tcx.features().associated_type_defaults {
Applicability::Unspecified
} else {
Applicability::MaybeIncorrect
};
- err.span_suggestion(
- assoc_name.span,
- format!("`{ty_param_name}` has the following associated type"),
- all_candidate_names.first().unwrap().to_string(),
+ err.sugg = Some(errors::AssocItemNotFoundSugg::Other {
+ span: assoc_name.span,
applicability,
- );
+ ty_param_name,
+ assoc_kind: assoc_kind_str,
+ suggested_name: *candidate_name,
+ });
} else {
- err.span_label(assoc_name.span, format!("associated type `{assoc_name}` not found"));
+ err.label = Some(errors::AssocItemNotFoundLabel::NotFound { span: assoc_name.span });
}
- err.emit()
+ tcx.sess.emit_err(err)
+ }
+
+ fn complain_about_assoc_kind_mismatch(
+ &self,
+ assoc_item: &ty::AssocItem,
+ assoc_kind: ty::AssocKind,
+ ident: Ident,
+ span: Span,
+ binding: Option<&super::ConvertedBinding<'_, 'tcx>>,
+ ) -> ErrorGuaranteed {
+ let tcx = self.tcx();
+
+ let bound_on_assoc_const_label = if let ty::AssocKind::Const = assoc_item.kind
+ && let Some(binding) = binding
+ && let ConvertedBindingKind::Constraint(_) = binding.kind
+ {
+ let lo = if binding.gen_args.span_ext.is_dummy() {
+ ident.span
+ } else {
+ binding.gen_args.span_ext
+ };
+ Some(lo.between(span.shrink_to_hi()))
+ } else {
+ None
+ };
+
+ // FIXME(associated_const_equality): This has quite a few false positives and negatives.
+ let wrap_in_braces_sugg = if let Some(binding) = binding
+ && let ConvertedBindingKind::Equality(term) = binding.kind
+ && let ty::TermKind::Ty(ty) = term.node.unpack()
+ && (ty.is_enum() || ty.references_error())
+ && tcx.features().associated_const_equality
+ {
+ Some(errors::AssocKindMismatchWrapInBracesSugg {
+ lo: term.span.shrink_to_lo(),
+ hi: term.span.shrink_to_hi(),
+ })
+ } else {
+ None
+ };
+
+ // For equality bounds, we want to blame the term (RHS) instead of the item (LHS) since
+ // one can argue that that's more “untuitive” to the user.
+ let (span, expected_because_label, expected, got) = if let Some(binding) = binding
+ && let ConvertedBindingKind::Equality(term) = binding.kind
+ {
+ (term.span, Some(ident.span), assoc_item.kind, assoc_kind)
+ } else {
+ (ident.span, None, assoc_kind, assoc_item.kind)
+ };
+
+ tcx.sess.emit_err(errors::AssocKindMismatch {
+ span,
+ expected: super::assoc_kind_str(expected),
+ got: super::assoc_kind_str(got),
+ expected_because_label,
+ assoc_kind: super::assoc_kind_str(assoc_item.kind),
+ def_span: tcx.def_span(assoc_item.def_id),
+ bound_on_assoc_const_label,
+ wrap_in_braces_sugg,
+ })
}
pub(crate) fn complain_about_ambiguous_inherent_assoc_type(
@@ -506,23 +569,24 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
/// emit a generic note suggesting using a `where` clause to constraint instead.
pub(crate) fn complain_about_missing_associated_types(
&self,
- associated_types: FxHashMap<Span, BTreeSet<DefId>>,
+ associated_types: FxIndexMap<Span, FxIndexSet<DefId>>,
potential_assoc_types: Vec<Span>,
trait_bounds: &[hir::PolyTraitRef<'_>],
) {
if associated_types.values().all(|v| v.is_empty()) {
return;
}
+
let tcx = self.tcx();
// FIXME: Marked `mut` so that we can replace the spans further below with a more
// appropriate one, but this should be handled earlier in the span assignment.
- let mut associated_types: FxHashMap<Span, Vec<_>> = associated_types
+ let mut associated_types: FxIndexMap<Span, Vec<_>> = associated_types
.into_iter()
.map(|(span, def_ids)| {
(span, def_ids.into_iter().map(|did| tcx.associated_item(did)).collect())
})
.collect();
- let mut names: FxHashMap<String, Vec<Symbol>> = Default::default();
+ let mut names: FxIndexMap<String, Vec<Symbol>> = Default::default();
let mut names_len = 0;
// Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and
@@ -585,6 +649,32 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
}
+ // We get all the associated items that _are_ set,
+ // so that we can check if any of their names match one of the ones we are missing.
+ // This would mean that they are shadowing the associated type we are missing,
+ // and we can then use their span to indicate this to the user.
+ let bound_names = trait_bounds
+ .iter()
+ .filter_map(|poly_trait_ref| {
+ let path = poly_trait_ref.trait_ref.path.segments.last()?;
+ let args = path.args?;
+
+ Some(args.bindings.iter().filter_map(|binding| {
+ let ident = binding.ident;
+ let trait_def = path.res.def_id();
+ let assoc_item = tcx.associated_items(trait_def).find_by_name_and_kind(
+ tcx,
+ ident,
+ ty::AssocKind::Type,
+ trait_def,
+ );
+
+ Some((ident.name, assoc_item?))
+ }))
+ })
+ .flatten()
+ .collect::<FxHashMap<Symbol, &ty::AssocItem>>();
+
let mut names = names
.into_iter()
.map(|(trait_, mut assocs)| {
@@ -625,16 +715,42 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
*names.entry(item.name).or_insert(0) += 1;
}
let mut dupes = false;
+ let mut shadows = false;
for item in assoc_items {
let prefix = if names[&item.name] > 1 {
let trait_def_id = item.container_id(tcx);
dupes = true;
format!("{}::", tcx.def_path_str(trait_def_id))
+ } else if bound_names.get(&item.name).is_some_and(|x| x != &item) {
+ let trait_def_id = item.container_id(tcx);
+ shadows = true;
+ format!("{}::", tcx.def_path_str(trait_def_id))
} else {
String::new()
};
+
+ let mut is_shadowed = false;
+
+ if let Some(assoc_item) = bound_names.get(&item.name)
+ && assoc_item != &item
+ {
+ is_shadowed = true;
+
+ let rename_message =
+ if assoc_item.def_id.is_local() { ", consider renaming it" } else { "" };
+ err.span_label(
+ tcx.def_span(assoc_item.def_id),
+ format!("`{}{}` shadowed here{}", prefix, item.name, rename_message),
+ );
+ }
+
+ let rename_message = if is_shadowed { ", consider renaming it" } else { "" };
+
if let Some(sp) = tcx.hir().span_if_local(item.def_id) {
- err.span_label(sp, format!("`{}{}` defined here", prefix, item.name));
+ err.span_label(
+ sp,
+ format!("`{}{}` defined here{}", prefix, item.name, rename_message),
+ );
}
}
if potential_assoc_types.len() == assoc_items.len() {
@@ -642,8 +758,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// 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) =
- (tcx.sess.source_map().span_to_snippet(*span), dupes)
+ } else if let (Ok(snippet), false, false) =
+ (tcx.sess.source_map().span_to_snippet(*span), dupes, shadows)
{
let types: Vec<_> =
assoc_items.iter().map(|item| format!("{} = Type", item.name)).collect();
@@ -725,6 +841,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
err.span_help(where_constraints, where_msg);
}
}
+
err.emit();
}
}
diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs
index d29a27ece..b495b00ec 100644
--- a/compiler/rustc_hir_analysis/src/astconv/generics.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs
@@ -243,6 +243,31 @@ pub fn create_args_for_parent_generic_args<'tcx, 'a>(
match (args_iter.peek(), params.peek()) {
(Some(&arg), Some(&param)) => {
match (arg, &param.kind, arg_count.explicit_late_bound) {
+ (
+ GenericArg::Const(hir::ConstArg {
+ is_desugared_from_effects: true,
+ ..
+ }),
+ GenericParamDefKind::Const { is_host_effect: false, .. }
+ | GenericParamDefKind::Type { .. }
+ | GenericParamDefKind::Lifetime,
+ _,
+ ) => {
+ // SPECIAL CASE FOR DESUGARED EFFECT PARAMS
+ // This comes from the following example:
+ //
+ // ```
+ // #[const_trait]
+ // pub trait PartialEq<Rhs: ?Sized = Self> {}
+ // impl const PartialEq for () {}
+ // ```
+ //
+ // Since this is a const impl, we need to insert a host arg at the end of
+ // `PartialEq`'s generics, but this errors since `Rhs` isn't specified.
+ // To work around this, we infer all arguments until we reach the host param.
+ args.push(ctx.inferred_kind(Some(&args), param, infer_args));
+ params.next();
+ }
(GenericArg::Lifetime(_), GenericParamDefKind::Lifetime, _)
| (
GenericArg::Type(_) | GenericArg::Infer(_),
@@ -636,7 +661,7 @@ pub(crate) fn prohibit_explicit_late_bound_lifetimes(
args.args[0].hir_id(),
multispan,
msg,
- |lint| lint,
+ |_| {},
);
}
diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/astconv/lint.rs
index bc57bbcca..9afb04b74 100644
--- a/compiler/rustc_hir_analysis/src/astconv/lint.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/lint.rs
@@ -24,7 +24,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
..
}),
..
- }) = tcx.hir().get_by_def_id(parent_id)
+ }) = tcx.hir_node_by_def_id(parent_id)
&& self_ty.hir_id == impl_self_ty.hir_id
{
if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
@@ -106,7 +106,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
);
}
// 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);
+ self.maybe_lint_blanket_trait_impl(self_ty, &mut diag);
diag.stash(self_ty.span, StashKey::TraitMissingMethod);
} else {
let msg = "trait objects without an explicit `dyn` are deprecated";
@@ -121,8 +121,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
sugg,
Applicability::MachineApplicable,
);
- self.maybe_lint_blanket_trait_impl(&self_ty, lint);
- lint
+ self.maybe_lint_blanket_trait_impl(self_ty, lint);
},
);
}
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 2fcb45ef8..6f8e80172 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -18,29 +18,30 @@ use crate::require_c_abi_if_c_variadic;
use rustc_ast::TraitObjectSyntax;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{
- struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, FatalError,
- MultiSpan,
+ error_code, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
+ FatalError, MultiSpan,
};
use rustc_hir as hir;
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::{InferCtxt, InferOk, TyCtxtInferExt};
+use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::ObligationCause;
use rustc_middle::middle::stability::AllowUnstable;
use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::ty::{
- self, Const, GenericArgKind, GenericArgsRef, IsSuggestable, Ty, TyCtxt, TypeVisitableExt,
+ self, Const, GenericArgKind, GenericArgsRef, IsSuggestable, ParamEnv, Ty, TyCtxt,
+ TypeVisitableExt,
};
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
use rustc_span::edit_distance::find_best_match_for_name;
+use rustc_span::source_map::{respan, Spanned};
use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::{sym, BytePos, Span, DUMMY_SP};
use rustc_target::spec::abi;
use rustc_trait_selection::traits::wf::object_region_bounds;
-use rustc_trait_selection::traits::{self, NormalizeExt, ObligationCtxt};
-use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
+use rustc_trait_selection::traits::{self, ObligationCtxt};
use std::fmt::Display;
use std::slice;
@@ -162,7 +163,7 @@ struct ConvertedBinding<'a, 'tcx> {
#[derive(Debug)]
enum ConvertedBindingKind<'a, 'tcx> {
- Equality(ty::Term<'tcx>),
+ Equality(Spanned<ty::Term<'tcx>>),
Constraint(&'a [hir::GenericBound<'a>]),
}
@@ -239,7 +240,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
def: Option<&ty::GenericParamDef>,
) -> ty::Region<'tcx> {
let tcx = self.tcx();
- let lifetime_name = |def_id| tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id));
+ let lifetime_name = |def_id| tcx.hir().name(tcx.local_def_id_to_hir_id(def_id));
match tcx.named_bound_var(lifetime.hir_id) {
Some(rbv::ResolvedArg::StaticLifetime) => tcx.lifetimes.re_static,
@@ -250,7 +251,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
var: ty::BoundVar::from_u32(index),
kind: ty::BrNamed(def_id, name),
};
- ty::Region::new_late_bound(tcx, debruijn, br)
+ ty::Region::new_bound(tcx, debruijn, br)
}
Some(rbv::ResolvedArg::EarlyBound(def_id)) => {
@@ -258,12 +259,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local());
let generics = tcx.generics_of(item_def_id);
let index = generics.param_def_id_to_index[&def_id];
- ty::Region::new_early_bound(tcx, ty::EarlyBoundRegion { def_id, index, name })
+ ty::Region::new_early_param(tcx, ty::EarlyParamRegion { def_id, index, name })
}
Some(rbv::ResolvedArg::Free(scope, id)) => {
let name = lifetime_name(id.expect_local());
- ty::Region::new_free(tcx, scope, ty::BrNamed(id, name))
+ ty::Region::new_late_param(tcx, scope, ty::BrNamed(id, name))
// (*) -- not late-bound, won't change
}
@@ -476,7 +477,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
ty::Const::new_misc_error(tcx, ty).into()
}
}
- _ => unreachable!(),
+ (kind, arg) => span_bug!(
+ self.span,
+ "mismatched path argument for kind {kind:?}: found arg {arg:?}"
+ ),
}
}
@@ -595,12 +599,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.map(|binding| {
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::Ty(ty) => ConvertedBindingKind::Equality(respan(
+ ty.span,
+ self.ast_ty_to_ty(ty).into(),
+ )),
hir::Term::Const(c) => {
+ let span = self.tcx().def_span(c.def_id);
let c = Const::from_anon_const(self.tcx(), c.def_id);
- ConvertedBindingKind::Equality(c.into())
+ ConvertedBindingKind::Equality(respan(span, c.into()))
}
},
hir::TypeBindingKind::Constraint { bounds } => {
@@ -672,36 +678,57 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
)
}
- fn instantiate_poly_trait_ref_inner(
+ /// Given a trait bound like `Debug`, applies that trait bound the given self-type to construct
+ /// a full trait reference. The resulting trait reference is returned. This may also generate
+ /// auxiliary bounds, which are added to `bounds`.
+ ///
+ /// Example:
+ ///
+ /// ```ignore (illustrative)
+ /// poly_trait_ref = Iterator<Item = u32>
+ /// self_ty = Foo
+ /// ```
+ ///
+ /// this would return `Foo: Iterator` and add `<Foo as Iterator>::Item = u32` into `bounds`.
+ ///
+ /// **A note on binders:** against our usual convention, there is an implied binder around
+ /// the `self_ty` and `poly_trait_ref` parameters here. So they may reference bound regions.
+ /// If for example you had `for<'a> Foo<'a>: Bar<'a>`, then the `self_ty` would be `Foo<'a>`
+ /// where `'a` is a bound region at depth 0. Similarly, the `poly_trait_ref` would be
+ /// `Bar<'a>`. The returned poly-trait-ref will have this binder instantiated explicitly,
+ /// however.
+ #[instrument(level = "debug", skip(self, span, constness, bounds, speculative))]
+ pub(crate) fn instantiate_poly_trait_ref(
&self,
- hir_id: hir::HirId,
+ trait_ref: &hir::TraitRef<'_>,
span: Span,
- binding_span: Option<Span>,
constness: ty::BoundConstness,
polarity: ty::ImplPolarity,
+ self_ty: Ty<'tcx>,
bounds: &mut Bounds<'tcx>,
speculative: bool,
- trait_ref_span: Span,
- trait_def_id: DefId,
- trait_segment: &hir::PathSegment<'_>,
- args: &GenericArgs<'_>,
- infer_args: bool,
- self_ty: Ty<'tcx>,
only_self_bounds: OnlySelfBounds,
) -> GenericArgCountResult {
+ let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise());
+ let trait_segment = trait_ref.path.segments.last().unwrap();
+ let args = trait_segment.args();
+
+ self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
+ self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false);
+
let (generic_args, arg_count) = self.create_args_for_ast_path(
- trait_ref_span,
+ trait_ref.path.span,
trait_def_id,
&[],
trait_segment,
args,
- infer_args,
+ trait_segment.infer_args,
Some(self_ty),
constness,
);
let tcx = self.tcx();
- let bound_vars = tcx.late_bound_vars(hir_id);
+ let bound_vars = tcx.late_bound_vars(trait_ref.hir_ref_id);
debug!(?bound_vars);
let assoc_bindings = self.create_assoc_bindings_for_generic_args(args);
@@ -720,21 +747,22 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// since we should have emitten an error for them earlier, and they will
// not be well-formed!
if polarity == ty::ImplPolarity::Negative {
- self.tcx()
- .sess
- .delay_span_bug(binding.span, "negative trait bounds should not have bindings");
+ self.tcx().sess.span_delayed_bug(
+ binding.span,
+ "negative trait bounds should not have bindings",
+ );
continue;
}
// Specify type to assert that error was already reported in `Err` case.
let _: Result<_, ErrorGuaranteed> = self.add_predicates_for_ast_type_binding(
- hir_id,
+ trait_ref.hir_ref_id,
poly_trait_ref,
binding,
bounds,
speculative,
&mut dup_bindings,
- binding_span.unwrap_or(binding.span),
+ binding.span,
constness,
only_self_bounds,
polarity,
@@ -745,102 +773,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
arg_count
}
- /// Given a trait bound like `Debug`, applies that trait bound the given self-type to construct
- /// a full trait reference. The resulting trait reference is returned. This may also generate
- /// auxiliary bounds, which are added to `bounds`.
- ///
- /// Example:
- ///
- /// ```ignore (illustrative)
- /// poly_trait_ref = Iterator<Item = u32>
- /// self_ty = Foo
- /// ```
- ///
- /// this would return `Foo: Iterator` and add `<Foo as Iterator>::Item = u32` into `bounds`.
- ///
- /// **A note on binders:** against our usual convention, there is an implied bounder around
- /// the `self_ty` and `poly_trait_ref` parameters here. So they may reference bound regions.
- /// If for example you had `for<'a> Foo<'a>: Bar<'a>`, then the `self_ty` would be `Foo<'a>`
- /// where `'a` is a bound region at depth 0. Similarly, the `poly_trait_ref` would be
- /// `Bar<'a>`. The returned poly-trait-ref will have this binder instantiated explicitly,
- /// however.
- #[instrument(level = "debug", skip(self, span, constness, bounds, speculative))]
- pub(crate) fn instantiate_poly_trait_ref(
- &self,
- trait_ref: &hir::TraitRef<'_>,
- span: Span,
- constness: ty::BoundConstness,
- polarity: ty::ImplPolarity,
- self_ty: Ty<'tcx>,
- bounds: &mut Bounds<'tcx>,
- speculative: bool,
- only_self_bounds: OnlySelfBounds,
- ) -> GenericArgCountResult {
- let hir_id = trait_ref.hir_ref_id;
- let binding_span = None;
- let trait_ref_span = trait_ref.path.span;
- let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise());
- let trait_segment = trait_ref.path.segments.last().unwrap();
- let args = trait_segment.args();
- let infer_args = trait_segment.infer_args;
-
- self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
- self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false);
-
- self.instantiate_poly_trait_ref_inner(
- hir_id,
- span,
- binding_span,
- constness,
- polarity,
- bounds,
- speculative,
- trait_ref_span,
- trait_def_id,
- trait_segment,
- args,
- infer_args,
- self_ty,
- only_self_bounds,
- )
- }
-
- pub(crate) fn instantiate_lang_item_trait_ref(
- &self,
- lang_item: hir::LangItem,
- span: Span,
- hir_id: hir::HirId,
- args: &GenericArgs<'_>,
- self_ty: Ty<'tcx>,
- bounds: &mut Bounds<'tcx>,
- only_self_bounds: OnlySelfBounds,
- ) {
- let binding_span = Some(span);
- let constness = ty::BoundConstness::NotConst;
- let speculative = false;
- let trait_ref_span = span;
- let trait_def_id = self.tcx().require_lang_item(lang_item, Some(span));
- let trait_segment = &hir::PathSegment::invalid();
- let infer_args = false;
-
- self.instantiate_poly_trait_ref_inner(
- hir_id,
- span,
- binding_span,
- constness,
- ty::ImplPolarity::Positive,
- bounds,
- speculative,
- trait_ref_span,
- trait_def_id,
- trait_segment,
- args,
- infer_args,
- self_ty,
- only_self_bounds,
- );
- }
-
fn ast_path_to_mono_trait_ref(
&self,
span: Span,
@@ -945,7 +877,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
Applicability::MachineApplicable,
);
} else {
- match (types, traits) {
+ let mut types = types.to_vec();
+ types.sort();
+ let mut traits = traits.to_vec();
+ traits.sort();
+ match (&types[..], &traits[..]) {
([], []) => {
err.span_suggestion_verbose(
span,
@@ -1051,7 +987,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
debug!("find_bound_for_assoc_item: predicates={:#?}", predicates);
let param_name = tcx.hir().ty_param_name(ty_param_def_id);
- self.one_bound_for_assoc_type(
+ self.one_bound_for_assoc_item(
|| {
traits::transitive_bounds_that_define_assoc_item(
tcx,
@@ -1063,6 +999,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
},
param_name,
Some(ty_param_def_id),
+ ty::AssocKind::Type,
assoc_name,
span,
None,
@@ -1071,48 +1008,45 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// Checks that `bounds` contains exactly one element and reports appropriate
// errors otherwise.
- #[instrument(level = "debug", skip(self, all_candidates, ty_param_name, is_equality), ret)]
- fn one_bound_for_assoc_type<I>(
+ #[instrument(level = "debug", skip(self, all_candidates, ty_param_name, binding), ret)]
+ fn one_bound_for_assoc_item<I>(
&self,
all_candidates: impl Fn() -> I,
ty_param_name: impl Display,
ty_param_def_id: Option<LocalDefId>,
+ assoc_kind: ty::AssocKind,
assoc_name: Ident,
span: Span,
- is_equality: Option<ty::Term<'tcx>>,
+ binding: Option<&ConvertedBinding<'_, 'tcx>>,
) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed>
where
I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
{
+ let tcx = self.tcx();
+
let mut matching_candidates = all_candidates().filter(|r| {
- self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Type, assoc_name)
- });
- let mut const_candidates = all_candidates().filter(|r| {
- self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Const, assoc_name)
+ self.trait_defines_associated_item_named(r.def_id(), assoc_kind, assoc_name)
});
- let (mut bound, mut next_cand) = match (matching_candidates.next(), const_candidates.next())
- {
- (Some(bound), _) => (bound, matching_candidates.next()),
- (None, Some(bound)) => (bound, const_candidates.next()),
- (None, None) => {
- let reported = self.complain_about_assoc_type_not_found(
- all_candidates,
- &ty_param_name.to_string(),
- ty_param_def_id,
- assoc_name,
- span,
- );
- return Err(reported);
- }
+ let Some(mut bound) = matching_candidates.next() else {
+ let reported = self.complain_about_assoc_item_not_found(
+ all_candidates,
+ &ty_param_name.to_string(),
+ ty_param_def_id,
+ assoc_kind,
+ assoc_name,
+ span,
+ binding,
+ );
+ return Err(reported);
};
debug!(?bound);
// look for a candidate that is not the same as our first bound, disregarding
// whether the bound is const.
+ let mut next_cand = matching_candidates.next();
while let Some(mut bound2) = next_cand {
debug!(?bound2);
- let tcx = self.tcx();
if bound2.bound_vars() != bound.bound_vars() {
break;
}
@@ -1133,7 +1067,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.map(|(n, arg)| if host_index == n { tcx.consts.true_.into() } else { arg });
if unconsted_args.eq(bound2.skip_binder().args.iter()) {
- next_cand = matching_candidates.next().or_else(|| const_candidates.next());
+ next_cand = matching_candidates.next();
} else {
break;
}
@@ -1142,51 +1076,53 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
if let Some(bound2) = next_cand {
debug!(?bound2);
- let bounds = IntoIterator::into_iter([bound, bound2]).chain(matching_candidates);
- let mut err = if is_equality.is_some() {
- // More specific Error Index entry.
- struct_span_err!(
- self.tcx().sess,
- span,
- E0222,
- "ambiguous associated type `{}` in bounds of `{}`",
- assoc_name,
- ty_param_name
- )
- } else {
- struct_span_err!(
- self.tcx().sess,
- span,
- E0221,
- "ambiguous associated type `{}` in bounds of `{}`",
- assoc_name,
- ty_param_name
- )
- };
- err.span_label(span, format!("ambiguous associated type `{assoc_name}`"));
+ let assoc_kind_str = assoc_kind_str(assoc_kind);
+ let ty_param_name = &ty_param_name.to_string();
+ let mut err = tcx.sess.create_err(crate::errors::AmbiguousAssocItem {
+ span,
+ assoc_kind: assoc_kind_str,
+ assoc_name,
+ ty_param_name,
+ });
+ // Provide a more specific error code index entry for equality bindings.
+ err.code(
+ if let Some(binding) = binding
+ && let ConvertedBindingKind::Equality(_) = binding.kind
+ {
+ error_code!(E0222)
+ } else {
+ error_code!(E0221)
+ },
+ );
+ // FIXME(#97583): Resugar equality bounds to type/const bindings.
+ // FIXME: Turn this into a structured, translateable & more actionable suggestion.
let mut where_bounds = vec![];
- for bound in bounds {
+ for bound in [bound, bound2].into_iter().chain(matching_candidates) {
let bound_id = bound.def_id();
- let bound_span = self
- .tcx()
+ let bound_span = tcx
.associated_items(bound_id)
- .find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, bound_id)
- .and_then(|item| self.tcx().hir().span_if_local(item.def_id));
+ .find_by_name_and_kind(tcx, assoc_name, assoc_kind, bound_id)
+ .and_then(|item| tcx.hir().span_if_local(item.def_id));
if let Some(bound_span) = bound_span {
err.span_label(
bound_span,
- format!(
- "ambiguous `{assoc_name}` from `{}`",
- bound.print_only_trait_path(),
- ),
+ format!("ambiguous `{assoc_name}` from `{}`", bound.print_trait_sugared(),),
);
- if let Some(constraint) = &is_equality {
- where_bounds.push(format!(
- " T: {trait}::{assoc_name} = {constraint}",
- trait=bound.print_only_trait_path(),
- ));
+ if let Some(binding) = binding {
+ match binding.kind {
+ ConvertedBindingKind::Equality(term) => {
+ // FIXME(#97583): This isn't syntactically well-formed!
+ where_bounds.push(format!(
+ " T: {trait}::{assoc_name} = {term}",
+ trait = bound.print_only_trait_path(),
+ term = term.node,
+ ));
+ }
+ // FIXME: Provide a suggestion.
+ ConvertedBindingKind::Constraint(_bounds) => {}
+ }
} else {
err.span_suggestion_verbose(
span.with_hi(assoc_name.span.lo()),
@@ -1197,7 +1133,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
} else {
err.note(format!(
- "associated type `{ty_param_name}` could derive from `{}`",
+ "associated {assoc_kind_str} `{assoc_name}` could derive from `{}`",
bound.print_only_trait_path(),
));
}
@@ -1218,46 +1154,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
Ok(bound)
}
- #[instrument(level = "debug", skip(self, all_candidates, ty_name), ret)]
- fn one_bound_for_assoc_method(
- &self,
- all_candidates: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
- ty_name: impl Display,
- assoc_name: Ident,
- span: Span,
- ) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed> {
- let mut matching_candidates = all_candidates.filter(|r| {
- self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Fn, assoc_name)
- });
-
- let candidate = match matching_candidates.next() {
- Some(candidate) => candidate,
- None => {
- return Err(self.tcx().sess.emit_err(
- crate::errors::ReturnTypeNotationMissingMethod {
- span,
- ty_name: ty_name.to_string(),
- assoc_name: assoc_name.name,
- },
- ));
- }
- };
-
- if let Some(conflicting_candidate) = matching_candidates.next() {
- return Err(self.tcx().sess.emit_err(
- crate::errors::ReturnTypeNotationConflictingBound {
- span,
- ty_name: ty_name.to_string(),
- assoc_name: assoc_name.name,
- first_bound: candidate.print_only_trait_path(),
- second_bound: conflicting_candidate.print_only_trait_path(),
- },
- ));
- }
-
- Ok(candidate)
- }
-
// 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
@@ -1415,11 +1311,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// trait reference.
let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else {
// A cycle error occurred, most likely.
- let guar = tcx.sess.delay_span_bug(span, "expected cycle error");
+ let guar = tcx.sess.span_delayed_bug(span, "expected cycle error");
return Err(guar);
};
- self.one_bound_for_assoc_type(
+ self.one_bound_for_assoc_item(
|| {
traits::supertraits(
tcx,
@@ -1428,6 +1324,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
},
kw::SelfUpper,
None,
+ ty::AssocKind::Type,
assoc_ident,
span,
None,
@@ -1508,15 +1405,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
};
let trait_did = bound.def_id();
- let Some(assoc_ty_did) = self.lookup_assoc_ty(assoc_ident, hir_ref_id, span, trait_did)
- else {
- // Assume that if it's not matched, there must be a const defined with the same name
- // but it was used in a type position.
- let msg = format!("found associated const `{assoc_ident}` when type was expected");
- let guar = tcx.sess.struct_span_err(span, msg).emit();
- return Err(guar);
- };
-
+ let assoc_ty_did = self.lookup_assoc_ty(assoc_ident, hir_ref_id, span, trait_did).unwrap();
let ty = self.projected_ty_from_poly_trait_ref(span, assoc_ty_did, assoc_segment, bound);
if let Some(variant_def_id) = variant_resolution {
@@ -1545,8 +1434,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
format!("<{} as {}>::{}", qself_ty, tcx.item_name(trait_did), assoc_ident),
Applicability::MachineApplicable,
);
-
- lint
},
);
}
@@ -1602,134 +1489,110 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// FIXME(inherent_associated_types): Acquiring the ParamEnv this early leads to cycle errors
// when inside of an ADT (#108491) or where clause.
let param_env = tcx.param_env(block.owner);
- let cause = ObligationCause::misc(span, block.owner.def_id);
-
- let mut fulfillment_errors = Vec::new();
- let mut applicable_candidates: Vec<_> = infcx.probe(|_| {
- // Regions are not considered during selection.
- let self_ty = self_ty
- .fold_with(&mut BoundVarEraser { tcx, universe: infcx.create_next_universe() });
-
- struct BoundVarEraser<'tcx> {
- tcx: TyCtxt<'tcx>,
- universe: ty::UniverseIndex,
- }
- // FIXME(non_lifetime_binders): Don't assign the same universe to each placeholder.
- impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarEraser<'tcx> {
- fn interner(&self) -> TyCtxt<'tcx> {
- self.tcx
- }
+ let mut universes = if self_ty.has_escaping_bound_vars() {
+ vec![None; self_ty.outer_exclusive_binder().as_usize()]
+ } else {
+ vec![]
+ };
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
- if r.is_late_bound() { self.tcx.lifetimes.re_erased } else { r }
- }
+ let (impl_, (assoc_item, def_scope)) =
+ crate::traits::project::with_replaced_escaping_bound_vars(
+ infcx,
+ &mut universes,
+ self_ty,
+ |self_ty| {
+ self.select_inherent_assoc_type_candidates(
+ infcx, name, span, self_ty, param_env, candidates,
+ )
+ },
+ )?;
+
+ self.check_assoc_ty(assoc_item, name, def_scope, block, span);
+
+ // FIXME(fmease): Currently creating throwaway `parent_args` to please
+ // `create_args_for_associated_item`. Modify the latter instead (or sth. similar) to
+ // not require the parent args logic.
+ let parent_args = ty::GenericArgs::identity_for_item(tcx, impl_);
+ let args = self.create_args_for_associated_item(span, assoc_item, segment, parent_args);
+ let args = tcx.mk_args_from_iter(
+ std::iter::once(ty::GenericArg::from(self_ty))
+ .chain(args.into_iter().skip(parent_args.len())),
+ );
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
- match *ty.kind() {
- ty::Bound(_, bv) => Ty::new_placeholder(
- self.tcx,
- ty::PlaceholderType { universe: self.universe, bound: bv },
- ),
- _ => ty.super_fold_with(self),
- }
- }
+ let ty = Ty::new_alias(tcx, ty::Inherent, ty::AliasTy::new(tcx, assoc_item, args));
- fn fold_const(
- &mut self,
- ct: ty::Const<'tcx>,
- ) -> <TyCtxt<'tcx> as rustc_type_ir::Interner>::Const {
- assert!(!ct.ty().has_escaping_bound_vars());
-
- match ct.kind() {
- ty::ConstKind::Bound(_, bv) => ty::Const::new_placeholder(
- self.tcx,
- ty::PlaceholderConst { universe: self.universe, bound: bv },
- ct.ty(),
- ),
- _ => ct.super_fold_with(self),
- }
- }
- }
+ Ok(Some((ty, assoc_item)))
+ }
- let InferOk { value: self_ty, obligations } =
- infcx.at(&cause, param_env).normalize(self_ty);
+ fn select_inherent_assoc_type_candidates(
+ &self,
+ infcx: &InferCtxt<'tcx>,
+ name: Ident,
+ span: Span,
+ self_ty: Ty<'tcx>,
+ param_env: ParamEnv<'tcx>,
+ candidates: Vec<(DefId, (DefId, DefId))>,
+ ) -> Result<(DefId, (DefId, DefId)), ErrorGuaranteed> {
+ let tcx = self.tcx();
+ let mut fulfillment_errors = Vec::new();
- candidates
- .iter()
- .copied()
- .filter(|&(impl_, _)| {
- infcx.probe(|_| {
- let ocx = ObligationCtxt::new(&infcx);
- ocx.register_obligations(obligations.clone());
-
- let impl_args = infcx.fresh_args_for_item(span, impl_);
- let impl_ty = tcx.type_of(impl_).instantiate(tcx, impl_args);
- let impl_ty = ocx.normalize(&cause, param_env, impl_ty);
-
- // Check that the self types can be related.
- // FIXME(inherent_associated_types): Should we use `eq` here? Method probing uses
- // `sup` for this situtation, too. What for? To constrain inference variables?
- if ocx.sup(&ObligationCause::dummy(), param_env, impl_ty, self_ty).is_err()
- {
- return false;
- }
+ let applicable_candidates: Vec<_> = candidates
+ .iter()
+ .copied()
+ .filter(|&(impl_, _)| {
+ infcx.probe(|_| {
+ let ocx = ObligationCtxt::new(infcx);
+ let self_ty = ocx.normalize(&ObligationCause::dummy(), param_env, self_ty);
+
+ let impl_args = infcx.fresh_args_for_item(span, impl_);
+ let impl_ty = tcx.type_of(impl_).instantiate(tcx, impl_args);
+ let impl_ty = ocx.normalize(&ObligationCause::dummy(), param_env, impl_ty);
+
+ // Check that the self types can be related.
+ if ocx.eq(&ObligationCause::dummy(), param_env, impl_ty, self_ty).is_err() {
+ return false;
+ }
- // Check whether the impl imposes obligations we have to worry about.
- let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_args);
- let impl_bounds = ocx.normalize(&cause, param_env, impl_bounds);
- let impl_obligations = traits::predicates_for_generics(
- |_, _| cause.clone(),
- param_env,
- impl_bounds,
- );
- ocx.register_obligations(impl_obligations);
+ // Check whether the impl imposes obligations we have to worry about.
+ let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_args);
+ let impl_bounds =
+ ocx.normalize(&ObligationCause::dummy(), param_env, impl_bounds);
+ let impl_obligations = traits::predicates_for_generics(
+ |_, _| ObligationCause::dummy(),
+ param_env,
+ impl_bounds,
+ );
+ ocx.register_obligations(impl_obligations);
- let mut errors = ocx.select_where_possible();
- if !errors.is_empty() {
- fulfillment_errors.append(&mut errors);
- return false;
- }
+ let mut errors = ocx.select_where_possible();
+ if !errors.is_empty() {
+ fulfillment_errors.append(&mut errors);
+ return false;
+ }
- true
- })
+ true
})
- .collect()
- });
+ })
+ .collect();
- if applicable_candidates.len() > 1 {
- return Err(self.complain_about_ambiguous_inherent_assoc_type(
+ match &applicable_candidates[..] {
+ &[] => Err(self.complain_about_inherent_assoc_type_not_found(
name,
- applicable_candidates.into_iter().map(|(_, (candidate, _))| candidate).collect(),
+ self_ty,
+ candidates,
+ fulfillment_errors,
span,
- ));
- }
+ )),
- if let Some((impl_, (assoc_item, def_scope))) = applicable_candidates.pop() {
- self.check_assoc_ty(assoc_item, name, def_scope, block, span);
-
- // FIXME(fmease): Currently creating throwaway `parent_args` to please
- // `create_args_for_associated_item`. Modify the latter instead (or sth. similar) to
- // not require the parent args logic.
- let parent_args = ty::GenericArgs::identity_for_item(tcx, impl_);
- let args = self.create_args_for_associated_item(span, assoc_item, segment, parent_args);
- let args = tcx.mk_args_from_iter(
- std::iter::once(ty::GenericArg::from(self_ty))
- .chain(args.into_iter().skip(parent_args.len())),
- );
+ &[applicable_candidate] => Ok(applicable_candidate),
- let ty = Ty::new_alias(tcx, ty::Inherent, ty::AliasTy::new(tcx, assoc_item, args));
-
- return Ok(Some((ty, assoc_item)));
+ &[_, ..] => Err(self.complain_about_ambiguous_inherent_assoc_type(
+ name,
+ applicable_candidates.into_iter().map(|(_, (candidate, _))| candidate).collect(),
+ span,
+ )),
}
-
- Err(self.complain_about_inherent_assoc_type_not_found(
- name,
- self_ty,
- candidates,
- fulfillment_errors,
- span,
- ))
}
fn lookup_assoc_ty(
@@ -1753,8 +1616,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let tcx = self.tcx();
let (ident, def_scope) = tcx.adjust_ident_and_get_scope(name, scope, block);
- // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead
- // of calling `find_by_name_and_kind`.
+ // We have already adjusted the item name above, so compare with `.normalize_to_macros_2_0()`
+ // instead of calling `filter_by_name_and_kind` which would needlessly normalize the
+ // `ident` again and again.
let item = tcx.associated_items(scope).in_definition_order().find(|i| {
i.kind.namespace() == Namespace::TypeNS
&& i.ident(tcx).normalize_to_macros_2_0() == ident
@@ -1869,7 +1733,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let parent_def_id = def_id
.as_local()
- .map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
+ .map(|def_id| tcx.local_def_id_to_hir_id(def_id))
.map(|hir_id| tcx.hir().get_parent_item(hir_id).to_def_id());
debug!("qpath_to_ty: parent_def_id={:?}", parent_def_id);
@@ -1973,7 +1837,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
types_and_spans[..types_and_spans.len() - 1]
.iter()
.map(|(x, _)| x.as_str())
- .intersperse(&", ")
+ .intersperse(", ")
.collect::<String>()
),
[(only, _)] => only.to_string(),
@@ -2008,7 +1872,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
"s",
),
[only] => (only.to_string(), ""),
- [] => unreachable!(),
+ [] => unreachable!("expected at least one generic to prohibit"),
};
let last_span = *arg_spans.last().unwrap();
let span: MultiSpan = arg_spans.into();
@@ -2396,7 +2260,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");
+ .span_delayed_bug(path.span, "path with `Res::Err` but no error emitted");
self.set_tainted_by_errors(e);
Ty::new_error(self.tcx(), e)
}
@@ -2543,7 +2407,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.map(|(ty, _, _)| ty)
.unwrap_or_else(|guar| Ty::new_error(tcx, guar))
}
- &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 (args, _) = self.create_args_for_ast_path(
span,
@@ -2617,8 +2481,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
if let Some(i) = (param.index as usize).checked_sub(generics.count() - lifetimes.len())
{
// Resolve our own lifetime parameters.
- let GenericParamDefKind::Lifetime { .. } = param.kind else { bug!() };
- let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] else { bug!() };
+ let GenericParamDefKind::Lifetime { .. } = param.kind else {
+ span_bug!(
+ tcx.def_span(param.def_id),
+ "only expected lifetime for opaque's own generics, got {:?}",
+ param.kind
+ );
+ };
+ let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] else {
+ bug!(
+ "expected lifetime argument for param {param:?}, found {:?}",
+ &lifetimes[i]
+ )
+ };
self.ast_region_to_region(lifetime, None).into()
} else {
tcx.mk_param_from_def(param)
@@ -2777,7 +2652,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let hir = tcx.hir();
let hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), ident, .. }) =
- hir.get(fn_hir_id)
+ tcx.hir_node(fn_hir_id)
else {
return None;
};
@@ -2845,6 +2720,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
/// provided, if they provided one, and otherwise search the supertypes of trait bounds
/// for region bounds. It may be that we can derive no bound at all, in which case
/// we return `None`.
+ #[instrument(level = "debug", skip(self, span), ret)]
fn compute_object_lifetime_bound(
&self,
span: Span,
@@ -2853,8 +2729,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
{
let tcx = self.tcx();
- debug!("compute_opt_region_bound(existential_predicates={:?})", existential_predicates);
-
// No explicit region bound specified. Therefore, examine trait
// bounds and see if we can derive region bounds from those.
let derived_region_bounds = object_region_bounds(tcx, existential_predicates);
@@ -2881,3 +2755,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
Some(r)
}
}
+
+fn assoc_kind_str(kind: ty::AssocKind) -> &'static str {
+ match kind {
+ ty::AssocKind::Fn => "function",
+ ty::AssocKind::Const => "constant",
+ ty::AssocKind::Type => "type",
+ }
+}
diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
index 00ff3f836..dd5deb6f2 100644
--- a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
@@ -1,7 +1,7 @@
use crate::astconv::{GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds};
use crate::bounds::Bounds;
use crate::errors::TraitObjectDeclaredWithNoTraits;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
@@ -14,7 +14,6 @@ use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
use rustc_trait_selection::traits::{self, astconv_object_safety_violations};
use smallvec::{smallvec, SmallVec};
-use std::collections::BTreeSet;
use super::AstConv;
@@ -74,7 +73,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
| ty::ClauseKind::ConstArgHasType(..)
| ty::ClauseKind::WellFormed(_)
| ty::ClauseKind::ConstEvaluatable(_) => {
- bug!()
+ span_bug!(span, "did not expect {pred} clause in object bounds");
}
}
}
@@ -107,6 +106,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
trait here instead: `trait NewTrait: {} {{}}`",
regular_traits
.iter()
+ // FIXME: This should `print_sugared`, but also needs to integrate projection bounds...
.map(|t| t.trait_ref().print_only_trait_path().to_string())
.collect::<Vec<_>>()
.join(" + "),
@@ -148,8 +148,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 mut associated_types: FxIndexMap<Span, FxIndexSet<DefId>> = FxIndexMap::default();
let regular_traits_refs_spans = trait_bounds
.into_iter()
@@ -327,7 +326,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
false
});
if references_self {
- let guar = tcx.sess.delay_span_bug(
+ let guar = tcx.sess.span_delayed_bug(
span,
"trait object projection bounds reference `Self`",
);