Rollup merge of #139669 - nnethercote:overhaul-AssocItem, r=oli-obk

Overhaul `AssocItem`

`AssocItem` has multiple fields that only make sense some of the time. E.g. the `name` can be empty if it's an RPITIT associated type. It's clearer and less error prone if these fields are moved to the relevant `kind` variants.

r? ``@fee1-dead``
This commit is contained in:
Stuart Cook 2025-04-15 15:47:27 +10:00 committed by GitHub
commit 13cd5256ac
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
86 changed files with 609 additions and 546 deletions

View file

@ -85,7 +85,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
.delegation_fn_sigs .delegation_fn_sigs
.get(&local_def_id) .get(&local_def_id)
.is_some_and(|sig| sig.has_self), .is_some_and(|sig| sig.has_self),
None => self.tcx.associated_item(def_id).fn_has_self_parameter, None => self.tcx.associated_item(def_id).is_method(),
}, },
_ => span_bug!(span, "unexpected DefKind for delegation item"), _ => span_bug!(span, "unexpected DefKind for delegation item"),
} }

View file

@ -647,7 +647,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
&& tc.polarity() == ty::PredicatePolarity::Positive && tc.polarity() == ty::PredicatePolarity::Positive
&& supertrait_def_ids(tcx, tc.def_id()) && supertrait_def_ids(tcx, tc.def_id())
.flat_map(|trait_did| tcx.associated_items(trait_did).in_definition_order()) .flat_map(|trait_did| tcx.associated_items(trait_did).in_definition_order())
.any(|item| item.fn_has_self_parameter) .any(|item| item.is_method())
}) })
}) { }) {
return None; return None;

View file

@ -1,6 +1,6 @@
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
use rustc_hir::LangItem; use rustc_hir::LangItem;
use rustc_middle::ty::{AssocKind, GenericArg}; use rustc_middle::ty::{AssocTag, GenericArg};
use rustc_session::config::EntryFnType; use rustc_session::config::EntryFnType;
use rustc_span::{DUMMY_SP, Ident}; use rustc_span::{DUMMY_SP, Ident};
@ -107,7 +107,7 @@ pub(crate) fn maybe_create_entry_wrapper(
.find_by_ident_and_kind( .find_by_ident_and_kind(
tcx, tcx,
Ident::from_str("report"), Ident::from_str("report"),
AssocKind::Fn, AssocTag::Fn,
termination_trait, termination_trait,
) )
.unwrap(); .unwrap();

View file

@ -443,13 +443,13 @@ fn best_definition_site_of_opaque<'tcx>(
let impl_def_id = tcx.local_parent(parent); let impl_def_id = tcx.local_parent(parent);
for assoc in tcx.associated_items(impl_def_id).in_definition_order() { for assoc in tcx.associated_items(impl_def_id).in_definition_order() {
match assoc.kind { match assoc.kind {
ty::AssocKind::Const | ty::AssocKind::Fn => { ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => {
if let ControlFlow::Break(span) = locator.check(assoc.def_id.expect_local()) if let ControlFlow::Break(span) = locator.check(assoc.def_id.expect_local())
{ {
return Some(span); return Some(span);
} }
} }
ty::AssocKind::Type => {} ty::AssocKind::Type { .. } => {}
} }
} }
@ -740,7 +740,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
for &assoc_item in assoc_items.in_definition_order() { for &assoc_item in assoc_items.in_definition_order() {
match assoc_item.kind { match assoc_item.kind {
ty::AssocKind::Type if assoc_item.defaultness(tcx).has_value() => { ty::AssocKind::Type { .. } if assoc_item.defaultness(tcx).has_value() => {
let trait_args = GenericArgs::identity_for_item(tcx, def_id); let trait_args = GenericArgs::identity_for_item(tcx, def_id);
let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds( let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds(
tcx, tcx,
@ -942,7 +942,7 @@ fn check_impl_items_against_trait<'tcx>(
if res.is_ok() { if res.is_ok() {
match ty_impl_item.kind { match ty_impl_item.kind {
ty::AssocKind::Fn => { ty::AssocKind::Fn { .. } => {
compare_impl_item::refine::check_refining_return_position_impl_trait_in_trait( compare_impl_item::refine::check_refining_return_position_impl_trait_in_trait(
tcx, tcx,
ty_impl_item, ty_impl_item,
@ -952,8 +952,8 @@ fn check_impl_items_against_trait<'tcx>(
.instantiate_identity(), .instantiate_identity(),
); );
} }
ty::AssocKind::Const => {} ty::AssocKind::Const { .. } => {}
ty::AssocKind::Type => {} ty::AssocKind::Type { .. } => {}
} }
} }

View file

@ -43,9 +43,11 @@ pub(super) fn compare_impl_item(
debug!(?impl_trait_ref); debug!(?impl_trait_ref);
match impl_item.kind { match impl_item.kind {
ty::AssocKind::Fn => compare_impl_method(tcx, impl_item, trait_item, impl_trait_ref), ty::AssocKind::Fn { .. } => compare_impl_method(tcx, impl_item, trait_item, impl_trait_ref),
ty::AssocKind::Type => compare_impl_ty(tcx, impl_item, trait_item, impl_trait_ref), ty::AssocKind::Type { .. } => compare_impl_ty(tcx, impl_item, trait_item, impl_trait_ref),
ty::AssocKind::Const => compare_impl_const(tcx, impl_item, trait_item, impl_trait_ref), ty::AssocKind::Const { .. } => {
compare_impl_const(tcx, impl_item, trait_item, impl_trait_ref)
}
} }
} }
@ -654,7 +656,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
cause.span, cause.span,
E0053, E0053,
"method `{}` has an incompatible return type for trait", "method `{}` has an incompatible return type for trait",
trait_m.name trait_m.name()
); );
infcx.err_ctxt().note_type_err( infcx.err_ctxt().note_type_err(
&mut diag, &mut diag,
@ -1032,11 +1034,11 @@ fn report_trait_method_mismatch<'tcx>(
impl_err_span, impl_err_span,
E0053, E0053,
"method `{}` has an incompatible type for trait", "method `{}` has an incompatible type for trait",
trait_m.name trait_m.name()
); );
match &terr { match &terr {
TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0) TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
if trait_m.fn_has_self_parameter => if trait_m.is_method() =>
{ {
let ty = trait_sig.inputs()[0]; let ty = trait_sig.inputs()[0];
let sugg = get_self_string(ty, |ty| ty == impl_trait_ref.self_ty()); let sugg = get_self_string(ty, |ty| ty == impl_trait_ref.self_ty());
@ -1255,7 +1257,7 @@ fn compare_self_type<'tcx>(
get_self_string(self_arg_ty, can_eq_self) get_self_string(self_arg_ty, can_eq_self)
}; };
match (trait_m.fn_has_self_parameter, impl_m.fn_has_self_parameter) { match (trait_m.is_method(), impl_m.is_method()) {
(false, false) | (true, true) => {} (false, false) | (true, true) => {}
(false, true) => { (false, true) => {
@ -1266,14 +1268,14 @@ fn compare_self_type<'tcx>(
impl_m_span, impl_m_span,
E0185, E0185,
"method `{}` has a `{}` declaration in the impl, but not in the trait", "method `{}` has a `{}` declaration in the impl, but not in the trait",
trait_m.name, trait_m.name(),
self_descr self_descr
); );
err.span_label(impl_m_span, format!("`{self_descr}` used in impl")); err.span_label(impl_m_span, format!("`{self_descr}` used in impl"));
if let Some(span) = tcx.hir_span_if_local(trait_m.def_id) { if let Some(span) = tcx.hir_span_if_local(trait_m.def_id) {
err.span_label(span, format!("trait method declared without `{self_descr}`")); err.span_label(span, format!("trait method declared without `{self_descr}`"));
} else { } else {
err.note_trait_signature(trait_m.name, trait_m.signature(tcx)); err.note_trait_signature(trait_m.name(), trait_m.signature(tcx));
} }
return Err(err.emit_unless(delay)); return Err(err.emit_unless(delay));
} }
@ -1286,14 +1288,14 @@ fn compare_self_type<'tcx>(
impl_m_span, impl_m_span,
E0186, E0186,
"method `{}` has a `{}` declaration in the trait, but not in the impl", "method `{}` has a `{}` declaration in the trait, but not in the impl",
trait_m.name, trait_m.name(),
self_descr self_descr
); );
err.span_label(impl_m_span, format!("expected `{self_descr}` in impl")); err.span_label(impl_m_span, format!("expected `{self_descr}` in impl"));
if let Some(span) = tcx.hir_span_if_local(trait_m.def_id) { if let Some(span) = tcx.hir_span_if_local(trait_m.def_id) {
err.span_label(span, format!("`{self_descr}` used in trait")); err.span_label(span, format!("`{self_descr}` used in trait"));
} else { } else {
err.note_trait_signature(trait_m.name, trait_m.signature(tcx)); err.note_trait_signature(trait_m.name(), trait_m.signature(tcx));
} }
return Err(err.emit_unless(delay)); return Err(err.emit_unless(delay));
@ -1363,7 +1365,7 @@ fn compare_number_of_generics<'tcx>(
let mut err_occurred = None; let mut err_occurred = None;
for (kind, trait_count, impl_count) in matchings { for (kind, trait_count, impl_count) in matchings {
if impl_count != trait_count { if impl_count != trait_count {
let arg_spans = |kind: ty::AssocKind, generics: &hir::Generics<'_>| { let arg_spans = |item: &ty::AssocItem, generics: &hir::Generics<'_>| {
let mut spans = generics let mut spans = generics
.params .params
.iter() .iter()
@ -1373,7 +1375,7 @@ fn compare_number_of_generics<'tcx>(
} => { } => {
// A fn can have an arbitrary number of extra elided lifetimes for the // A fn can have an arbitrary number of extra elided lifetimes for the
// same signature. // same signature.
!matches!(kind, ty::AssocKind::Fn) !item.is_fn()
} }
_ => true, _ => true,
}) })
@ -1386,7 +1388,7 @@ fn compare_number_of_generics<'tcx>(
}; };
let (trait_spans, impl_trait_spans) = if let Some(def_id) = trait_.def_id.as_local() { let (trait_spans, impl_trait_spans) = if let Some(def_id) = trait_.def_id.as_local() {
let trait_item = tcx.hir_expect_trait_item(def_id); let trait_item = tcx.hir_expect_trait_item(def_id);
let arg_spans: Vec<Span> = arg_spans(trait_.kind, trait_item.generics); let arg_spans: Vec<Span> = arg_spans(&trait_, trait_item.generics);
let impl_trait_spans: Vec<Span> = trait_item let impl_trait_spans: Vec<Span> = trait_item
.generics .generics
.params .params
@ -1412,7 +1414,7 @@ fn compare_number_of_generics<'tcx>(
_ => None, _ => None,
}) })
.collect(); .collect();
let spans = arg_spans(impl_.kind, impl_item.generics); let spans = arg_spans(&impl_, impl_item.generics);
let span = spans.first().copied(); let span = spans.first().copied();
let mut err = tcx.dcx().struct_span_err( let mut err = tcx.dcx().struct_span_err(
@ -1421,7 +1423,7 @@ fn compare_number_of_generics<'tcx>(
"{} `{}` has {} {kind} parameter{} but its trait \ "{} `{}` has {} {kind} parameter{} but its trait \
declaration has {} {kind} parameter{}", declaration has {} {kind} parameter{}",
item_kind, item_kind,
trait_.name, trait_.name(),
impl_count, impl_count,
pluralize!(impl_count), pluralize!(impl_count),
trait_count, trait_count,
@ -1512,7 +1514,7 @@ fn compare_number_of_method_arguments<'tcx>(
impl_span, impl_span,
E0050, E0050,
"method `{}` has {} but the declaration in trait `{}` has {}", "method `{}` has {} but the declaration in trait `{}` has {}",
trait_m.name, trait_m.name(),
potentially_plural_count(impl_number_args, "parameter"), potentially_plural_count(impl_number_args, "parameter"),
tcx.def_path_str(trait_m.def_id), tcx.def_path_str(trait_m.def_id),
trait_number_args trait_number_args
@ -1527,7 +1529,7 @@ fn compare_number_of_method_arguments<'tcx>(
), ),
); );
} else { } else {
err.note_trait_signature(trait_m.name, trait_m.signature(tcx)); err.note_trait_signature(trait_m.name(), trait_m.signature(tcx));
} }
err.span_label( err.span_label(
@ -1581,7 +1583,7 @@ fn compare_synthetic_generics<'tcx>(
impl_span, impl_span,
E0643, E0643,
"method `{}` has incompatible signature for trait", "method `{}` has incompatible signature for trait",
trait_m.name trait_m.name()
); );
err.span_label(trait_span, "declaration in trait here"); err.span_label(trait_span, "declaration in trait here");
if impl_synthetic { if impl_synthetic {
@ -1703,7 +1705,7 @@ fn compare_generic_param_kinds<'tcx>(
trait_item: ty::AssocItem, trait_item: ty::AssocItem,
delay: bool, delay: bool,
) -> Result<(), ErrorGuaranteed> { ) -> Result<(), ErrorGuaranteed> {
assert_eq!(impl_item.kind, trait_item.kind); assert_eq!(impl_item.as_tag(), trait_item.as_tag());
let ty_const_params_of = |def_id| { let ty_const_params_of = |def_id| {
tcx.generics_of(def_id).own_params.iter().filter(|param| { tcx.generics_of(def_id).own_params.iter().filter(|param| {
@ -1741,7 +1743,7 @@ fn compare_generic_param_kinds<'tcx>(
E0053, E0053,
"{} `{}` has an incompatible generic parameter for trait `{}`", "{} `{}` has an incompatible generic parameter for trait `{}`",
impl_item.descr(), impl_item.descr(),
trait_item.name, trait_item.name(),
&tcx.def_path_str(tcx.parent(trait_item.def_id)) &tcx.def_path_str(tcx.parent(trait_item.def_id))
); );
@ -1877,7 +1879,7 @@ fn compare_const_predicate_entailment<'tcx>(
cause.span, cause.span,
E0326, E0326,
"implemented const `{}` has an incompatible type for trait", "implemented const `{}` has an incompatible type for trait",
trait_ct.name trait_ct.name()
); );
let trait_c_span = trait_ct.def_id.as_local().map(|trait_ct_def_id| { let trait_c_span = trait_ct.def_id.as_local().map(|trait_ct_def_id| {
@ -2235,16 +2237,19 @@ fn param_env_with_gat_bounds<'tcx>(
// of the RPITITs associated with the same body. This is because checking // of the RPITITs associated with the same body. This is because checking
// the item bounds of RPITITs often involves nested RPITITs having to prove // the item bounds of RPITITs often involves nested RPITITs having to prove
// bounds about themselves. // bounds about themselves.
let impl_tys_to_install = match impl_ty.opt_rpitit_info { let impl_tys_to_install = match impl_ty.kind {
None => vec![impl_ty], ty::AssocKind::Type {
Some( data:
ty::AssocTypeData::Rpitit(
ty::ImplTraitInTraitData::Impl { fn_def_id } ty::ImplTraitInTraitData::Impl { fn_def_id }
| ty::ImplTraitInTraitData::Trait { fn_def_id, .. }, | ty::ImplTraitInTraitData::Trait { fn_def_id, .. },
) => tcx ),
} => tcx
.associated_types_for_impl_traits_in_associated_fn(fn_def_id) .associated_types_for_impl_traits_in_associated_fn(fn_def_id)
.iter() .iter()
.map(|def_id| tcx.associated_item(*def_id)) .map(|def_id| tcx.associated_item(*def_id))
.collect(), .collect(),
_ => vec![impl_ty],
}; };
for impl_ty in impl_tys_to_install { for impl_ty in impl_tys_to_install {

View file

@ -205,7 +205,7 @@ fn missing_items_err(
let missing_items_msg = missing_items let missing_items_msg = missing_items
.clone() .clone()
.map(|trait_item| trait_item.name.to_string()) .map(|trait_item| trait_item.name().to_string())
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("`, `"); .join("`, `");
@ -236,7 +236,7 @@ fn missing_items_err(
let code = format!("{padding}{snippet}\n{padding}"); let code = format!("{padding}{snippet}\n{padding}");
if let Some(span) = tcx.hir_span_if_local(trait_item.def_id) { if let Some(span) = tcx.hir_span_if_local(trait_item.def_id) {
missing_trait_item_label missing_trait_item_label
.push(errors::MissingTraitItemLabel { span, item: trait_item.name }); .push(errors::MissingTraitItemLabel { span, item: trait_item.name() });
missing_trait_item.push(errors::MissingTraitItemSuggestion { missing_trait_item.push(errors::MissingTraitItemSuggestion {
span: sugg_sp, span: sugg_sp,
code, code,
@ -407,14 +407,14 @@ fn fn_sig_suggestion<'tcx>(
.enumerate() .enumerate()
.map(|(i, ty)| { .map(|(i, ty)| {
Some(match ty.kind() { Some(match ty.kind() {
ty::Param(_) if assoc.fn_has_self_parameter && i == 0 => "self".to_string(), ty::Param(_) if assoc.is_method() && i == 0 => "self".to_string(),
ty::Ref(reg, ref_ty, mutability) if i == 0 => { ty::Ref(reg, ref_ty, mutability) if i == 0 => {
let reg = format!("{reg} "); let reg = format!("{reg} ");
let reg = match &reg[..] { let reg = match &reg[..] {
"'_ " | " " => "", "'_ " | " " => "",
reg => reg, reg => reg,
}; };
if assoc.fn_has_self_parameter { if assoc.is_method() {
match ref_ty.kind() { match ref_ty.kind() {
ty::Param(param) if param.name == kw::SelfUpper => { ty::Param(param) if param.name == kw::SelfUpper => {
format!("&{}{}self", reg, mutability.prefix_str()) format!("&{}{}self", reg, mutability.prefix_str())
@ -427,7 +427,7 @@ fn fn_sig_suggestion<'tcx>(
} }
} }
_ => { _ => {
if assoc.fn_has_self_parameter && i == 0 { if assoc.is_method() && i == 0 {
format!("self: {ty}") format!("self: {ty}")
} else { } else {
format!("_: {ty}") format!("_: {ty}")
@ -489,7 +489,7 @@ fn suggestion_signature<'tcx>(
); );
match assoc.kind { match assoc.kind {
ty::AssocKind::Fn => fn_sig_suggestion( ty::AssocKind::Fn { .. } => fn_sig_suggestion(
tcx, tcx,
tcx.liberate_late_bound_regions( tcx.liberate_late_bound_regions(
assoc.def_id, assoc.def_id,
@ -499,14 +499,14 @@ fn suggestion_signature<'tcx>(
tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args), tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args),
assoc, assoc,
), ),
ty::AssocKind::Type => { ty::AssocKind::Type { .. } => {
let (generics, where_clauses) = bounds_from_generic_predicates( let (generics, where_clauses) = bounds_from_generic_predicates(
tcx, tcx,
tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args), tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args),
); );
format!("type {}{generics} = /* Type */{where_clauses};", assoc.name) format!("type {}{generics} = /* Type */{where_clauses};", assoc.name())
} }
ty::AssocKind::Const => { ty::AssocKind::Const { name } => {
let ty = tcx.type_of(assoc.def_id).instantiate_identity(); let ty = tcx.type_of(assoc.def_id).instantiate_identity();
let val = tcx let val = tcx
.infer_ctxt() .infer_ctxt()
@ -514,7 +514,7 @@ fn suggestion_signature<'tcx>(
.err_ctxt() .err_ctxt()
.ty_kind_suggestion(tcx.param_env(assoc.def_id), ty) .ty_kind_suggestion(tcx.param_env(assoc.def_id), ty)
.unwrap_or_else(|| "value".to_string()); .unwrap_or_else(|| "value".to_string());
format!("const {}: {} = {};", assoc.name, ty, val) format!("const {}: {} = {};", name, ty, val)
} }
} }
} }

View file

@ -408,7 +408,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
let gat_def_id = gat_item.def_id.expect_local(); let gat_def_id = gat_item.def_id.expect_local();
let gat_item = tcx.associated_item(gat_def_id); let gat_item = tcx.associated_item(gat_def_id);
// If this item is not an assoc ty, or has no args, then it's not a GAT // If this item is not an assoc ty, or has no args, then it's not a GAT
if gat_item.kind != ty::AssocKind::Type { if !gat_item.is_type() {
continue; continue;
} }
let gat_generics = tcx.generics_of(gat_def_id); let gat_generics = tcx.generics_of(gat_def_id);
@ -432,7 +432,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
let item_required_bounds = match tcx.associated_item(item_def_id).kind { let item_required_bounds = match tcx.associated_item(item_def_id).kind {
// In our example, this corresponds to `into_iter` method // In our example, this corresponds to `into_iter` method
ty::AssocKind::Fn => { ty::AssocKind::Fn { .. } => {
// For methods, we check the function signature's return type for any GATs // For methods, we check the function signature's return type for any GATs
// to constrain. In the `into_iter` case, we see that the return type // to constrain. In the `into_iter` case, we see that the return type
// `Self::Iter<'a>` is a GAT we want to gather any potential missing bounds from. // `Self::Iter<'a>` is a GAT we want to gather any potential missing bounds from.
@ -453,7 +453,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
) )
} }
// In our example, this corresponds to the `Iter` and `Item` associated types // In our example, this corresponds to the `Iter` and `Item` associated types
ty::AssocKind::Type => { ty::AssocKind::Type { .. } => {
// If our associated item is a GAT with missing bounds, add them to // If our associated item is a GAT with missing bounds, add them to
// the param-env here. This allows this GAT to propagate missing bounds // the param-env here. This allows this GAT to propagate missing bounds
// to other GATs. // to other GATs.
@ -474,7 +474,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
gat_generics, gat_generics,
) )
} }
ty::AssocKind::Const => None, ty::AssocKind::Const { .. } => None,
}; };
if let Some(item_required_bounds) = item_required_bounds { if let Some(item_required_bounds) = item_required_bounds {
@ -1076,7 +1076,7 @@ fn check_associated_item(
}; };
match item.kind { match item.kind {
ty::AssocKind::Const => { ty::AssocKind::Const { .. } => {
let ty = tcx.type_of(item.def_id).instantiate_identity(); let ty = tcx.type_of(item.def_id).instantiate_identity();
let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty); let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
wfcx.register_wf_obligation(span, loc, ty.into()); wfcx.register_wf_obligation(span, loc, ty.into());
@ -1089,7 +1089,7 @@ fn check_associated_item(
); );
Ok(()) Ok(())
} }
ty::AssocKind::Fn => { ty::AssocKind::Fn { .. } => {
let sig = tcx.fn_sig(item.def_id).instantiate_identity(); let sig = tcx.fn_sig(item.def_id).instantiate_identity();
let hir_sig = sig_if_method.expect("bad signature for method"); let hir_sig = sig_if_method.expect("bad signature for method");
check_fn_or_method( check_fn_or_method(
@ -1101,7 +1101,7 @@ fn check_associated_item(
); );
check_method_receiver(wfcx, hir_sig, item, self_ty) check_method_receiver(wfcx, hir_sig, item, self_ty)
} }
ty::AssocKind::Type => { ty::AssocKind::Type { .. } => {
if let ty::AssocItemContainer::Trait = item.container { if let ty::AssocItemContainer::Trait = item.container {
check_associated_type_bounds(wfcx, item, span) check_associated_type_bounds(wfcx, item, span)
} }
@ -1716,7 +1716,7 @@ fn check_method_receiver<'tcx>(
) -> Result<(), ErrorGuaranteed> { ) -> Result<(), ErrorGuaranteed> {
let tcx = wfcx.tcx(); let tcx = wfcx.tcx();
if !method.fn_has_self_parameter { if !method.is_method() {
return Ok(()); return Ok(());
} }

View file

@ -51,7 +51,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
for &item1 in impl_items1.in_definition_order() { for &item1 in impl_items1.in_definition_order() {
let collision = impl_items2 let collision = impl_items2
.filter_by_name_unhygienic(item1.name) .filter_by_name_unhygienic(item1.name())
.any(|&item2| self.compare_hygienically(item1, item2)); .any(|&item2| self.compare_hygienically(item1, item2));
if collision { if collision {
@ -64,7 +64,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
fn compare_hygienically(&self, item1: ty::AssocItem, item2: ty::AssocItem) -> bool { fn compare_hygienically(&self, item1: ty::AssocItem, item2: ty::AssocItem) -> bool {
// Symbols and namespace match, compare hygienically. // Symbols and namespace match, compare hygienically.
item1.kind.namespace() == item2.kind.namespace() item1.namespace() == item2.namespace()
&& item1.ident(self.tcx).normalize_to_macros_2_0() && item1.ident(self.tcx).normalize_to_macros_2_0()
== item2.ident(self.tcx).normalize_to_macros_2_0() == item2.ident(self.tcx).normalize_to_macros_2_0()
} }
@ -113,7 +113,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
let mut res = Ok(()); let mut res = Ok(());
for &item1 in impl_items1.in_definition_order() { for &item1 in impl_items1.in_definition_order() {
let collision = impl_items2 let collision = impl_items2
.filter_by_name_unhygienic(item1.name) .filter_by_name_unhygienic(item1.name())
.find(|&&item2| self.compare_hygienically(item1, item2)); .find(|&&item2| self.compare_hygienically(item1, item2));
if let Some(item2) = collision { if let Some(item2) = collision {
@ -230,11 +230,11 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
let mut ids = impl_items let mut ids = impl_items
.in_definition_order() .in_definition_order()
.filter_map(|item| { .filter_map(|item| {
let entry = connected_region_ids.entry(item.name); let entry = connected_region_ids.entry(item.name());
if let IndexEntry::Occupied(e) = &entry { if let IndexEntry::Occupied(e) = &entry {
Some(*e.get()) Some(*e.get())
} else { } else {
idents_to_add.push(item.name); idents_to_add.push(item.name());
None None
} }
}) })

View file

@ -44,7 +44,7 @@ use rustc_trait_selection::traits::ObligationCtxt;
use tracing::{debug, instrument}; use tracing::{debug, instrument};
use crate::errors; use crate::errors;
use crate::hir_ty_lowering::errors::assoc_kind_str; use crate::hir_ty_lowering::errors::assoc_tag_str;
use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason}; use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason};
pub(crate) mod dump; pub(crate) mod dump;
@ -450,7 +450,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
item_def_id: DefId, item_def_id: DefId,
item_segment: &rustc_hir::PathSegment<'tcx>, item_segment: &rustc_hir::PathSegment<'tcx>,
poly_trait_ref: ty::PolyTraitRef<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>,
kind: ty::AssocKind, assoc_tag: ty::AssocTag,
) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> { ) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> {
if let Some(trait_ref) = poly_trait_ref.no_bound_vars() { if let Some(trait_ref) = poly_trait_ref.no_bound_vars() {
let item_args = self.lowerer().lower_generic_args_of_assoc_item( let item_args = self.lowerer().lower_generic_args_of_assoc_item(
@ -525,7 +525,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
inferred_sugg, inferred_sugg,
bound, bound,
mpart_sugg, mpart_sugg,
what: assoc_kind_str(kind), what: assoc_tag_str(assoc_tag),
})) }))
} }
} }

View file

@ -1811,7 +1811,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
self.tcx, self.tcx,
type_def_id, type_def_id,
constraint.ident, constraint.ident,
ty::AssocKind::Fn, ty::AssocTag::Fn,
) { ) {
bound_vars.extend( bound_vars.extend(
self.tcx self.tcx
@ -1843,7 +1843,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
self.tcx, self.tcx,
type_def_id, type_def_id,
constraint.ident, constraint.ident,
ty::AssocKind::Type, ty::AssocTag::Type,
) )
.map(|(bound_vars, _)| bound_vars); .map(|(bound_vars, _)| bound_vars);
self.with(scope, |this| { self.with(scope, |this| {
@ -1875,13 +1875,13 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
def_id: DefId, def_id: DefId,
assoc_ident: Ident, assoc_ident: Ident,
assoc_kind: ty::AssocKind, assoc_tag: ty::AssocTag,
) -> Option<(Vec<ty::BoundVariableKind>, &'tcx ty::AssocItem)> { ) -> Option<(Vec<ty::BoundVariableKind>, &'tcx ty::AssocItem)> {
let trait_defines_associated_item_named = |trait_def_id: DefId| { let trait_defines_associated_item_named = |trait_def_id: DefId| {
tcx.associated_items(trait_def_id).find_by_ident_and_kind( tcx.associated_items(trait_def_id).find_by_ident_and_kind(
tcx, tcx,
assoc_ident, assoc_ident,
assoc_kind, assoc_tag,
trait_def_id, trait_def_id,
) )
}; };
@ -1894,8 +1894,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
let Some((def_id, bound_vars)) = stack.pop() else { let Some((def_id, bound_vars)) = stack.pop() else {
break None; break None;
}; };
// See issue #83753. If someone writes an associated type on a non-trait, just treat it as // See issue #83753. If someone writes an associated type on a non-trait, just treat it
// there being no supertrait HRTBs. // as there being no supertrait HRTBs.
match tcx.def_kind(def_id) { match tcx.def_kind(def_id) {
DefKind::Trait | DefKind::TraitAlias | DefKind::Impl { .. } => {} DefKind::Trait | DefKind::TraitAlias | DefKind::Impl { .. } => {}
_ => break None, _ => break None,
@ -2067,7 +2067,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
self.tcx, self.tcx,
trait_def_id, trait_def_id,
item_segment.ident, item_segment.ident,
ty::AssocKind::Fn, ty::AssocTag::Fn,
) )
}); });
@ -2112,7 +2112,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
self.tcx, self.tcx,
trait_def_id, trait_def_id,
item_segment.ident, item_segment.ident,
ty::AssocKind::Fn, ty::AssocTag::Fn,
) else { ) else {
return; return;
}; };

View file

@ -32,9 +32,11 @@ pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
for &assoc_id in tcx.associated_item_def_ids(impl_def_id) { for &assoc_id in tcx.associated_item_def_ids(impl_def_id) {
let assoc = tcx.associated_item(assoc_id); let assoc = tcx.associated_item(assoc_id);
match assoc.kind { match assoc.kind {
ty::AssocKind::Const | ty::AssocKind::Fn => locator.check(assoc_id.expect_local()), ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => {
locator.check(assoc_id.expect_local())
}
// Associated types don't have bodies, so they can't constrain hidden types // Associated types don't have bodies, so they can't constrain hidden types
ty::AssocKind::Type => {} ty::AssocKind::Type { .. } => {}
} }
} }

View file

@ -4,7 +4,7 @@ use GenericArgsInfo::*;
use rustc_errors::codes::*; use rustc_errors::codes::*;
use rustc_errors::{Applicability, Diag, Diagnostic, EmissionGuarantee, MultiSpan, pluralize}; use rustc_errors::{Applicability, Diag, Diagnostic, EmissionGuarantee, MultiSpan, pluralize};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt}; use rustc_middle::ty::{self as ty, AssocItems, TyCtxt};
use rustc_span::def_id::DefId; use rustc_span::def_id::DefId;
use tracing::debug; use tracing::debug;
@ -486,13 +486,13 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
let items: &AssocItems = self.tcx.associated_items(self.def_id); let items: &AssocItems = self.tcx.associated_items(self.def_id);
items items
.in_definition_order() .in_definition_order()
.filter(|item| item.kind == AssocKind::Type) .filter(|item| item.is_type())
.filter(|item| { .filter(|item| {
!self !self
.gen_args .gen_args
.constraints .constraints
.iter() .iter()
.any(|constraint| constraint.ident.name == item.name) .any(|constraint| constraint.ident.name == item.name())
}) })
.filter(|item| !item.is_impl_trait_in_trait()) .filter(|item| !item.is_impl_trait_in_trait())
.map(|item| self.tcx.item_ident(item.def_id).to_string()) .map(|item| self.tcx.item_ident(item.def_id).to_string())

View file

@ -431,16 +431,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
) -> Result<(), ErrorGuaranteed> { ) -> Result<(), ErrorGuaranteed> {
let tcx = self.tcx(); let tcx = self.tcx();
let assoc_kind = if constraint.gen_args.parenthesized let assoc_tag = if constraint.gen_args.parenthesized
== hir::GenericArgsParentheses::ReturnTypeNotation == hir::GenericArgsParentheses::ReturnTypeNotation
{ {
ty::AssocKind::Fn ty::AssocTag::Fn
} else if let hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(_) } = } else if let hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(_) } =
constraint.kind constraint.kind
{ {
ty::AssocKind::Const ty::AssocTag::Const
} else { } else {
ty::AssocKind::Type ty::AssocTag::Type
}; };
// Given something like `U: Trait<T = X>`, we want to produce a predicate like // Given something like `U: Trait<T = X>`, we want to produce a predicate like
@ -453,7 +453,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// trait SuperTrait<A> { type T; } // trait SuperTrait<A> { type T; }
let candidate = if self.probe_trait_that_defines_assoc_item( let candidate = if self.probe_trait_that_defines_assoc_item(
trait_ref.def_id(), trait_ref.def_id(),
assoc_kind, assoc_tag,
constraint.ident, constraint.ident,
) { ) {
// Simple case: The assoc item is defined in the current trait. // Simple case: The assoc item is defined in the current trait.
@ -464,7 +464,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self.probe_single_bound_for_assoc_item( self.probe_single_bound_for_assoc_item(
|| traits::supertraits(tcx, trait_ref), || traits::supertraits(tcx, trait_ref),
AssocItemQSelf::Trait(trait_ref.def_id()), AssocItemQSelf::Trait(trait_ref.def_id()),
assoc_kind, assoc_tag,
constraint.ident, constraint.ident,
path_span, path_span,
Some(constraint), Some(constraint),
@ -474,7 +474,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let assoc_item = self let assoc_item = self
.probe_assoc_item( .probe_assoc_item(
constraint.ident, constraint.ident,
assoc_kind, assoc_tag,
hir_ref_id, hir_ref_id,
constraint.span, constraint.span,
candidate.def_id(), candidate.def_id(),
@ -493,7 +493,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}) })
.or_insert(constraint.span); .or_insert(constraint.span);
let projection_term = if let ty::AssocKind::Fn = assoc_kind { let projection_term = if let ty::AssocTag::Fn = assoc_tag {
let bound_vars = tcx.late_bound_vars(constraint.hir_id); let bound_vars = tcx.late_bound_vars(constraint.hir_id);
ty::Binder::bind_with_vars( ty::Binder::bind_with_vars(
self.lower_return_type_notation_ty(candidate, assoc_item.def_id, path_span)?.into(), self.lower_return_type_notation_ty(candidate, assoc_item.def_id, path_span)?.into(),
@ -542,7 +542,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}; };
match constraint.kind { match constraint.kind {
hir::AssocItemConstraintKind::Equality { .. } if let ty::AssocKind::Fn = assoc_kind => { hir::AssocItemConstraintKind::Equality { .. } if let ty::AssocTag::Fn = assoc_tag => {
return Err(self.dcx().emit_err(crate::errors::ReturnTypeNotationEqualityBound { return Err(self.dcx().emit_err(crate::errors::ReturnTypeNotationEqualityBound {
span: constraint.span, span: constraint.span,
})); }));
@ -679,7 +679,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
trait_def_id, trait_def_id,
hir_ty.span, hir_ty.span,
item_segment, item_segment,
ty::AssocKind::Type, ty::AssocTag::Type,
); );
return Ty::new_error(tcx, guar); return Ty::new_error(tcx, guar);
}; };
@ -771,7 +771,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
) )
}, },
AssocItemQSelf::SelfTyAlias, AssocItemQSelf::SelfTyAlias,
ty::AssocKind::Fn, ty::AssocTag::Fn,
assoc_ident, assoc_ident,
span, span,
None, None,
@ -783,7 +783,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
) => self.probe_single_ty_param_bound_for_assoc_item( ) => self.probe_single_ty_param_bound_for_assoc_item(
param_did.expect_local(), param_did.expect_local(),
qself.span, qself.span,
ty::AssocKind::Fn, ty::AssocTag::Fn,
assoc_ident, assoc_ident,
span, span,
)?, )?,
@ -823,7 +823,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let trait_def_id = bound.def_id(); let trait_def_id = bound.def_id();
let assoc_ty = self let assoc_ty = self
.probe_assoc_item(assoc_ident, ty::AssocKind::Fn, qpath_hir_id, span, trait_def_id) .probe_assoc_item(assoc_ident, ty::AssocTag::Fn, qpath_hir_id, span, trait_def_id)
.expect("failed to find associated type"); .expect("failed to find associated type");
Ok((bound, assoc_ty.def_id)) Ok((bound, assoc_ty.def_id))

View file

@ -201,7 +201,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
tcx.associated_items(pred.trait_ref.def_id) tcx.associated_items(pred.trait_ref.def_id)
.in_definition_order() .in_definition_order()
// We only care about associated types. // We only care about associated types.
.filter(|item| item.kind == ty::AssocKind::Type) .filter(|item| item.is_type())
// No RPITITs -- they're not dyn-compatible for now. // No RPITITs -- they're not dyn-compatible for now.
.filter(|item| !item.is_impl_trait_in_trait()) .filter(|item| !item.is_impl_trait_in_trait())
// If the associated type has a `where Self: Sized` bound, // If the associated type has a `where Self: Sized` bound,

View file

@ -116,7 +116,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&self, &self,
all_candidates: impl Fn() -> I, all_candidates: impl Fn() -> I,
qself: AssocItemQSelf, qself: AssocItemQSelf,
assoc_kind: ty::AssocKind, assoc_tag: ty::AssocTag,
assoc_ident: Ident, assoc_ident: Ident,
span: Span, span: Span,
constraint: Option<&hir::AssocItemConstraint<'tcx>>, constraint: Option<&hir::AssocItemConstraint<'tcx>>,
@ -134,14 +134,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}) { }) {
return self.complain_about_assoc_kind_mismatch( return self.complain_about_assoc_kind_mismatch(
assoc_item, assoc_item,
assoc_kind, assoc_tag,
assoc_ident, assoc_ident,
span, span,
constraint, constraint,
); );
} }
let assoc_kind_str = assoc_kind_str(assoc_kind); let assoc_kind_str = assoc_tag_str(assoc_tag);
let qself_str = qself.to_string(tcx); let qself_str = qself.to_string(tcx);
// The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a // The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a
@ -168,7 +168,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let all_candidate_names: Vec<_> = all_candidates() let all_candidate_names: Vec<_> = all_candidates()
.flat_map(|r| tcx.associated_items(r.def_id()).in_definition_order()) .flat_map(|r| tcx.associated_items(r.def_id()).in_definition_order())
.filter_map(|item| { .filter_map(|item| {
(!item.is_impl_trait_in_trait() && item.kind == assoc_kind).then_some(item.name) if !item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag {
item.opt_name()
} else {
None
}
}) })
.collect(); .collect();
@ -200,7 +204,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.iter() .iter()
.flat_map(|trait_def_id| 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| { .filter_map(|item| {
(!item.is_impl_trait_in_trait() && item.kind == assoc_kind).then_some(item.name) (!item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag)
.then_some(item.name())
}) })
.collect(); .collect();
@ -213,7 +218,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.filter(|trait_def_id| { .filter(|trait_def_id| {
tcx.associated_items(trait_def_id) tcx.associated_items(trait_def_id)
.filter_by_name_unhygienic(suggested_name) .filter_by_name_unhygienic(suggested_name)
.any(|item| item.kind == assoc_kind) .any(|item| item.as_tag() == assoc_tag)
}) })
.collect::<Vec<_>>()[..] .collect::<Vec<_>>()[..]
{ {
@ -330,14 +335,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
fn complain_about_assoc_kind_mismatch( fn complain_about_assoc_kind_mismatch(
&self, &self,
assoc_item: &ty::AssocItem, assoc_item: &ty::AssocItem,
assoc_kind: ty::AssocKind, assoc_tag: ty::AssocTag,
ident: Ident, ident: Ident,
span: Span, span: Span,
constraint: Option<&hir::AssocItemConstraint<'tcx>>, constraint: Option<&hir::AssocItemConstraint<'tcx>>,
) -> ErrorGuaranteed { ) -> ErrorGuaranteed {
let tcx = self.tcx(); let tcx = self.tcx();
let bound_on_assoc_const_label = if let ty::AssocKind::Const = assoc_item.kind let bound_on_assoc_const_label = if let ty::AssocKind::Const { .. } = assoc_item.kind
&& let Some(constraint) = constraint && let Some(constraint) = constraint
&& let hir::AssocItemConstraintKind::Bound { .. } = constraint.kind && let hir::AssocItemConstraintKind::Bound { .. } = constraint.kind
{ {
@ -375,17 +380,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
hir::Term::Ty(ty) => ty.span, hir::Term::Ty(ty) => ty.span,
hir::Term::Const(ct) => ct.span(), hir::Term::Const(ct) => ct.span(),
}; };
(span, Some(ident.span), assoc_item.kind, assoc_kind) (span, Some(ident.span), assoc_item.as_tag(), assoc_tag)
} else { } else {
(ident.span, None, assoc_kind, assoc_item.kind) (ident.span, None, assoc_tag, assoc_item.as_tag())
}; };
self.dcx().emit_err(errors::AssocKindMismatch { self.dcx().emit_err(errors::AssocKindMismatch {
span, span,
expected: assoc_kind_str(expected), expected: assoc_tag_str(expected),
got: assoc_kind_str(got), got: assoc_tag_str(got),
expected_because_label, expected_because_label,
assoc_kind: assoc_kind_str(assoc_item.kind), assoc_kind: assoc_tag_str(assoc_item.as_tag()),
def_span: tcx.def_span(assoc_item.def_id), def_span: tcx.def_span(assoc_item.def_id),
bound_on_assoc_const_label, bound_on_assoc_const_label,
wrap_in_braces_sugg, wrap_in_braces_sugg,
@ -398,9 +403,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
types: &[String], types: &[String],
traits: &[String], traits: &[String],
name: Symbol, name: Symbol,
kind: ty::AssocKind, assoc_tag: ty::AssocTag,
) -> ErrorGuaranteed { ) -> ErrorGuaranteed {
let kind_str = assoc_kind_str(kind); let kind_str = assoc_tag_str(assoc_tag);
let mut err = let mut err =
struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated {kind_str}"); struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated {kind_str}");
if self if self
@ -569,7 +574,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
candidates: Vec<(DefId, (DefId, DefId))>, candidates: Vec<(DefId, (DefId, DefId))>,
fulfillment_errors: Vec<FulfillmentError<'tcx>>, fulfillment_errors: Vec<FulfillmentError<'tcx>>,
span: Span, span: Span,
kind: ty::AssocKind, assoc_tag: ty::AssocTag,
) -> ErrorGuaranteed { ) -> ErrorGuaranteed {
// FIXME(fmease): This was copied in parts from an old version of `rustc_hir_typeck::method::suggest`. // FIXME(fmease): This was copied in parts from an old version of `rustc_hir_typeck::method::suggest`.
// Either // Either
@ -579,14 +584,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let tcx = self.tcx(); let tcx = self.tcx();
let kind_str = assoc_kind_str(kind); let assoc_tag_str = assoc_tag_str(assoc_tag);
let adt_did = self_ty.ty_adt_def().map(|def| def.did()); let adt_did = self_ty.ty_adt_def().map(|def| def.did());
let add_def_label = |err: &mut Diag<'_>| { let add_def_label = |err: &mut Diag<'_>| {
if let Some(did) = adt_did { if let Some(did) = adt_did {
err.span_label( err.span_label(
tcx.def_span(did), tcx.def_span(did),
format!( format!(
"associated {kind_str} `{name}` not found for this {}", "associated {assoc_tag_str} `{name}` not found for this {}",
tcx.def_descr(did) tcx.def_descr(did)
), ),
); );
@ -615,11 +620,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self.dcx(), self.dcx(),
name.span, name.span,
E0220, E0220,
"associated {kind_str} `{name}` not found for `{self_ty}` in the current scope" "associated {assoc_tag_str} `{name}` not found for `{self_ty}` in the current scope"
); );
err.span_label(name.span, format!("associated item not found in `{self_ty}`")); err.span_label(name.span, format!("associated item not found in `{self_ty}`"));
err.note(format!( err.note(format!(
"the associated {kind_str} was found for\n{type_candidates}{additional_types}", "the associated {assoc_tag_str} was found for\n{type_candidates}{additional_types}",
)); ));
add_def_label(&mut err); add_def_label(&mut err);
return err.emit(); return err.emit();
@ -700,7 +705,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let mut err = self.dcx().struct_span_err( let mut err = self.dcx().struct_span_err(
name.span, name.span,
format!("the associated {kind_str} `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied") format!("the associated {assoc_tag_str} `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied")
); );
if !bounds.is_empty() { if !bounds.is_empty() {
err.note(format!( err.note(format!(
@ -710,7 +715,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
} }
err.span_label( err.span_label(
name.span, name.span,
format!("associated {kind_str} cannot be referenced on `{self_ty}` due to unsatisfied trait bounds") format!("associated {assoc_tag_str} cannot be referenced on `{self_ty}` due to unsatisfied trait bounds")
); );
for (span, mut bounds) in bound_spans { for (span, mut bounds) in bound_spans {
@ -761,7 +766,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// `issue-22560.rs`. // `issue-22560.rs`.
let mut dyn_compatibility_violations = Ok(()); let mut dyn_compatibility_violations = Ok(());
for (assoc_item, trait_ref) in &missing_assoc_types { for (assoc_item, trait_ref) in &missing_assoc_types {
names.entry(trait_ref).or_default().push(assoc_item.name); names.entry(trait_ref).or_default().push(assoc_item.name());
names_len += 1; names_len += 1;
let violations = let violations =
@ -812,7 +817,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let assoc_item = tcx.associated_items(trait_def).find_by_ident_and_kind( let assoc_item = tcx.associated_items(trait_def).find_by_ident_and_kind(
tcx, tcx,
ident, ident,
ty::AssocKind::Type, ty::AssocTag::Type,
trait_def, trait_def,
); );
@ -852,16 +857,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let mut names: UnordMap<_, usize> = Default::default(); let mut names: UnordMap<_, usize> = Default::default();
for (item, _) in &missing_assoc_types { for (item, _) in &missing_assoc_types {
types_count += 1; types_count += 1;
*names.entry(item.name).or_insert(0) += 1; *names.entry(item.name()).or_insert(0) += 1;
} }
let mut dupes = false; let mut dupes = false;
let mut shadows = false; let mut shadows = false;
for (item, trait_ref) in &missing_assoc_types { for (item, trait_ref) in &missing_assoc_types {
let prefix = if names[&item.name] > 1 { let name = item.name();
let prefix = if names[&name] > 1 {
let trait_def_id = trait_ref.def_id(); let trait_def_id = trait_ref.def_id();
dupes = true; dupes = true;
format!("{}::", tcx.def_path_str(trait_def_id)) format!("{}::", tcx.def_path_str(trait_def_id))
} else if bound_names.get(&item.name).is_some_and(|x| *x != item) { } else if bound_names.get(&name).is_some_and(|x| *x != item) {
let trait_def_id = trait_ref.def_id(); let trait_def_id = trait_ref.def_id();
shadows = true; shadows = true;
format!("{}::", tcx.def_path_str(trait_def_id)) format!("{}::", tcx.def_path_str(trait_def_id))
@ -871,7 +877,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let mut is_shadowed = false; let mut is_shadowed = false;
if let Some(assoc_item) = bound_names.get(&item.name) if let Some(assoc_item) = bound_names.get(&name)
&& *assoc_item != item && *assoc_item != item
{ {
is_shadowed = true; is_shadowed = true;
@ -880,17 +886,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
if assoc_item.def_id.is_local() { ", consider renaming it" } else { "" }; if assoc_item.def_id.is_local() { ", consider renaming it" } else { "" };
err.span_label( err.span_label(
tcx.def_span(assoc_item.def_id), tcx.def_span(assoc_item.def_id),
format!("`{}{}` shadowed here{}", prefix, item.name, rename_message), format!("`{}{}` shadowed here{}", prefix, name, rename_message),
); );
} }
let rename_message = if is_shadowed { ", consider renaming it" } else { "" }; let rename_message = if is_shadowed { ", consider renaming it" } else { "" };
if let Some(sp) = tcx.hir_span_if_local(item.def_id) { if let Some(sp) = tcx.hir_span_if_local(item.def_id) {
err.span_label( err.span_label(sp, format!("`{}{}` defined here{}", prefix, name, rename_message));
sp,
format!("`{}{}` defined here{}", prefix, item.name, rename_message),
);
} }
} }
if potential_assoc_types.len() == missing_assoc_types.len() { if potential_assoc_types.len() == missing_assoc_types.len() {
@ -903,7 +906,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
{ {
let types: Vec<_> = missing_assoc_types let types: Vec<_> = missing_assoc_types
.iter() .iter()
.map(|(item, _)| format!("{} = Type", item.name)) .map(|(item, _)| format!("{} = Type", item.name()))
.collect(); .collect();
let code = if let Some(snippet) = snippet.strip_suffix('>') { let code = if let Some(snippet) = snippet.strip_suffix('>') {
// The user wrote `Trait<'a>` or similar and we don't have a type we can // The user wrote `Trait<'a>` or similar and we don't have a type we can
@ -938,16 +941,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let mut names: FxIndexMap<_, usize> = FxIndexMap::default(); let mut names: FxIndexMap<_, usize> = FxIndexMap::default();
for (item, _) in &missing_assoc_types { for (item, _) in &missing_assoc_types {
types_count += 1; types_count += 1;
*names.entry(item.name).or_insert(0) += 1; *names.entry(item.name()).or_insert(0) += 1;
} }
let mut label = vec![]; let mut label = vec![];
for (item, trait_ref) in &missing_assoc_types { for (item, trait_ref) in &missing_assoc_types {
let postfix = if names[&item.name] > 1 { let name = item.name();
let postfix = if names[&name] > 1 {
format!(" (from trait `{}`)", trait_ref.print_trait_sugared()) format!(" (from trait `{}`)", trait_ref.print_trait_sugared())
} else { } else {
String::new() String::new()
}; };
label.push(format!("`{}`{}", item.name, postfix)); label.push(format!("`{}`{}", name, postfix));
} }
if !label.is_empty() { if !label.is_empty() {
err.span_label( err.span_label(
@ -1022,12 +1026,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.map(|simple_ty| tcx.incoherent_impls(simple_ty)) .map(|simple_ty| tcx.incoherent_impls(simple_ty))
}) })
&& let name = Symbol::intern(&format!("{ident2}_{ident3}")) && let name = Symbol::intern(&format!("{ident2}_{ident3}"))
&& let Some(ty::AssocItem { kind: ty::AssocKind::Fn, .. }) = inherent_impls && let Some(item) = inherent_impls
.iter() .iter()
.flat_map(|inherent_impl| { .flat_map(|inherent_impl| {
tcx.associated_items(inherent_impl).filter_by_name_unhygienic(name) tcx.associated_items(inherent_impl).filter_by_name_unhygienic(name)
}) })
.next() .next()
&& item.is_fn()
{ {
Err(struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type") Err(struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type")
.with_span_suggestion_verbose( .with_span_suggestion_verbose(
@ -1629,10 +1634,10 @@ fn generics_args_err_extend<'a>(
} }
} }
pub(crate) fn assoc_kind_str(kind: ty::AssocKind) -> &'static str { pub(crate) fn assoc_tag_str(assoc_tag: ty::AssocTag) -> &'static str {
match kind { match assoc_tag {
ty::AssocKind::Fn => "function", ty::AssocTag::Fn => "function",
ty::AssocKind::Const => "constant", ty::AssocTag::Const => "constant",
ty::AssocKind::Type => "type", ty::AssocTag::Type => "type",
} }
} }

View file

@ -501,8 +501,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let names: Vec<_> = tcx let names: Vec<_> = tcx
.associated_items(trait_def_id) .associated_items(trait_def_id)
.in_definition_order() .in_definition_order()
.filter(|assoc| assoc.kind.namespace() == Namespace::ValueNS) .filter(|assoc| assoc.namespace() == Namespace::ValueNS)
.map(|cand| cand.name) .map(|cand| cand.name())
.collect(); .collect();
if let Some(typo) = find_best_match_for_name(&names, segment.ident.name, None) { if let Some(typo) = find_best_match_for_name(&names, segment.ident.name, None) {
diag.span_suggestion_verbose( diag.span_suggestion_verbose(

View file

@ -38,8 +38,8 @@ use rustc_middle::middle::stability::AllowUnstable;
use rustc_middle::mir::interpret::LitToConstInput; use rustc_middle::mir::interpret::LitToConstInput;
use rustc_middle::ty::print::PrintPolyTraitRefExt as _; use rustc_middle::ty::print::PrintPolyTraitRefExt as _;
use rustc_middle::ty::{ use rustc_middle::ty::{
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt, self, AssocTag, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty,
TypeVisitableExt, TypingMode, Upcast, fold_regions, TyCtxt, TypeVisitableExt, TypingMode, Upcast, fold_regions,
}; };
use rustc_middle::{bug, span_bug}; use rustc_middle::{bug, span_bug};
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
@ -51,7 +51,7 @@ use rustc_trait_selection::traits::wf::object_region_bounds;
use rustc_trait_selection::traits::{self, ObligationCtxt}; use rustc_trait_selection::traits::{self, ObligationCtxt};
use tracing::{debug, instrument}; use tracing::{debug, instrument};
use self::errors::assoc_kind_str; use self::errors::assoc_tag_str;
use crate::check::check_abi_fn_ptr; use crate::check::check_abi_fn_ptr;
use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, NoVariantNamed}; use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, NoVariantNamed};
use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint}; use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint};
@ -168,7 +168,7 @@ pub trait HirTyLowerer<'tcx> {
item_def_id: DefId, item_def_id: DefId,
item_segment: &hir::PathSegment<'tcx>, item_segment: &hir::PathSegment<'tcx>,
poly_trait_ref: ty::PolyTraitRef<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>,
kind: ty::AssocKind, assoc_tag: ty::AssocTag,
) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed>; ) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed>;
fn lower_fn_sig( fn lower_fn_sig(
@ -251,10 +251,10 @@ enum LowerAssocMode {
} }
impl LowerAssocMode { impl LowerAssocMode {
fn kind(self) -> ty::AssocKind { fn assoc_tag(self) -> ty::AssocTag {
match self { match self {
LowerAssocMode::Type { .. } => ty::AssocKind::Type, LowerAssocMode::Type { .. } => ty::AssocTag::Type,
LowerAssocMode::Const => ty::AssocKind::Const, LowerAssocMode::Const => ty::AssocTag::Const,
} }
} }
@ -268,7 +268,8 @@ impl LowerAssocMode {
fn permit_variants(self) -> bool { fn permit_variants(self) -> bool {
match self { match self {
LowerAssocMode::Type { permit_variants } => permit_variants, LowerAssocMode::Type { permit_variants } => permit_variants,
// FIXME(mgca): Support paths like `Option::<T>::None` or `Option::<T>::Some` which resolve to const ctors/fn items respectively // FIXME(mgca): Support paths like `Option::<T>::None` or `Option::<T>::Some` which
// resolve to const ctors/fn items respectively.
LowerAssocMode::Const => false, LowerAssocMode::Const => false,
} }
} }
@ -932,12 +933,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
fn probe_trait_that_defines_assoc_item( fn probe_trait_that_defines_assoc_item(
&self, &self,
trait_def_id: DefId, trait_def_id: DefId,
assoc_kind: ty::AssocKind, assoc_tag: AssocTag,
assoc_ident: Ident, assoc_ident: Ident,
) -> bool { ) -> bool {
self.tcx() self.tcx()
.associated_items(trait_def_id) .associated_items(trait_def_id)
.find_by_ident_and_kind(self.tcx(), assoc_ident, assoc_kind, trait_def_id) .find_by_ident_and_kind(self.tcx(), assoc_ident, assoc_tag, trait_def_id)
.is_some() .is_some()
} }
@ -975,7 +976,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&self, &self,
ty_param_def_id: LocalDefId, ty_param_def_id: LocalDefId,
ty_param_span: Span, ty_param_span: Span,
kind: ty::AssocKind, assoc_tag: AssocTag,
assoc_ident: Ident, assoc_ident: Ident,
span: Span, span: Span,
) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed> { ) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed> {
@ -993,7 +994,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
traits::transitive_bounds_that_define_assoc_item(tcx, trait_refs, assoc_ident) traits::transitive_bounds_that_define_assoc_item(tcx, trait_refs, assoc_ident)
}, },
AssocItemQSelf::TyParam(ty_param_def_id, ty_param_span), AssocItemQSelf::TyParam(ty_param_def_id, ty_param_span),
kind, assoc_tag,
assoc_ident, assoc_ident,
span, span,
None, None,
@ -1010,7 +1011,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&self, &self,
all_candidates: impl Fn() -> I, all_candidates: impl Fn() -> I,
qself: AssocItemQSelf, qself: AssocItemQSelf,
assoc_kind: ty::AssocKind, assoc_tag: AssocTag,
assoc_ident: Ident, assoc_ident: Ident,
span: Span, span: Span,
constraint: Option<&hir::AssocItemConstraint<'tcx>>, constraint: Option<&hir::AssocItemConstraint<'tcx>>,
@ -1021,14 +1022,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let tcx = self.tcx(); let tcx = self.tcx();
let mut matching_candidates = all_candidates().filter(|r| { let mut matching_candidates = all_candidates().filter(|r| {
self.probe_trait_that_defines_assoc_item(r.def_id(), assoc_kind, assoc_ident) self.probe_trait_that_defines_assoc_item(r.def_id(), assoc_tag, assoc_ident)
}); });
let Some(bound) = matching_candidates.next() else { let Some(bound) = matching_candidates.next() else {
let reported = self.complain_about_assoc_item_not_found( let reported = self.complain_about_assoc_item_not_found(
all_candidates, all_candidates,
qself, qself,
assoc_kind, assoc_tag,
assoc_ident, assoc_ident,
span, span,
constraint, constraint,
@ -1040,7 +1041,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
if let Some(bound2) = matching_candidates.next() { if let Some(bound2) = matching_candidates.next() {
debug!(?bound2); debug!(?bound2);
let assoc_kind_str = errors::assoc_kind_str(assoc_kind); let assoc_kind_str = errors::assoc_tag_str(assoc_tag);
let qself_str = qself.to_string(tcx); let qself_str = qself.to_string(tcx);
let mut err = self.dcx().create_err(crate::errors::AmbiguousAssocItem { let mut err = self.dcx().create_err(crate::errors::AmbiguousAssocItem {
span, span,
@ -1059,14 +1060,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}, },
); );
// FIXME(#97583): Print associated item bindings properly (i.e., not as equality predicates!). // FIXME(#97583): Print associated item bindings properly (i.e., not as equality
// predicates!).
// FIXME: Turn this into a structured, translateable & more actionable suggestion. // FIXME: Turn this into a structured, translateable & more actionable suggestion.
let mut where_bounds = vec![]; let mut where_bounds = vec![];
for bound in [bound, bound2].into_iter().chain(matching_candidates) { for bound in [bound, bound2].into_iter().chain(matching_candidates) {
let bound_id = bound.def_id(); let bound_id = bound.def_id();
let bound_span = tcx let bound_span = tcx
.associated_items(bound_id) .associated_items(bound_id)
.find_by_ident_and_kind(tcx, assoc_ident, assoc_kind, bound_id) .find_by_ident_and_kind(tcx, assoc_ident, assoc_tag, bound_id)
.and_then(|item| tcx.hir_span_if_local(item.def_id)); .and_then(|item| tcx.hir_span_if_local(item.def_id));
if let Some(bound_span) = bound_span { if let Some(bound_span) = bound_span {
@ -1265,7 +1267,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
qself_ty, qself_ty,
hir_ref_id, hir_ref_id,
span, span,
mode.kind(), mode.assoc_tag(),
)? { )? {
return Ok(LoweredAssoc::Term(did, args)); return Ok(LoweredAssoc::Term(did, args));
} }
@ -1296,7 +1298,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
) )
}, },
AssocItemQSelf::SelfTyAlias, AssocItemQSelf::SelfTyAlias,
mode.kind(), mode.assoc_tag(),
assoc_ident, assoc_ident,
span, span,
None, None,
@ -1308,12 +1310,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
) => self.probe_single_ty_param_bound_for_assoc_item( ) => self.probe_single_ty_param_bound_for_assoc_item(
param_did.expect_local(), param_did.expect_local(),
qself.span, qself.span,
mode.kind(), mode.assoc_tag(),
assoc_ident, assoc_ident,
span, span,
)?, )?,
_ => { _ => {
let kind_str = assoc_kind_str(mode.kind()); let kind_str = assoc_tag_str(mode.assoc_tag());
let reported = if variant_resolution.is_some() { let reported = if variant_resolution.is_some() {
// Variant in type position // Variant in type position
let msg = format!("expected {kind_str}, found variant `{assoc_ident}`"); let msg = format!("expected {kind_str}, found variant `{assoc_ident}`");
@ -1420,7 +1422,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&[qself_ty.to_string()], &[qself_ty.to_string()],
&traits, &traits,
assoc_ident.name, assoc_ident.name,
mode.kind(), mode.assoc_tag(),
) )
}; };
return Err(reported); return Err(reported);
@ -1429,10 +1431,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let trait_did = bound.def_id(); let trait_did = bound.def_id();
let assoc_item = self let assoc_item = self
.probe_assoc_item(assoc_ident, mode.kind(), hir_ref_id, span, trait_did) .probe_assoc_item(assoc_ident, mode.assoc_tag(), hir_ref_id, span, trait_did)
.expect("failed to find associated item"); .expect("failed to find associated item");
let (def_id, args) = let (def_id, args) = self.lower_assoc_shared(
self.lower_assoc_shared(span, assoc_item.def_id, assoc_segment, bound, mode.kind())?; span,
assoc_item.def_id,
assoc_segment,
bound,
mode.assoc_tag(),
)?;
let result = LoweredAssoc::Term(def_id, args); let result = LoweredAssoc::Term(def_id, args);
if let Some(variant_def_id) = variant_resolution { if let Some(variant_def_id) = variant_resolution {
@ -1469,20 +1476,21 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self_ty: Ty<'tcx>, self_ty: Ty<'tcx>,
block: HirId, block: HirId,
span: Span, span: Span,
kind: ty::AssocKind, assoc_tag: ty::AssocTag,
) -> Result<Option<(DefId, GenericArgsRef<'tcx>)>, ErrorGuaranteed> { ) -> Result<Option<(DefId, GenericArgsRef<'tcx>)>, ErrorGuaranteed> {
let tcx = self.tcx(); let tcx = self.tcx();
if !tcx.features().inherent_associated_types() { if !tcx.features().inherent_associated_types() {
match kind { match assoc_tag {
// Don't attempt to look up inherent associated types when the feature is not enabled. // Don't attempt to look up inherent associated types when the feature is not
// Theoretically it'd be fine to do so since we feature-gate their definition site. // enabled. Theoretically it'd be fine to do so since we feature-gate their
// However, due to current limitations of the implementation (caused by us performing // definition site. However, due to current limitations of the implementation
// selection during HIR ty lowering instead of in the trait solver), IATs can lead to cycle // (caused by us performing selection during HIR ty lowering instead of in the
// errors (#108491) which mask the feature-gate error, needlessly confusing users // trait solver), IATs can lead to cycle errors (#108491) which mask the
// who use IATs by accident (#113265). // feature-gate error, needlessly confusing users who use IATs by accident
ty::AssocKind::Type => return Ok(None), // (#113265).
ty::AssocKind::Const => { ty::AssocTag::Type => return Ok(None),
ty::AssocTag::Const => {
// We also gate the mgca codepath for type-level uses of inherent consts // We also gate the mgca codepath for type-level uses of inherent consts
// with the inherent_associated_types feature gate since it relies on the // with the inherent_associated_types feature gate since it relies on the
// same machinery and has similar rough edges. // same machinery and has similar rough edges.
@ -1494,7 +1502,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
) )
.emit()); .emit());
} }
ty::AssocKind::Fn => unreachable!(), ty::AssocTag::Fn => unreachable!(),
} }
} }
@ -1503,7 +1511,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.inherent_impls(adt_did) .inherent_impls(adt_did)
.iter() .iter()
.filter_map(|&impl_| { .filter_map(|&impl_| {
let (item, scope) = self.probe_assoc_item_unchecked(name, kind, block, impl_)?; let (item, scope) =
self.probe_assoc_item_unchecked(name, assoc_tag, block, impl_)?;
Some((impl_, (item.def_id, scope))) Some((impl_, (item.def_id, scope)))
}) })
.collect(); .collect();
@ -1542,7 +1551,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self_ty, self_ty,
|self_ty| { |self_ty| {
self.select_inherent_assoc_candidates( self.select_inherent_assoc_candidates(
infcx, name, span, self_ty, param_env, candidates, kind, infcx, name, span, self_ty, param_env, candidates, assoc_tag,
) )
}, },
)?; )?;
@ -1570,7 +1579,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self_ty: Ty<'tcx>, self_ty: Ty<'tcx>,
param_env: ParamEnv<'tcx>, param_env: ParamEnv<'tcx>,
candidates: Vec<(DefId, (DefId, DefId))>, candidates: Vec<(DefId, (DefId, DefId))>,
kind: ty::AssocKind, assoc_tag: ty::AssocTag,
) -> Result<(DefId, (DefId, DefId)), ErrorGuaranteed> { ) -> Result<(DefId, (DefId, DefId)), ErrorGuaranteed> {
let tcx = self.tcx(); let tcx = self.tcx();
let mut fulfillment_errors = Vec::new(); let mut fulfillment_errors = Vec::new();
@ -1621,7 +1630,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
candidates, candidates,
fulfillment_errors, fulfillment_errors,
span, span,
kind, assoc_tag,
)), )),
&[applicable_candidate] => Ok(applicable_candidate), &[applicable_candidate] => Ok(applicable_candidate),
@ -1640,12 +1649,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
fn probe_assoc_item( fn probe_assoc_item(
&self, &self,
ident: Ident, ident: Ident,
kind: ty::AssocKind, assoc_tag: ty::AssocTag,
block: HirId, block: HirId,
span: Span, span: Span,
scope: DefId, scope: DefId,
) -> Option<ty::AssocItem> { ) -> Option<ty::AssocItem> {
let (item, scope) = self.probe_assoc_item_unchecked(ident, kind, block, scope)?; let (item, scope) = self.probe_assoc_item_unchecked(ident, assoc_tag, block, scope)?;
self.check_assoc_item(item.def_id, ident, scope, block, span); self.check_assoc_item(item.def_id, ident, scope, block, span);
Some(item) Some(item)
} }
@ -1657,7 +1666,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
fn probe_assoc_item_unchecked( fn probe_assoc_item_unchecked(
&self, &self,
ident: Ident, ident: Ident,
kind: ty::AssocKind, assoc_tag: ty::AssocTag,
block: HirId, block: HirId,
scope: DefId, scope: DefId,
) -> Option<(ty::AssocItem, /*scope*/ DefId)> { ) -> Option<(ty::AssocItem, /*scope*/ DefId)> {
@ -1670,7 +1679,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let item = tcx let item = tcx
.associated_items(scope) .associated_items(scope)
.filter_by_name_unhygienic(ident.name) .filter_by_name_unhygienic(ident.name)
.find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == ident)?; .find(|i| i.as_tag() == assoc_tag && i.ident(tcx).normalize_to_macros_2_0() == ident)?;
Some((*item, def_scope)) Some((*item, def_scope))
} }
@ -1722,9 +1731,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
tcx.associated_items(*trait_def_id) tcx.associated_items(*trait_def_id)
.in_definition_order() .in_definition_order()
.any(|i| { .any(|i| {
i.kind.namespace() == Namespace::TypeNS i.namespace() == Namespace::TypeNS
&& i.ident(tcx).normalize_to_macros_2_0() == assoc_ident && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
&& matches!(i.kind, ty::AssocKind::Type) && i.is_type()
}) })
// Consider only accessible traits // Consider only accessible traits
&& tcx.visibility(*trait_def_id) && tcx.visibility(*trait_def_id)
@ -1770,7 +1779,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
item_def_id, item_def_id,
trait_segment, trait_segment,
item_segment, item_segment,
ty::AssocKind::Type, ty::AssocTag::Type,
) { ) {
Ok((item_def_id, item_args)) => { Ok((item_def_id, item_args)) => {
Ty::new_projection_from_args(self.tcx(), item_def_id, item_args) Ty::new_projection_from_args(self.tcx(), item_def_id, item_args)
@ -1795,7 +1804,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
item_def_id, item_def_id,
trait_segment, trait_segment,
item_segment, item_segment,
ty::AssocKind::Const, ty::AssocTag::Const,
) { ) {
Ok((item_def_id, item_args)) => { Ok((item_def_id, item_args)) => {
let uv = ty::UnevaluatedConst::new(item_def_id, item_args); let uv = ty::UnevaluatedConst::new(item_def_id, item_args);
@ -1813,7 +1822,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
item_def_id: DefId, item_def_id: DefId,
trait_segment: &hir::PathSegment<'tcx>, trait_segment: &hir::PathSegment<'tcx>,
item_segment: &hir::PathSegment<'tcx>, item_segment: &hir::PathSegment<'tcx>,
kind: ty::AssocKind, assoc_tag: ty::AssocTag,
) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed> { ) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed> {
let tcx = self.tcx(); let tcx = self.tcx();
@ -1821,7 +1830,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
debug!(?trait_def_id); debug!(?trait_def_id);
let Some(self_ty) = opt_self_ty else { let Some(self_ty) = opt_self_ty else {
return Err(self.error_missing_qpath_self_ty(trait_def_id, span, item_segment, kind)); return Err(self.error_missing_qpath_self_ty(
trait_def_id,
span,
item_segment,
assoc_tag,
));
}; };
debug!(?self_ty); debug!(?self_ty);
@ -1840,7 +1854,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
trait_def_id: DefId, trait_def_id: DefId,
span: Span, span: Span,
item_segment: &hir::PathSegment<'tcx>, item_segment: &hir::PathSegment<'tcx>,
kind: ty::AssocKind, assoc_tag: ty::AssocTag,
) -> ErrorGuaranteed { ) -> ErrorGuaranteed {
let tcx = self.tcx(); let tcx = self.tcx();
let path_str = tcx.def_path_str(trait_def_id); let path_str = tcx.def_path_str(trait_def_id);
@ -1877,7 +1891,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that // FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that
// references the trait. Relevant for the first case in // references the trait. Relevant for the first case in
// `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs` // `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs`
self.report_ambiguous_assoc(span, &type_names, &[path_str], item_segment.ident.name, kind) self.report_ambiguous_assoc(
span,
&type_names,
&[path_str],
item_segment.ident.name,
assoc_tag,
)
} }
pub fn prohibit_generic_args<'a>( pub fn prohibit_generic_args<'a>(
@ -2862,7 +2882,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let assoc = tcx.associated_items(trait_ref.def_id).find_by_ident_and_kind( let assoc = tcx.associated_items(trait_ref.def_id).find_by_ident_and_kind(
tcx, tcx,
*ident, *ident,
ty::AssocKind::Fn, ty::AssocTag::Fn,
trait_ref.def_id, trait_ref.def_id,
)?; )?;

View file

@ -112,14 +112,14 @@ pub(crate) fn enforce_impl_lifetime_params_are_constrained(
.flat_map(|def_id| { .flat_map(|def_id| {
let item = tcx.associated_item(def_id); let item = tcx.associated_item(def_id);
match item.kind { match item.kind {
ty::AssocKind::Type => { ty::AssocKind::Type { .. } => {
if item.defaultness(tcx).has_value() { if item.defaultness(tcx).has_value() {
cgp::parameters_for(tcx, tcx.type_of(def_id).instantiate_identity(), true) cgp::parameters_for(tcx, tcx.type_of(def_id).instantiate_identity(), true)
} else { } else {
vec![] vec![]
} }
} }
ty::AssocKind::Fn | ty::AssocKind::Const => vec![], ty::AssocKind::Fn { .. } | ty::AssocKind::Const { .. } => vec![],
} }
}) })
.collect(); .collect();

View file

@ -1089,14 +1089,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// This function checks whether the method is not static and does not accept other parameters than `self`. /// This function checks whether the method is not static and does not accept other parameters than `self`.
fn has_only_self_parameter(&self, method: &AssocItem) -> bool { fn has_only_self_parameter(&self, method: &AssocItem) -> bool {
match method.kind { method.is_method()
ty::AssocKind::Fn => { && self.tcx.fn_sig(method.def_id).skip_binder().inputs().skip_binder().len() == 1
method.fn_has_self_parameter
&& self.tcx.fn_sig(method.def_id).skip_binder().inputs().skip_binder().len()
== 1
}
_ => false,
}
} }
/// If the given `HirId` corresponds to a block with a trailing expression, return that expression /// If the given `HirId` corresponds to a block with a trailing expression, return that expression

View file

@ -2588,9 +2588,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.into_iter() .into_iter()
.flat_map(|i| self.tcx.associated_items(i).in_definition_order()) .flat_map(|i| self.tcx.associated_items(i).in_definition_order())
// Only assoc fn with no receivers. // Only assoc fn with no receivers.
.filter(|item| { .filter(|item| item.is_fn() && !item.is_method())
matches!(item.kind, ty::AssocKind::Fn) && !item.fn_has_self_parameter
})
.filter_map(|item| { .filter_map(|item| {
// Only assoc fns that return `Self` // Only assoc fns that return `Self`
let fn_sig = self.tcx.fn_sig(item.def_id).skip_binder(); let fn_sig = self.tcx.fn_sig(item.def_id).skip_binder();
@ -2603,8 +2601,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return None; return None;
} }
let input_len = fn_sig.inputs().skip_binder().len(); let input_len = fn_sig.inputs().skip_binder().len();
let order = !item.name.as_str().starts_with("new"); let name = item.name();
Some((order, item.name, input_len)) let order = !name.as_str().starts_with("new");
Some((order, name, input_len))
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
items.sort_by_key(|(order, _, _)| *order); items.sort_by_key(|(order, _, _)| *order);

View file

@ -616,7 +616,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some((DefKind::AssocFn, def_id)) = if let Some((DefKind::AssocFn, def_id)) =
self.typeck_results.borrow().type_dependent_def(call_expr.hir_id) self.typeck_results.borrow().type_dependent_def(call_expr.hir_id)
&& let Some(assoc) = tcx.opt_associated_item(def_id) && let Some(assoc) = tcx.opt_associated_item(def_id)
&& assoc.fn_has_self_parameter && assoc.is_method()
{ {
Some(*receiver) Some(*receiver)
} else { } else {
@ -642,8 +642,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
TraitsInScope, TraitsInScope,
|mut ctxt| ctxt.probe_for_similar_candidate(), |mut ctxt| ctxt.probe_for_similar_candidate(),
) )
&& let ty::AssocKind::Fn = assoc.kind && assoc.is_method()
&& assoc.fn_has_self_parameter
{ {
let args = self.infcx.fresh_args_for_item(call_name.span, assoc.def_id); let args = self.infcx.fresh_args_for_item(call_name.span, assoc.def_id);
let fn_sig = tcx.fn_sig(assoc.def_id).instantiate(tcx, args); let fn_sig = tcx.fn_sig(assoc.def_id).instantiate(tcx, args);
@ -684,10 +683,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.all(|(expected, found)| self.may_coerce(*expected, *found)) .all(|(expected, found)| self.may_coerce(*expected, *found))
&& fn_sig.inputs()[1..].len() == input_types.len() && fn_sig.inputs()[1..].len() == input_types.len()
{ {
let assoc_name = assoc.name();
err.span_suggestion_verbose( err.span_suggestion_verbose(
call_name.span, call_name.span,
format!("you might have meant to use `{}`", assoc.name), format!("you might have meant to use `{}`", assoc_name),
assoc.name, assoc_name,
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
return; return;
@ -707,7 +707,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
tcx.def_span(assoc.def_id), tcx.def_span(assoc.def_id),
format!( format!(
"there's is a method with similar name `{}`, but the arguments don't match", "there's is a method with similar name `{}`, but the arguments don't match",
assoc.name, assoc.name(),
), ),
); );
return; return;
@ -719,7 +719,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
format!( format!(
"there's is a method with similar name `{}`, but their argument count \ "there's is a method with similar name `{}`, but their argument count \
doesn't match", doesn't match",
assoc.name, assoc.name(),
), ),
); );
return; return;

View file

@ -314,7 +314,7 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
item_def_id: DefId, item_def_id: DefId,
item_segment: &rustc_hir::PathSegment<'tcx>, item_segment: &rustc_hir::PathSegment<'tcx>,
poly_trait_ref: ty::PolyTraitRef<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>,
_kind: ty::AssocKind, _assoc_tag: ty::AssocTag,
) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> { ) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> {
let trait_ref = self.instantiate_binder_with_fresh_vars( let trait_ref = self.instantiate_binder_with_fresh_vars(
span, span,

View file

@ -381,9 +381,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut suggestions = methods let mut suggestions = methods
.iter() .iter()
.filter_map(|conversion_method| { .filter_map(|conversion_method| {
let conversion_method_name = conversion_method.name();
let receiver_method_ident = expr.method_ident(); let receiver_method_ident = expr.method_ident();
if let Some(method_ident) = receiver_method_ident if let Some(method_ident) = receiver_method_ident
&& method_ident.name == conversion_method.name && method_ident.name == conversion_method_name
{ {
return None; // do not suggest code that is already there (#53348) return None; // do not suggest code that is already there (#53348)
} }
@ -391,20 +392,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let method_call_list = [sym::to_vec, sym::to_string]; let method_call_list = [sym::to_vec, sym::to_string];
let mut sugg = if let ExprKind::MethodCall(receiver_method, ..) = expr.kind let mut sugg = if let ExprKind::MethodCall(receiver_method, ..) = expr.kind
&& receiver_method.ident.name == sym::clone && receiver_method.ident.name == sym::clone
&& method_call_list.contains(&conversion_method.name) && method_call_list.contains(&conversion_method_name)
// If receiver is `.clone()` and found type has one of those methods, // If receiver is `.clone()` and found type has one of those methods,
// we guess that the user wants to convert from a slice type (`&[]` or `&str`) // we guess that the user wants to convert from a slice type (`&[]` or `&str`)
// to an owned type (`Vec` or `String`). These conversions clone internally, // to an owned type (`Vec` or `String`). These conversions clone internally,
// so we remove the user's `clone` call. // so we remove the user's `clone` call.
{ {
vec![(receiver_method.ident.span, conversion_method.name.to_string())] vec![(receiver_method.ident.span, conversion_method_name.to_string())]
} else if expr.precedence() < ExprPrecedence::Unambiguous { } else if expr.precedence() < ExprPrecedence::Unambiguous {
vec![ vec![
(expr.span.shrink_to_lo(), "(".to_string()), (expr.span.shrink_to_lo(), "(".to_string()),
(expr.span.shrink_to_hi(), format!(").{}()", conversion_method.name)), (expr.span.shrink_to_hi(), format!(").{}()", conversion_method_name)),
] ]
} else { } else {
vec![(expr.span.shrink_to_hi(), format!(".{}()", conversion_method.name))] vec![(expr.span.shrink_to_hi(), format!(".{}()", conversion_method_name))]
}; };
let struct_pat_shorthand_field = let struct_pat_shorthand_field =
self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr); self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr);

View file

@ -265,7 +265,7 @@ fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Opti
let expected_type = if let Some(&hir::Ty { kind: hir::TyKind::Infer(()), span, .. }) = node.ty() let expected_type = if let Some(&hir::Ty { kind: hir::TyKind::Infer(()), span, .. }) = node.ty()
{ {
if let Some(item) = tcx.opt_associated_item(def_id.into()) if let Some(item) = tcx.opt_associated_item(def_id.into())
&& let ty::AssocKind::Const = item.kind && let ty::AssocKind::Const { .. } = item.kind
&& let ty::AssocItemContainer::Impl = item.container && let ty::AssocItemContainer::Impl = item.container
&& let Some(trait_item_def_id) = item.trait_item_def_id && let Some(trait_item_def_id) = item.trait_item_def_id
{ {

View file

@ -379,7 +379,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}; };
let def_id = method_item.def_id; let def_id = method_item.def_id;
if method_item.kind != ty::AssocKind::Fn { if !method_item.is_fn() {
span_bug!(tcx.def_span(def_id), "expected `{m_name}` to be an associated function"); span_bug!(tcx.def_span(def_id), "expected `{m_name}` to be an associated function");
} }
@ -529,7 +529,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
} }
let def_kind = pick.item.kind.as_def_kind(); let def_kind = pick.item.as_def_kind();
tcx.check_stability(pick.item.def_id, Some(expr_id), span, Some(method_name.span)); tcx.check_stability(pick.item.def_id, Some(expr_id), span, Some(method_name.span));
Ok((def_kind, pick.item.def_id)) Ok((def_kind, pick.item.def_id))
} }

View file

@ -992,7 +992,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
fn matches_return_type(&self, method: ty::AssocItem, expected: Ty<'tcx>) -> bool { fn matches_return_type(&self, method: ty::AssocItem, expected: Ty<'tcx>) -> bool {
match method.kind { match method.kind {
ty::AssocKind::Fn => self.probe(|_| { ty::AssocKind::Fn { .. } => self.probe(|_| {
let args = self.fresh_args_for_item(self.span, method.def_id); let args = self.fresh_args_for_item(self.span, method.def_id);
let fty = self.tcx.fn_sig(method.def_id).instantiate(self.tcx, args); let fty = self.tcx.fn_sig(method.def_id).instantiate(self.tcx, args);
let fty = self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, fty); let fty = self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, fty);
@ -1583,7 +1583,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}, },
None, None,
) { ) {
self.private_candidate.set(Some((pick.item.kind.as_def_kind(), pick.item.def_id))); self.private_candidate.set(Some((pick.item.as_def_kind(), pick.item.def_id)));
} }
} }
None None
@ -1671,16 +1671,7 @@ impl<'tcx> Pick<'tcx> {
/// Do not use for type checking. /// Do not use for type checking.
pub(crate) fn differs_from(&self, other: &Self) -> bool { pub(crate) fn differs_from(&self, other: &Self) -> bool {
let Self { let Self {
item: item: AssocItem { def_id, kind: _, container: _, trait_item_def_id: _ },
AssocItem {
def_id,
name: _,
kind: _,
container: _,
trait_item_def_id: _,
fn_has_self_parameter: _,
opt_rpitit_info: _,
},
kind: _, kind: _,
import_ids: _, import_ids: _,
autoderefs: _, autoderefs: _,
@ -1703,7 +1694,7 @@ impl<'tcx> Pick<'tcx> {
if self.unstable_candidates.is_empty() { if self.unstable_candidates.is_empty() {
return; return;
} }
let def_kind = self.item.kind.as_def_kind(); let def_kind = self.item.as_def_kind();
tcx.node_span_lint(lint::builtin::UNSTABLE_NAME_COLLISIONS, scope_expr_id, span, |lint| { tcx.node_span_lint(lint::builtin::UNSTABLE_NAME_COLLISIONS, scope_expr_id, span, |lint| {
lint.primary_message(format!( lint.primary_message(format!(
"{} {} with this name may be added to the standard library in the future", "{} {} with this name may be added to the standard library in the future",
@ -1712,7 +1703,7 @@ impl<'tcx> Pick<'tcx> {
)); ));
match (self.item.kind, self.item.container) { match (self.item.kind, self.item.container) {
(ty::AssocKind::Fn, _) => { (ty::AssocKind::Fn { .. }, _) => {
// FIXME: This should be a `span_suggestion` instead of `help` // FIXME: This should be a `span_suggestion` instead of `help`
// However `self.span` only // However `self.span` only
// highlights the method name, so we can't use it. Also consider reusing // highlights the method name, so we can't use it. Also consider reusing
@ -1723,17 +1714,12 @@ impl<'tcx> Pick<'tcx> {
tcx.def_path_str(self.item.def_id), tcx.def_path_str(self.item.def_id),
)); ));
} }
(ty::AssocKind::Const, ty::AssocItemContainer::Trait) => { (ty::AssocKind::Const { name }, ty::AssocItemContainer::Trait) => {
let def_id = self.item.container_id(tcx); let def_id = self.item.container_id(tcx);
lint.span_suggestion( lint.span_suggestion(
span, span,
"use the fully qualified path to the associated const", "use the fully qualified path to the associated const",
format!( format!("<{} as {}>::{}", self.self_ty, tcx.def_path_str(def_id), name),
"<{} as {}>::{}",
self.self_ty,
tcx.def_path_str(def_id),
self.item.name
),
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
} }
@ -2222,7 +2208,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let best_name = { let best_name = {
let names = applicable_close_candidates let names = applicable_close_candidates
.iter() .iter()
.map(|cand| cand.name) .map(|cand| cand.name())
.collect::<Vec<Symbol>>(); .collect::<Vec<Symbol>>();
find_best_match_for_name_with_substrings( find_best_match_for_name_with_substrings(
&names, &names,
@ -2234,10 +2220,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
applicable_close_candidates applicable_close_candidates
.iter() .iter()
.find(|cand| self.matches_by_doc_alias(cand.def_id)) .find(|cand| self.matches_by_doc_alias(cand.def_id))
.map(|cand| cand.name) .map(|cand| cand.name())
}); });
Ok(best_name.and_then(|best_name| { Ok(best_name.and_then(|best_name| {
applicable_close_candidates.into_iter().find(|method| method.name == best_name) applicable_close_candidates
.into_iter()
.find(|method| method.name() == best_name)
})) }))
} }
}) })
@ -2252,10 +2240,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
// In Path mode (i.e., resolving a value like `T::next`), consider any // In Path mode (i.e., resolving a value like `T::next`), consider any
// associated value (i.e., methods, constants) but not types. // associated value (i.e., methods, constants) but not types.
match self.mode { match self.mode {
Mode::MethodCall => item.fn_has_self_parameter, Mode::MethodCall => item.is_method(),
Mode::Path => match item.kind { Mode::Path => match item.kind {
ty::AssocKind::Type => false, ty::AssocKind::Type { .. } => false,
ty::AssocKind::Fn | ty::AssocKind::Const => true, ty::AssocKind::Fn { .. } | ty::AssocKind::Const { .. } => true,
}, },
} }
// FIXME -- check for types that deref to `Self`, // FIXME -- check for types that deref to `Self`,
@ -2277,7 +2265,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
impl_ty: Ty<'tcx>, impl_ty: Ty<'tcx>,
args: GenericArgsRef<'tcx>, args: GenericArgsRef<'tcx>,
) -> (Ty<'tcx>, Option<Ty<'tcx>>) { ) -> (Ty<'tcx>, Option<Ty<'tcx>>) {
if item.kind == ty::AssocKind::Fn && self.mode == Mode::MethodCall { if item.is_fn() && self.mode == Mode::MethodCall {
let sig = self.xform_method_sig(item.def_id, args); let sig = self.xform_method_sig(item.def_id, args);
(sig.inputs()[0], Some(sig.output())) (sig.inputs()[0], Some(sig.output()))
} else { } else {
@ -2328,8 +2316,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
/// Determine if the given associated item type is relevant in the current context. /// Determine if the given associated item type is relevant in the current context.
fn is_relevant_kind_for_mode(&self, kind: ty::AssocKind) -> bool { fn is_relevant_kind_for_mode(&self, kind: ty::AssocKind) -> bool {
match (self.mode, kind) { match (self.mode, kind) {
(Mode::MethodCall, ty::AssocKind::Fn) => true, (Mode::MethodCall, ty::AssocKind::Fn { .. }) => true,
(Mode::Path, ty::AssocKind::Const | ty::AssocKind::Fn) => true, (Mode::Path, ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. }) => true,
_ => false, _ => false,
} }
} }
@ -2411,7 +2399,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
} }
match edit_distance_with_substrings( match edit_distance_with_substrings(
name.as_str(), name.as_str(),
x.name.as_str(), x.name().as_str(),
max_dist, max_dist,
) { ) {
Some(d) => d > 0, Some(d) => d > 0,

View file

@ -713,7 +713,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& let Some(candidate) = tcx.associated_items(impl_def_id).find_by_ident_and_kind( && let Some(candidate) = tcx.associated_items(impl_def_id).find_by_ident_and_kind(
self.tcx, self.tcx,
item_ident, item_ident,
ty::AssocKind::Type, ty::AssocTag::Type,
impl_def_id, impl_def_id,
) )
&& let Some(adt_def) = tcx.type_of(candidate.def_id).skip_binder().ty_adt_def() && let Some(adt_def) = tcx.type_of(candidate.def_id).skip_binder().ty_adt_def()
@ -1442,7 +1442,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some(assoc) = self.associated_value(*def_id, item_ident) { if let Some(assoc) = self.associated_value(*def_id, item_ident) {
// Check for both mode is the same so we avoid suggesting // Check for both mode is the same so we avoid suggesting
// incorrect associated item. // incorrect associated item.
match (mode, assoc.fn_has_self_parameter, source) { match (mode, assoc.is_method(), source) {
(Mode::MethodCall, true, SelfSource::MethodCall(_)) => { (Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
// We check that the suggest type is actually // We check that the suggest type is actually
// different from the received one // different from the received one
@ -1722,7 +1722,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// that had unsatisfied trait bounds // that had unsatisfied trait bounds
if unsatisfied_predicates.is_empty() if unsatisfied_predicates.is_empty()
// ...or if we already suggested that name because of `rustc_confusable` annotation. // ...or if we already suggested that name because of `rustc_confusable` annotation.
&& Some(similar_candidate.name) != confusable_suggested && Some(similar_candidate.name()) != confusable_suggested
{ {
self.find_likely_intended_associated_item( self.find_likely_intended_associated_item(
&mut err, &mut err,
@ -1819,12 +1819,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
mode: Mode, mode: Mode,
) { ) {
let tcx = self.tcx; let tcx = self.tcx;
let def_kind = similar_candidate.kind.as_def_kind(); let def_kind = similar_candidate.as_def_kind();
let an = self.tcx.def_kind_descr_article(def_kind, similar_candidate.def_id); let an = self.tcx.def_kind_descr_article(def_kind, similar_candidate.def_id);
let similar_candidate_name = similar_candidate.name();
let msg = format!( let msg = format!(
"there is {an} {} `{}` with a similar name", "there is {an} {} `{}` with a similar name",
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id), self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
similar_candidate.name, similar_candidate_name,
); );
// Methods are defined within the context of a struct and their first parameter // Methods are defined within the context of a struct and their first parameter
// is always `self`, which represents the instance of the struct the method is // is always `self`, which represents the instance of the struct the method is
@ -1834,7 +1835,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let ty_args = self.infcx.fresh_args_for_item(span, similar_candidate.def_id); let ty_args = self.infcx.fresh_args_for_item(span, similar_candidate.def_id);
let fn_sig = tcx.fn_sig(similar_candidate.def_id).instantiate(tcx, ty_args); let fn_sig = tcx.fn_sig(similar_candidate.def_id).instantiate(tcx, ty_args);
let fn_sig = self.instantiate_binder_with_fresh_vars(span, infer::FnCall, fn_sig); let fn_sig = self.instantiate_binder_with_fresh_vars(span, infer::FnCall, fn_sig);
if similar_candidate.fn_has_self_parameter { if similar_candidate.is_method() {
if let Some(args) = args if let Some(args) = args
&& fn_sig.inputs()[1..].len() == args.len() && fn_sig.inputs()[1..].len() == args.len()
{ {
@ -1843,7 +1844,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_suggestion_verbose( err.span_suggestion_verbose(
span, span,
msg, msg,
similar_candidate.name, similar_candidate_name,
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
} else { } else {
@ -1865,7 +1866,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_suggestion_verbose( err.span_suggestion_verbose(
span, span,
msg, msg,
similar_candidate.name, similar_candidate_name,
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
} else { } else {
@ -1878,7 +1879,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_suggestion_verbose( err.span_suggestion_verbose(
span, span,
msg, msg,
similar_candidate.name, similar_candidate_name,
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
} else { } else {
@ -1902,7 +1903,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{ {
if let Some(candidates) = find_attr!(self.tcx.get_all_attrs(inherent_method.def_id), AttributeKind::Confusables{symbols, ..} => symbols) if let Some(candidates) = find_attr!(self.tcx.get_all_attrs(inherent_method.def_id), AttributeKind::Confusables{symbols, ..} => symbols)
&& candidates.contains(&item_name.name) && candidates.contains(&item_name.name)
&& let ty::AssocKind::Fn = inherent_method.kind && inherent_method.is_fn()
{ {
let args = let args =
ty::GenericArgs::identity_for_item(self.tcx, inherent_method.def_id) ty::GenericArgs::identity_for_item(self.tcx, inherent_method.def_id)
@ -1918,6 +1919,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
infer::FnCall, infer::FnCall,
fn_sig, fn_sig,
); );
let name = inherent_method.name();
if let Some(ref args) = call_args if let Some(ref args) = call_args
&& fn_sig.inputs()[1..] && fn_sig.inputs()[1..]
.iter() .iter()
@ -1927,20 +1929,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{ {
err.span_suggestion_verbose( err.span_suggestion_verbose(
item_name.span, item_name.span,
format!("you might have meant to use `{}`", inherent_method.name), format!("you might have meant to use `{}`", name),
inherent_method.name, name,
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
return Some(inherent_method.name); return Some(name);
} else if let None = call_args { } else if let None = call_args {
err.span_note( err.span_note(
self.tcx.def_span(inherent_method.def_id), self.tcx.def_span(inherent_method.def_id),
format!( format!("you might have meant to use method `{}`", name),
"you might have meant to use method `{}`",
inherent_method.name,
),
); );
return Some(inherent_method.name); return Some(name);
} }
} }
} }
@ -2116,8 +2115,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Only assoc fn with no receivers and only if // Only assoc fn with no receivers and only if
// they are resolvable // they are resolvable
.filter(|item| { .filter(|item| {
matches!(item.kind, ty::AssocKind::Fn) matches!(item.kind, ty::AssocKind::Fn { has_self: false, .. })
&& !item.fn_has_self_parameter
&& self && self
.probe_for_name( .probe_for_name(
Mode::Path, Mode::Path,
@ -2261,7 +2259,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}; };
let assoc = self.associated_value(assoc_did, item_name)?; let assoc = self.associated_value(assoc_did, item_name)?;
if assoc.kind != ty::AssocKind::Fn { if !assoc.is_fn() {
return None; return None;
} }
@ -3208,7 +3206,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If this method receives `&self`, then the provided // If this method receives `&self`, then the provided
// argument _should_ coerce, so it's valid to suggest // argument _should_ coerce, so it's valid to suggest
// just changing the path. // just changing the path.
&& pick.item.fn_has_self_parameter && pick.item.is_method()
&& let Some(self_ty) = && let Some(self_ty) =
self.tcx.fn_sig(pick.item.def_id).instantiate_identity().inputs().skip_binder().get(0) self.tcx.fn_sig(pick.item.def_id).instantiate_identity().inputs().skip_binder().get(0)
&& self_ty.is_ref() && self_ty.is_ref()
@ -3560,7 +3558,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|| (("Pin::new" == *pre) || (("Pin::new" == *pre)
&& ((sym::as_ref == item_name.name) || !unpin)) && ((sym::as_ref == item_name.name) || !unpin))
|| inputs_len.is_some_and(|inputs_len| { || inputs_len.is_some_and(|inputs_len| {
pick.item.kind == ty::AssocKind::Fn pick.item.is_fn()
&& self && self
.tcx .tcx
.fn_sig(pick.item.def_id) .fn_sig(pick.item.def_id)
@ -3618,7 +3616,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& pick.autoderefs == 0 && pick.autoderefs == 0
// Check that the method of the same name that was found on the new `Pin<T>` // Check that the method of the same name that was found on the new `Pin<T>`
// receiver has the same number of arguments that appear in the user's code. // receiver has the same number of arguments that appear in the user's code.
&& inputs_len.is_some_and(|inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() == inputs_len) && inputs_len.is_some_and(|inputs_len| pick.item.is_fn() && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() == inputs_len)
{ {
let indent = self let indent = self
.tcx .tcx
@ -3756,7 +3754,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& self && self
.associated_value(info.def_id, item_name) .associated_value(info.def_id, item_name)
.filter(|item| { .filter(|item| {
if let ty::AssocKind::Fn = item.kind { if item.is_fn() {
let id = item let id = item
.def_id .def_id
.as_local() .as_local()
@ -4279,17 +4277,17 @@ fn print_disambiguation_help<'tcx>(
item: ty::AssocItem, item: ty::AssocItem,
) -> Option<String> { ) -> Option<String> {
let trait_impl_type = trait_ref.self_ty().peel_refs(); let trait_impl_type = trait_ref.self_ty().peel_refs();
let trait_ref = if item.fn_has_self_parameter { let trait_ref = if item.is_method() {
trait_ref.print_only_trait_name().to_string() trait_ref.print_only_trait_name().to_string()
} else { } else {
format!("<{} as {}>", trait_ref.args[0], trait_ref.print_only_trait_name()) format!("<{} as {}>", trait_ref.args[0], trait_ref.print_only_trait_name())
}; };
Some( Some(
if matches!(item.kind, ty::AssocKind::Fn) if item.is_fn()
&& let SelfSource::MethodCall(receiver) = source && let SelfSource::MethodCall(receiver) = source
&& let Some(args) = args && let Some(args) = args
{ {
let def_kind_descr = tcx.def_kind_descr(item.kind.as_def_kind(), item.def_id); let def_kind_descr = tcx.def_kind_descr(item.as_def_kind(), item.def_id);
let item_name = item.ident(tcx); let item_name = item.ident(tcx);
let first_input = let first_input =
tcx.fn_sig(item.def_id).instantiate_identity().skip_binder().inputs().get(0); tcx.fn_sig(item.def_id).instantiate_identity().skip_binder().inputs().get(0);
@ -4304,7 +4302,7 @@ fn print_disambiguation_help<'tcx>(
let args = if let Some(first_arg_type) = first_arg_type let args = if let Some(first_arg_type) = first_arg_type
&& (first_arg_type == tcx.types.self_param && (first_arg_type == tcx.types.self_param
|| first_arg_type == trait_impl_type || first_arg_type == trait_impl_type
|| item.fn_has_self_parameter) || item.is_method())
{ {
Some(receiver) Some(receiver)
} else { } else {

View file

@ -372,7 +372,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.associated_item_def_ids(def_id) .associated_item_def_ids(def_id)
.iter() .iter()
.find(|item_def_id| { .find(|item_def_id| {
self.tcx.associated_item(*item_def_id).name == sym::Output self.tcx.associated_item(*item_def_id).name() == sym::Output
}) })
.cloned() .cloned()
}); });

View file

@ -855,11 +855,11 @@ impl<'tcx> LateContext<'tcx> {
&self, &self,
self_ty: Ty<'tcx>, self_ty: Ty<'tcx>,
trait_id: DefId, trait_id: DefId,
name: &str, name: Symbol,
) -> Option<Ty<'tcx>> { ) -> Option<Ty<'tcx>> {
let tcx = self.tcx; let tcx = self.tcx;
tcx.associated_items(trait_id) tcx.associated_items(trait_id)
.find_by_ident_and_kind(tcx, Ident::from_str(name), ty::AssocKind::Type, trait_id) .find_by_ident_and_kind(tcx, Ident::with_dummy_span(name), ty::AssocTag::Type, trait_id)
.and_then(|assoc| { .and_then(|assoc| {
let proj = Ty::new_projection(tcx, assoc.def_id, [self_ty]); let proj = Ty::new_projection(tcx, assoc.def_id, [self_ty]);
tcx.try_normalize_erasing_regions(self.typing_env(), proj).ok() tcx.try_normalize_erasing_regions(self.typing_env(), proj).ok()

View file

@ -69,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait {
&& let ty::Dynamic(data, _, ty::Dyn) = self_ty.kind() && let ty::Dynamic(data, _, ty::Dyn) = self_ty.kind()
&& let Some(self_principal) = data.principal() && let Some(self_principal) = data.principal()
// `<T as Deref>::Target` is `dyn target_principal` // `<T as Deref>::Target` is `dyn target_principal`
&& let Some(target) = cx.get_associated_type(self_ty, did, "Target") && let Some(target) = cx.get_associated_type(self_ty, did, sym::Target)
&& let ty::Dynamic(data, _, ty::Dyn) = target.kind() && let ty::Dynamic(data, _, ty::Dyn) = target.kind()
&& let Some(target_principal) = data.principal() && let Some(target_principal) = data.principal()
// `target_principal` is a supertrait of `t_principal` // `target_principal` is a supertrait of `t_principal`

View file

@ -1332,29 +1332,30 @@ impl<'a> CrateMetadataRef<'a> {
} }
fn get_associated_item(self, id: DefIndex, sess: &'a Session) -> ty::AssocItem { fn get_associated_item(self, id: DefIndex, sess: &'a Session) -> ty::AssocItem {
let name = if self.root.tables.opt_rpitit_info.get(self, id).is_some() { let kind = match self.def_kind(id) {
kw::Empty DefKind::AssocConst => ty::AssocKind::Const { name: self.item_name(id) },
DefKind::AssocFn => ty::AssocKind::Fn {
name: self.item_name(id),
has_self: self.get_fn_has_self_parameter(id, sess),
},
DefKind::AssocTy => {
let data = if let Some(rpitit_info) = self.root.tables.opt_rpitit_info.get(self, id)
{
ty::AssocTypeData::Rpitit(rpitit_info.decode(self))
} else { } else {
self.item_name(id) ty::AssocTypeData::Normal(self.item_name(id))
}; };
let (kind, has_self) = match self.def_kind(id) { ty::AssocKind::Type { data }
DefKind::AssocConst => (ty::AssocKind::Const, false), }
DefKind::AssocFn => (ty::AssocKind::Fn, self.get_fn_has_self_parameter(id, sess)),
DefKind::AssocTy => (ty::AssocKind::Type, false),
_ => bug!("cannot get associated-item of `{:?}`", self.def_key(id)), _ => bug!("cannot get associated-item of `{:?}`", self.def_key(id)),
}; };
let container = self.root.tables.assoc_container.get(self, id).unwrap(); let container = self.root.tables.assoc_container.get(self, id).unwrap();
let opt_rpitit_info =
self.root.tables.opt_rpitit_info.get(self, id).map(|d| d.decode(self));
ty::AssocItem { ty::AssocItem {
name,
kind, kind,
def_id: self.local_def_id(id), def_id: self.local_def_id(id),
trait_item_def_id: self.get_trait_item_def_id(id), trait_item_def_id: self.get_trait_item_def_id(id),
container, container,
fn_has_self_parameter: has_self,
opt_rpitit_info,
} }
} }

View file

@ -1338,7 +1338,7 @@ fn should_encode_const(def_kind: DefKind) -> bool {
fn should_encode_fn_impl_trait_in_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { fn should_encode_fn_impl_trait_in_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
if let Some(assoc_item) = tcx.opt_associated_item(def_id) if let Some(assoc_item) = tcx.opt_associated_item(def_id)
&& assoc_item.container == ty::AssocItemContainer::Trait && assoc_item.container == ty::AssocItemContainer::Trait
&& assoc_item.kind == ty::AssocKind::Fn && assoc_item.is_fn()
{ {
true true
} else { } else {
@ -1691,7 +1691,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
match item.container { match item.container {
AssocItemContainer::Trait => { AssocItemContainer::Trait => {
if let ty::AssocKind::Type = item.kind { if item.is_type() {
self.encode_explicit_item_bounds(def_id); self.encode_explicit_item_bounds(def_id);
self.encode_explicit_item_self_bounds(def_id); self.encode_explicit_item_self_bounds(def_id);
if tcx.is_conditionally_const(def_id) { if tcx.is_conditionally_const(def_id) {
@ -1706,7 +1706,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
} }
} }
} }
if let Some(rpitit_info) = item.opt_rpitit_info { if let ty::AssocKind::Type { data: ty::AssocTypeData::Rpitit(rpitit_info) } = item.kind {
record!(self.tables.opt_rpitit_info[def_id] <- rpitit_info); record!(self.tables.opt_rpitit_info[def_id] <- rpitit_info);
if matches!(rpitit_info, ty::ImplTraitInTraitData::Trait { .. }) { if matches!(rpitit_info, ty::ImplTraitInTraitData::Trait { .. }) {
record_array!( record_array!(

View file

@ -1636,8 +1636,8 @@ pub fn find_self_call<'tcx>(
&body[block].terminator &body[block].terminator
&& let Operand::Constant(box ConstOperand { const_, .. }) = func && let Operand::Constant(box ConstOperand { const_, .. }) = func
&& let ty::FnDef(def_id, fn_args) = *const_.ty().kind() && let ty::FnDef(def_id, fn_args) = *const_.ty().kind()
&& let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) = && let Some(item) = tcx.opt_associated_item(def_id)
tcx.opt_associated_item(def_id) && item.is_method()
&& let [Spanned { node: Operand::Move(self_place) | Operand::Copy(self_place), .. }, ..] = && let [Spanned { node: Operand::Move(self_place) | Operand::Copy(self_place), .. }, ..] =
**args **args
{ {

View file

@ -5,7 +5,7 @@ use rustc_hir::lang_items::LangItem;
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
use rustc_span::Span; use rustc_span::Span;
use crate::ty::{self, Ty, TyCtxt}; use crate::ty::{Ty, TyCtxt};
#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
pub enum PointerCoercion { pub enum PointerCoercion {
@ -133,7 +133,7 @@ impl OverloadedDeref {
}; };
tcx.associated_items(trait_def_id) tcx.associated_items(trait_def_id)
.in_definition_order() .in_definition_order()
.find(|m| m.kind == ty::AssocKind::Fn) .find(|item| item.is_fn())
.unwrap() .unwrap()
.def_id .def_id
} }

View file

@ -18,27 +18,33 @@ pub enum AssocItemContainer {
#[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash, Encodable, Decodable)] #[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash, Encodable, Decodable)]
pub struct AssocItem { pub struct AssocItem {
pub def_id: DefId, pub def_id: DefId,
pub name: Symbol,
pub kind: AssocKind, pub kind: AssocKind,
pub container: AssocItemContainer, pub container: AssocItemContainer,
/// If this is an item in an impl of a trait then this is the `DefId` of /// If this is an item in an impl of a trait then this is the `DefId` of
/// the associated item on the trait that this implements. /// the associated item on the trait that this implements.
pub trait_item_def_id: Option<DefId>, pub trait_item_def_id: Option<DefId>,
/// Whether this is a method with an explicit self
/// as its first parameter, allowing method calls.
pub fn_has_self_parameter: bool,
/// `Some` if the associated item (an associated type) comes from the
/// return-position `impl Trait` in trait desugaring. The `ImplTraitInTraitData`
/// provides additional information about its source.
pub opt_rpitit_info: Option<ty::ImplTraitInTraitData>,
} }
impl AssocItem { impl AssocItem {
// Gets the identifier, if it has one.
pub fn opt_name(&self) -> Option<Symbol> {
match self.kind {
ty::AssocKind::Type { data: AssocTypeData::Normal(name) } => Some(name),
ty::AssocKind::Type { data: AssocTypeData::Rpitit(_) } => None,
ty::AssocKind::Const { name } => Some(name),
ty::AssocKind::Fn { name, .. } => Some(name),
}
}
// Gets the identifier name. Aborts if it lacks one, i.e. is an RPITIT
// associated type.
pub fn name(&self) -> Symbol {
self.opt_name().expect("name of non-Rpitit assoc item")
}
pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident { pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap()) Ident::new(self.name(), tcx.def_ident_span(self.def_id).unwrap())
} }
/// Gets the defaultness of the associated item. /// Gets the defaultness of the associated item.
@ -78,35 +84,65 @@ impl AssocItem {
pub fn signature(&self, tcx: TyCtxt<'_>) -> String { pub fn signature(&self, tcx: TyCtxt<'_>) -> String {
match self.kind { match self.kind {
ty::AssocKind::Fn => { ty::AssocKind::Fn { .. } => {
// We skip the binder here because the binder would deanonymize all // We skip the binder here because the binder would deanonymize all
// late-bound regions, and we don't want method signatures to show up // 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)`. // regions just fine, showing `fn(&MyType)`.
tcx.fn_sig(self.def_id).instantiate_identity().skip_binder().to_string() tcx.fn_sig(self.def_id).instantiate_identity().skip_binder().to_string()
} }
ty::AssocKind::Type => format!("type {};", self.name), ty::AssocKind::Type { .. } => format!("type {};", self.name()),
ty::AssocKind::Const => { ty::AssocKind::Const { name } => {
format!( format!("const {}: {:?};", name, tcx.type_of(self.def_id).instantiate_identity())
"const {}: {:?};",
self.name,
tcx.type_of(self.def_id).instantiate_identity()
)
} }
} }
} }
pub fn descr(&self) -> &'static str { pub fn descr(&self) -> &'static str {
match self.kind { match self.kind {
ty::AssocKind::Const => "associated const", ty::AssocKind::Const { .. } => "associated const",
ty::AssocKind::Fn if self.fn_has_self_parameter => "method", ty::AssocKind::Fn { has_self: true, .. } => "method",
ty::AssocKind::Fn => "associated function", ty::AssocKind::Fn { has_self: false, .. } => "associated function",
ty::AssocKind::Type => "associated type", ty::AssocKind::Type { .. } => "associated type",
}
}
pub fn namespace(&self) -> Namespace {
match self.kind {
ty::AssocKind::Type { .. } => Namespace::TypeNS,
ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => Namespace::ValueNS,
}
}
pub fn as_def_kind(&self) -> DefKind {
match self.kind {
AssocKind::Const { .. } => DefKind::AssocConst,
AssocKind::Fn { .. } => DefKind::AssocFn,
AssocKind::Type { .. } => DefKind::AssocTy,
}
}
pub fn is_type(&self) -> bool {
matches!(self.kind, ty::AssocKind::Type { .. })
}
pub fn is_fn(&self) -> bool {
matches!(self.kind, ty::AssocKind::Fn { .. })
}
pub fn is_method(&self) -> bool {
matches!(self.kind, ty::AssocKind::Fn { has_self: true, .. })
}
pub fn as_tag(&self) -> AssocTag {
match self.kind {
AssocKind::Const { .. } => AssocTag::Const,
AssocKind::Fn { .. } => AssocTag::Fn,
AssocKind::Type { .. } => AssocTag::Type,
} }
} }
pub fn is_impl_trait_in_trait(&self) -> bool { pub fn is_impl_trait_in_trait(&self) -> bool {
self.opt_rpitit_info.is_some() matches!(self.kind, AssocKind::Type { data: AssocTypeData::Rpitit(_) })
} }
/// Returns true if: /// Returns true if:
@ -114,7 +150,7 @@ impl AssocItem {
/// - If it is in a trait impl, the item from the original trait has this attribute, or /// - If it is in a trait impl, the item from the original trait has this attribute, or
/// - It is an inherent assoc const. /// - It is an inherent assoc const.
pub fn is_type_const_capable(&self, tcx: TyCtxt<'_>) -> bool { pub fn is_type_const_capable(&self, tcx: TyCtxt<'_>) -> bool {
if self.kind != ty::AssocKind::Const { if !matches!(self.kind, ty::AssocKind::Const { .. }) {
return false; return false;
} }
@ -128,26 +164,35 @@ impl AssocItem {
} }
} }
#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)]
pub enum AssocTypeData {
Normal(Symbol),
/// The associated type comes from an RPITIT. It has no name, and the
/// `ImplTraitInTraitData` provides additional information about its
/// source.
Rpitit(ty::ImplTraitInTraitData),
}
#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)] #[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)]
pub enum AssocKind { pub enum AssocKind {
Const, Const { name: Symbol },
Fn, Fn { name: Symbol, has_self: bool },
Type, Type { data: AssocTypeData },
} }
impl AssocKind { impl AssocKind {
pub fn namespace(&self) -> Namespace { pub fn namespace(&self) -> Namespace {
match *self { match *self {
ty::AssocKind::Type => Namespace::TypeNS, ty::AssocKind::Type { .. } => Namespace::TypeNS,
ty::AssocKind::Const | ty::AssocKind::Fn => Namespace::ValueNS, ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => Namespace::ValueNS,
} }
} }
pub fn as_def_kind(&self) -> DefKind { pub fn as_def_kind(&self) -> DefKind {
match self { match self {
AssocKind::Const => DefKind::AssocConst, AssocKind::Const { .. } => DefKind::AssocConst,
AssocKind::Fn => DefKind::AssocFn, AssocKind::Fn { .. } => DefKind::AssocFn,
AssocKind::Type => DefKind::AssocTy, AssocKind::Type { .. } => DefKind::AssocTy,
} }
} }
} }
@ -155,15 +200,22 @@ impl AssocKind {
impl std::fmt::Display for AssocKind { impl std::fmt::Display for AssocKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
// FIXME: fails to distinguish between "associated function" and AssocKind::Fn { has_self: true, .. } => write!(f, "method"),
// "method" because `has_self` isn't known here. AssocKind::Fn { has_self: false, .. } => write!(f, "associated function"),
AssocKind::Fn => write!(f, "method"), AssocKind::Const { .. } => write!(f, "associated const"),
AssocKind::Const => write!(f, "associated const"), AssocKind::Type { .. } => write!(f, "associated type"),
AssocKind::Type => write!(f, "associated type"),
} }
} }
} }
// Like `AssocKind`, but just the tag, no fields. Used in various kinds of matching.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum AssocTag {
Const,
Fn,
Type,
}
/// A list of `ty::AssocItem`s in definition order that allows for efficient lookup by name. /// A list of `ty::AssocItem`s in definition order that allows for efficient lookup by name.
/// ///
/// When doing lookup by name, we try to postpone hygienic comparison for as long as possible since /// When doing lookup by name, we try to postpone hygienic comparison for as long as possible since
@ -171,17 +223,17 @@ impl std::fmt::Display for AssocKind {
/// done only on items with the same name. /// done only on items with the same name.
#[derive(Debug, Clone, PartialEq, HashStable)] #[derive(Debug, Clone, PartialEq, HashStable)]
pub struct AssocItems { pub struct AssocItems {
items: SortedIndexMultiMap<u32, Symbol, ty::AssocItem>, items: SortedIndexMultiMap<u32, Option<Symbol>, ty::AssocItem>,
} }
impl AssocItems { impl AssocItems {
/// Constructs an `AssociatedItems` map from a series of `ty::AssocItem`s in definition order. /// Constructs an `AssociatedItems` map from a series of `ty::AssocItem`s in definition order.
pub fn new(items_in_def_order: impl IntoIterator<Item = ty::AssocItem>) -> Self { pub fn new(items_in_def_order: impl IntoIterator<Item = ty::AssocItem>) -> Self {
let items = items_in_def_order.into_iter().map(|item| (item.name, item)).collect(); let items = items_in_def_order.into_iter().map(|item| (item.opt_name(), item)).collect();
AssocItems { items } AssocItems { items }
} }
/// Returns a slice of associated items in the order they were defined. /// Returns an iterator over associated items in the order they were defined.
/// ///
/// New code should avoid relying on definition order. If you need a particular associated item /// New code should avoid relying on definition order. If you need a particular associated item
/// for a known trait, make that trait a lang item instead of indexing this array. /// for a known trait, make that trait a lang item instead of indexing this array.
@ -198,7 +250,8 @@ impl AssocItems {
&self, &self,
name: Symbol, name: Symbol,
) -> impl '_ + Iterator<Item = &ty::AssocItem> { ) -> impl '_ + Iterator<Item = &ty::AssocItem> {
self.items.get_by_key(name) assert!(!name.is_empty());
self.items.get_by_key(Some(name))
} }
/// Returns the associated item with the given identifier and `AssocKind`, if one exists. /// Returns the associated item with the given identifier and `AssocKind`, if one exists.
@ -207,27 +260,14 @@ impl AssocItems {
&self, &self,
tcx: TyCtxt<'_>, tcx: TyCtxt<'_>,
ident: Ident, ident: Ident,
kind: AssocKind, assoc_tag: AssocTag,
parent_def_id: DefId, parent_def_id: DefId,
) -> Option<&ty::AssocItem> { ) -> Option<&ty::AssocItem> {
self.filter_by_name_unhygienic(ident.name) self.filter_by_name_unhygienic(ident.name)
.filter(|item| item.kind == kind) .filter(|item| item.as_tag() == assoc_tag)
.find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id)) .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
} }
/// Returns the associated item with the given identifier and any of `AssocKind`, if one
/// exists. The identifier is matched hygienically.
pub fn find_by_ident_and_kinds(
&self,
tcx: TyCtxt<'_>,
ident: Ident,
// Sorted in order of what kinds to look at
kinds: &[AssocKind],
parent_def_id: DefId,
) -> Option<&ty::AssocItem> {
kinds.iter().find_map(|kind| self.find_by_ident_and_kind(tcx, ident, *kind, parent_def_id))
}
/// Returns the associated item with the given identifier in the given `Namespace`, if one /// Returns the associated item with the given identifier in the given `Namespace`, if one
/// exists. The identifier is matched hygienically. /// exists. The identifier is matched hygienically.
pub fn find_by_ident_and_namespace( pub fn find_by_ident_and_namespace(
@ -238,7 +278,7 @@ impl AssocItems {
parent_def_id: DefId, parent_def_id: DefId,
) -> Option<&ty::AssocItem> { ) -> Option<&ty::AssocItem> {
self.filter_by_name_unhygienic(ident.name) self.filter_by_name_unhygienic(ident.name)
.filter(|item| item.kind.namespace() == ns) .filter(|item| item.namespace() == ns)
.find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id)) .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
} }
} }

View file

@ -464,7 +464,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
fn associated_type_def_ids(self, def_id: DefId) -> impl IntoIterator<Item = DefId> { fn associated_type_def_ids(self, def_id: DefId) -> impl IntoIterator<Item = DefId> {
self.associated_items(def_id) self.associated_items(def_id)
.in_definition_order() .in_definition_order()
.filter(|assoc_item| matches!(assoc_item.kind, ty::AssocKind::Type)) .filter(|assoc_item| assoc_item.is_type())
.map(|assoc_item| assoc_item.def_id) .map(|assoc_item| assoc_item.def_id)
} }

View file

@ -746,7 +746,7 @@ impl<'tcx> Instance<'tcx> {
let call_once = tcx let call_once = tcx
.associated_items(fn_once) .associated_items(fn_once)
.in_definition_order() .in_definition_order()
.find(|it| it.kind == ty::AssocKind::Fn) .find(|it| it.is_fn())
.unwrap() .unwrap()
.def_id; .def_id;
let track_caller = let track_caller =

View file

@ -1462,7 +1462,7 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn provided_trait_methods(self, id: DefId) -> impl 'tcx + Iterator<Item = &'tcx AssocItem> { pub fn provided_trait_methods(self, id: DefId) -> impl 'tcx + Iterator<Item = &'tcx AssocItem> {
self.associated_items(id) self.associated_items(id)
.in_definition_order() .in_definition_order()
.filter(move |item| item.kind == AssocKind::Fn && item.defaultness(self).has_value()) .filter(move |item| item.is_fn() && item.defaultness(self).has_value())
} }
pub fn repr_options_of_def(self, did: LocalDefId) -> ReprOptions { pub fn repr_options_of_def(self, did: LocalDefId) -> ReprOptions {
@ -1608,8 +1608,11 @@ impl<'tcx> TyCtxt<'tcx> {
/// return-position `impl Trait` from a trait, then provide the source info /// return-position `impl Trait` from a trait, then provide the source info
/// about where that RPITIT came from. /// about where that RPITIT came from.
pub fn opt_rpitit_info(self, def_id: DefId) -> Option<ImplTraitInTraitData> { pub fn opt_rpitit_info(self, def_id: DefId) -> Option<ImplTraitInTraitData> {
if let DefKind::AssocTy = self.def_kind(def_id) { if let DefKind::AssocTy = self.def_kind(def_id)
self.associated_item(def_id).opt_rpitit_info && let AssocKind::Type { data: AssocTypeData::Rpitit(rpitit_info) } =
self.associated_item(def_id).kind
{
Some(rpitit_info)
} else { } else {
None None
} }

View file

@ -1214,7 +1214,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
&& assoc && assoc
.trait_container(tcx) .trait_container(tcx)
.is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::Coroutine)) .is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::Coroutine))
&& assoc.name == rustc_span::sym::Return && assoc.opt_name() == Some(rustc_span::sym::Return)
{ {
if let ty::Coroutine(_, args) = args.type_at(0).kind() { if let ty::Coroutine(_, args) = args.type_at(0).kind() {
let return_ty = args.as_coroutine().return_ty(); let return_ty = args.as_coroutine().return_ty();
@ -1237,7 +1237,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
p!(", "); p!(", ");
} }
p!(write("{} = ", tcx.associated_item(assoc_item_def_id).name)); p!(write("{} = ", tcx.associated_item(assoc_item_def_id).name()));
match term.unpack() { match term.unpack() {
TermKind::Ty(ty) => p!(print(ty)), TermKind::Ty(ty) => p!(print(ty)),
@ -3291,7 +3291,7 @@ define_print! {
} }
ty::ExistentialProjection<'tcx> { ty::ExistentialProjection<'tcx> {
let name = cx.tcx().associated_item(self.def_id).name; let name = cx.tcx().associated_item(self.def_id).name();
// The args don't contain the self ty (as it has been erased) but the corresp. // The args don't contain the self ty (as it has been erased) but the corresp.
// generics do as the trait always has a self ty param. We need to offset. // generics do as the trait always has a self ty param. We need to offset.
let args = &self.args[cx.tcx().generics_of(self.def_id).parent_count - 1..]; let args = &self.args[cx.tcx().generics_of(self.def_id).parent_count - 1..];

View file

@ -735,7 +735,7 @@ impl<'tcx> Ty<'tcx> {
.map(|principal| { .map(|principal| {
tcx.associated_items(principal.def_id()) tcx.associated_items(principal.def_id())
.in_definition_order() .in_definition_order()
.filter(|item| item.kind == ty::AssocKind::Type) .filter(|item| item.is_type())
.filter(|item| !item.is_impl_trait_in_trait()) .filter(|item| !item.is_impl_trait_in_trait())
.filter(|item| !tcx.generics_require_sized_self(item.def_id)) .filter(|item| !tcx.generics_require_sized_self(item.def_id))
.count() .count()

View file

@ -819,7 +819,7 @@ impl<'tcx> TyCtxt<'tcx> {
/// Get an English description for the item's kind. /// Get an English description for the item's kind.
pub fn def_kind_descr(self, def_kind: DefKind, def_id: DefId) -> &'static str { pub fn def_kind_descr(self, def_kind: DefKind, def_id: DefId) -> &'static str {
match def_kind { match def_kind {
DefKind::AssocFn if self.associated_item(def_id).fn_has_self_parameter => "method", DefKind::AssocFn if self.associated_item(def_id).is_method() => "method",
DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => { DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => {
match coroutine_kind { match coroutine_kind {
hir::CoroutineKind::Desugared( hir::CoroutineKind::Desugared(
@ -873,7 +873,7 @@ impl<'tcx> TyCtxt<'tcx> {
/// Gets an English article for the [`TyCtxt::def_kind_descr`]. /// Gets an English article for the [`TyCtxt::def_kind_descr`].
pub fn def_kind_descr_article(self, def_kind: DefKind, def_id: DefId) -> &'static str { pub fn def_kind_descr_article(self, def_kind: DefKind, def_id: DefId) -> &'static str {
match def_kind { match def_kind {
DefKind::AssocFn if self.associated_item(def_id).fn_has_self_parameter => "a", DefKind::AssocFn if self.associated_item(def_id).is_method() => "a",
DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => { DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => {
match coroutine_kind { match coroutine_kind {
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, ..) => "an", hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, ..) => "an",

View file

@ -740,7 +740,7 @@ fn trait_method<'tcx>(
let item = tcx let item = tcx
.associated_items(trait_def_id) .associated_items(trait_def_id)
.filter_by_name_unhygienic(method_name) .filter_by_name_unhygienic(method_name)
.find(|item| item.kind == ty::AssocKind::Fn) .find(|item| item.is_fn())
.expect("trait method not found"); .expect("trait method not found");
let method_ty = Ty::new_fn_def(tcx, item.def_id, args); let method_ty = Ty::new_fn_def(tcx, item.def_id, args);

View file

@ -42,7 +42,7 @@ impl<'a, 'tcx> UndefinedTransmutesChecker<'a, 'tcx> {
if self.tcx.is_const_fn(def_id) if self.tcx.is_const_fn(def_id)
|| matches!( || matches!(
self.tcx.opt_associated_item(def_id), self.tcx.opt_associated_item(def_id),
Some(AssocItem { kind: AssocKind::Const, .. }) Some(AssocItem { kind: AssocKind::Const { .. }, .. })
) )
{ {
let fn_sig = function.ty(self.body, self.tcx).fn_sig(self.tcx).skip_binder(); let fn_sig = function.ty(self.body, self.tcx).fn_sig(self.tcx).skip_binder();

View file

@ -66,7 +66,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body<
let call_mut = tcx let call_mut = tcx
.associated_items(fn_mut) .associated_items(fn_mut)
.in_definition_order() .in_definition_order()
.find(|it| it.kind == ty::AssocKind::Fn) .find(|it| it.is_fn())
.unwrap() .unwrap()
.def_id; .def_id;

View file

@ -3,7 +3,7 @@ use rustc_data_structures::fx::FxIndexSet;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_middle::mir::visit::Visitor as MirVisitor; use rustc_middle::mir::visit::Visitor as MirVisitor;
use rustc_middle::mir::{self, Location, traversal}; use rustc_middle::mir::{self, Location, traversal};
use rustc_middle::ty::{self, AssocKind, Instance, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{self, AssocTag, Instance, Ty, TyCtxt, TypeFoldable};
use rustc_session::Limit; use rustc_session::Limit;
use rustc_session::lint::builtin::LARGE_ASSIGNMENTS; use rustc_session::lint::builtin::LARGE_ASSIGNMENTS;
use rustc_span::source_map::Spanned; use rustc_span::source_map::Spanned;
@ -194,7 +194,7 @@ fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) ->
if let Some(new) = tcx.associated_items(impl_def_id).find_by_ident_and_kind( if let Some(new) = tcx.associated_items(impl_def_id).find_by_ident_and_kind(
tcx, tcx,
fn_ident, fn_ident,
AssocKind::Fn, AssocTag::Fn,
def_id, def_id,
) { ) {
return Some(new.def_id); return Some(new.def_id);

View file

@ -1994,7 +1994,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
.iter() .iter()
.flat_map(|i| self.r.tcx.associated_items(i).in_definition_order()) .flat_map(|i| self.r.tcx.associated_items(i).in_definition_order())
// Only assoc fn with no receivers. // Only assoc fn with no receivers.
.filter(|item| matches!(item.kind, ty::AssocKind::Fn) && !item.fn_has_self_parameter) .filter(|item| item.is_fn() && !item.is_method())
.filter_map(|item| { .filter_map(|item| {
// Only assoc fns that return `Self` // Only assoc fns that return `Self`
let fn_sig = self.r.tcx.fn_sig(item.def_id).skip_binder(); let fn_sig = self.r.tcx.fn_sig(item.def_id).skip_binder();
@ -2007,8 +2007,9 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
if def.did() != def_id { if def.did() != def_id {
return None; return None;
} }
let order = !item.name.as_str().starts_with("new"); let name = item.name();
Some((order, item.name, input_len)) let order = !name.as_str().starts_with("new");
Some((order, name, input_len))
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
items.sort_by_key(|(order, _, _)| *order); items.sort_by_key(|(order, _, _)| *order);

View file

@ -240,7 +240,7 @@ fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tc
.flat_map(|super_poly_trait_ref| { .flat_map(|super_poly_trait_ref| {
tcx.associated_items(super_poly_trait_ref.def_id()) tcx.associated_items(super_poly_trait_ref.def_id())
.in_definition_order() .in_definition_order()
.filter(|item| item.kind == ty::AssocKind::Type) .filter(|item| item.is_type())
.filter(|item| !tcx.generics_require_sized_self(item.def_id)) .filter(|item| !tcx.generics_require_sized_self(item.def_id))
.map(move |assoc_ty| { .map(move |assoc_ty| {
super_poly_trait_ref.map_bound(|super_trait_ref| { super_poly_trait_ref.map_bound(|super_trait_ref| {
@ -446,7 +446,7 @@ pub(crate) fn transform_instance<'tcx>(
let call = tcx let call = tcx
.associated_items(trait_id) .associated_items(trait_id)
.in_definition_order() .in_definition_order()
.find(|it| it.kind == ty::AssocKind::Fn) .find(|it| it.is_fn())
.expect("No call-family function on closure-like Fn trait?") .expect("No call-family function on closure-like Fn trait?")
.def_id; .def_id;

View file

@ -894,12 +894,21 @@ impl<'tcx> Stable<'tcx> for rustc_session::cstore::ForeignModule {
impl<'tcx> Stable<'tcx> for ty::AssocKind { impl<'tcx> Stable<'tcx> for ty::AssocKind {
type T = stable_mir::ty::AssocKind; type T = stable_mir::ty::AssocKind;
fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
use stable_mir::ty::AssocKind; use stable_mir::ty::{AssocKind, AssocTypeData};
match self { match *self {
ty::AssocKind::Const => AssocKind::Const, ty::AssocKind::Const { name } => AssocKind::Const { name: name.to_string() },
ty::AssocKind::Fn => AssocKind::Fn, ty::AssocKind::Fn { name, has_self } => {
ty::AssocKind::Type => AssocKind::Type, AssocKind::Fn { name: name.to_string(), has_self }
}
ty::AssocKind::Type { data } => AssocKind::Type {
data: match data {
ty::AssocTypeData::Normal(name) => AssocTypeData::Normal(name.to_string()),
ty::AssocTypeData::Rpitit(rpitit) => {
AssocTypeData::Rpitit(rpitit.stable(tables))
}
},
},
} }
} }
} }
@ -922,12 +931,9 @@ impl<'tcx> Stable<'tcx> for ty::AssocItem {
fn stable(&self, tables: &mut Tables<'_>) -> Self::T { fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
stable_mir::ty::AssocItem { stable_mir::ty::AssocItem {
def_id: tables.assoc_def(self.def_id), def_id: tables.assoc_def(self.def_id),
name: self.name.to_string(),
kind: self.kind.stable(tables), kind: self.kind.stable(tables),
container: self.container.stable(tables), container: self.container.stable(tables),
trait_item_def_id: self.trait_item_def_id.map(|did| tables.assoc_def(did)), trait_item_def_id: self.trait_item_def_id.map(|did| tables.assoc_def(did)),
fn_has_self_parameter: self.fn_has_self_parameter,
opt_rpitit_info: self.opt_rpitit_info.map(|rpitit| rpitit.stable(tables)),
} }
} }
} }

View file

@ -22,9 +22,10 @@ impl Display for Ty {
impl Display for AssocKind { impl Display for AssocKind {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self { match self {
AssocKind::Fn => write!(f, "method"), AssocKind::Fn { has_self: true, .. } => write!(f, "method"),
AssocKind::Const => write!(f, "associated const"), AssocKind::Fn { has_self: false, .. } => write!(f, "associated function"),
AssocKind::Type => write!(f, "associated type"), AssocKind::Const { .. } => write!(f, "associated const"),
AssocKind::Type { .. } => write!(f, "associated type"),
} }
} }
} }

View file

@ -1578,29 +1578,28 @@ crate_def! {
#[derive(Clone, Debug, Eq, PartialEq, Serialize)] #[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct AssocItem { pub struct AssocItem {
pub def_id: AssocDef, pub def_id: AssocDef,
pub name: Symbol,
pub kind: AssocKind, pub kind: AssocKind,
pub container: AssocItemContainer, pub container: AssocItemContainer,
/// If this is an item in an impl of a trait then this is the `DefId` of /// If this is an item in an impl of a trait then this is the `DefId` of
/// the associated item on the trait that this implements. /// the associated item on the trait that this implements.
pub trait_item_def_id: Option<AssocDef>, pub trait_item_def_id: Option<AssocDef>,
}
/// Whether this is a method with an explicit self #[derive(Clone, PartialEq, Debug, Eq, Serialize)]
/// as its first parameter, allowing method calls. pub enum AssocTypeData {
pub fn_has_self_parameter: bool, Normal(Symbol),
/// The associated type comes from an RPITIT. It has no name, and the
/// `Some` if the associated item (an associated type) comes from the /// `ImplTraitInTraitData` provides additional information about its
/// return-position `impl Trait` in trait desugaring. The `ImplTraitInTraitData` /// source.
/// provides additional information about its source. Rpitit(ImplTraitInTraitData),
pub opt_rpitit_info: Option<ImplTraitInTraitData>,
} }
#[derive(Clone, Debug, Eq, PartialEq, Serialize)] #[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum AssocKind { pub enum AssocKind {
Const, Const { name: Symbol },
Fn, Fn { name: Symbol, has_self: bool },
Type, Type { data: AssocTypeData },
} }
#[derive(Clone, Debug, Eq, PartialEq, Serialize)] #[derive(Clone, Debug, Eq, PartialEq, Serialize)]
@ -1617,6 +1616,6 @@ pub enum ImplTraitInTraitData {
impl AssocItem { impl AssocItem {
pub fn is_impl_trait_in_trait(&self) -> bool { pub fn is_impl_trait_in_trait(&self) -> bool {
self.opt_rpitit_info.is_some() matches!(self.kind, AssocKind::Type { data: AssocTypeData::Rpitit(_) })
} }
} }

View file

@ -615,7 +615,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
cx.print_def_path(trait_ref.def_id, trait_ref.args)?; cx.print_def_path(trait_ref.def_id, trait_ref.args)?;
} }
ty::ExistentialPredicate::Projection(projection) => { ty::ExistentialPredicate::Projection(projection) => {
let name = cx.tcx.associated_item(projection.def_id).name; let name = cx.tcx.associated_item(projection.def_id).name();
cx.push("p"); cx.push("p");
cx.push_ident(name.as_str()); cx.push_ident(name.as_str());
match projection.term.unpack() { match projection.term.unpack() {

View file

@ -2334,13 +2334,13 @@ impl<'tcx> ObligationCause<'tcx> {
subdiags: Vec<TypeErrorAdditionalDiags>, subdiags: Vec<TypeErrorAdditionalDiags>,
) -> ObligationCauseFailureCode { ) -> ObligationCauseFailureCode {
match self.code() { match self.code() {
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => { ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn { .. }, .. } => {
ObligationCauseFailureCode::MethodCompat { span, subdiags } ObligationCauseFailureCode::MethodCompat { span, subdiags }
} }
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => { ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type { .. }, .. } => {
ObligationCauseFailureCode::TypeCompat { span, subdiags } ObligationCauseFailureCode::TypeCompat { span, subdiags }
} }
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => { ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const { .. }, .. } => {
ObligationCauseFailureCode::ConstCompat { span, subdiags } ObligationCauseFailureCode::ConstCompat { span, subdiags }
} }
ObligationCauseCode::BlockTailExpression(.., hir::MatchSource::TryDesugar(_)) => { ObligationCauseCode::BlockTailExpression(.., hir::MatchSource::TryDesugar(_)) => {
@ -2398,13 +2398,13 @@ impl<'tcx> ObligationCause<'tcx> {
fn as_requirement_str(&self) -> &'static str { fn as_requirement_str(&self) -> &'static str {
match self.code() { match self.code() {
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => { ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn { .. }, .. } => {
"method type is compatible with trait" "method type is compatible with trait"
} }
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => { ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type { .. }, .. } => {
"associated type is compatible with trait" "associated type is compatible with trait"
} }
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => { ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const { .. }, .. } => {
"const is compatible with trait" "const is compatible with trait"
} }
ObligationCauseCode::MainFunctionType => "`main` function has the correct type", ObligationCauseCode::MainFunctionType => "`main` function has the correct type",
@ -2422,9 +2422,13 @@ pub struct ObligationCauseAsDiagArg<'tcx>(pub ObligationCause<'tcx>);
impl IntoDiagArg for ObligationCauseAsDiagArg<'_> { impl IntoDiagArg for ObligationCauseAsDiagArg<'_> {
fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue { fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
let kind = match self.0.code() { let kind = match self.0.code() {
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => "method_compat", ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn { .. }, .. } => {
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => "type_compat", "method_compat"
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => { }
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type { .. }, .. } => {
"type_compat"
}
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const { .. }, .. } => {
"const_compat" "const_compat"
} }
ObligationCauseCode::MainFunctionType => "fn_main_correct_type", ObligationCauseCode::MainFunctionType => "fn_main_correct_type",

View file

@ -98,7 +98,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let assoc_item = self.tcx().associated_item(trait_item_def_id); let assoc_item = self.tcx().associated_item(trait_item_def_id);
let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] }; let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] };
match assoc_item.kind { match assoc_item.kind {
ty::AssocKind::Fn => { ty::AssocKind::Fn { .. } => {
if let Some(hir_id) = if let Some(hir_id) =
assoc_item.def_id.as_local().map(|id| self.tcx().local_def_id_to_hir_id(id)) assoc_item.def_id.as_local().map(|id| self.tcx().local_def_id_to_hir_id(id))
{ {

View file

@ -158,6 +158,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
&& self && self
.tcx() .tcx()
.opt_associated_item(scope_def_id.to_def_id()) .opt_associated_item(scope_def_id.to_def_id())
.is_some_and(|i| i.fn_has_self_parameter) .is_some_and(|i| i.is_method())
} }
} }

View file

@ -782,8 +782,8 @@ fn foo(&self) -> Self::T { String::new() }
let methods: Vec<(Span, String)> = items let methods: Vec<(Span, String)> = items
.in_definition_order() .in_definition_order()
.filter(|item| { .filter(|item| {
ty::AssocKind::Fn == item.kind item.is_fn()
&& Some(item.name) != current_method_ident && Some(item.name()) != current_method_ident
&& !tcx.is_doc_hidden(item.def_id) && !tcx.is_doc_hidden(item.def_id)
}) })
.filter_map(|item| { .filter_map(|item| {

View file

@ -1017,7 +1017,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
infer::BoundRegion(_, br, infer::AssocTypeProjection(def_id)) => format!( infer::BoundRegion(_, br, infer::AssocTypeProjection(def_id)) => format!(
" for lifetime parameter {}in trait containing associated type `{}`", " for lifetime parameter {}in trait containing associated type `{}`",
br_string(br), br_string(br),
self.tcx.associated_item(def_id).name self.tcx.associated_item(def_id).name()
), ),
infer::RegionParameterDefinition(_, name) => { infer::RegionParameterDefinition(_, name) => {
format!(" for lifetime parameter `{name}`") format!(" for lifetime parameter `{name}`")

View file

@ -348,11 +348,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
&& let None = self.tainted_by_errors() && let None = self.tainted_by_errors()
{ {
let (verb, noun) = match self.tcx.associated_item(item_id).kind { let (verb, noun) = match self.tcx.associated_item(item_id).kind {
ty::AssocKind::Const => ("refer to the", "constant"), ty::AssocKind::Const { .. } => ("refer to the", "constant"),
ty::AssocKind::Fn => ("call", "function"), ty::AssocKind::Fn { .. } => ("call", "function"),
// This is already covered by E0223, but this following single match // This is already covered by E0223, but this following single match
// arm doesn't hurt here. // arm doesn't hurt here.
ty::AssocKind::Type => ("refer to the", "type"), ty::AssocKind::Type { .. } => ("refer to the", "type"),
}; };
// Replace the more general E0283 with a more specific error // Replace the more general E0283 with a more specific error

View file

@ -2112,16 +2112,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
trait_ref: DefId, trait_ref: DefId,
) { ) {
if let Some(assoc_item) = self.tcx.opt_associated_item(item_def_id) { if let Some(assoc_item) = self.tcx.opt_associated_item(item_def_id) {
if let ty::AssocKind::Const | ty::AssocKind::Type = assoc_item.kind { if let ty::AssocKind::Const { .. } | ty::AssocKind::Type { .. } = assoc_item.kind {
err.note(format!( err.note(format!(
"{}s cannot be accessed directly on a `trait`, they can only be \ "{}s cannot be accessed directly on a `trait`, they can only be \
accessed through a specific `impl`", accessed through a specific `impl`",
self.tcx.def_kind_descr(assoc_item.kind.as_def_kind(), item_def_id) self.tcx.def_kind_descr(assoc_item.as_def_kind(), item_def_id)
)); ));
err.span_suggestion( err.span_suggestion(
span, span,
"use the fully qualified path to an implementation", "use the fully qualified path to an implementation",
format!("<Type as {}>::{}", self.tcx.def_path_str(trait_ref), assoc_item.name), format!(
"<Type as {}>::{}",
self.tcx.def_path_str(trait_ref),
assoc_item.name()
),
Applicability::HasPlaceholders, Applicability::HasPlaceholders,
); );
} }
@ -5411,7 +5415,7 @@ fn point_at_assoc_type_restriction<G: EmissionGuarantee>(
tcx.associated_items(data.impl_or_alias_def_id).find_by_ident_and_kind( tcx.associated_items(data.impl_or_alias_def_id).find_by_ident_and_kind(
tcx, tcx,
Ident::with_dummy_span(name), Ident::with_dummy_span(name),
ty::AssocKind::Type, ty::AssocTag::Type,
data.impl_or_alias_def_id, data.impl_or_alias_def_id,
) )
{ {

View file

@ -188,7 +188,7 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span
tcx.associated_items(trait_def_id) tcx.associated_items(trait_def_id)
.in_definition_order() .in_definition_order()
// We're only looking at associated type bounds // We're only looking at associated type bounds
.filter(|item| item.kind == ty::AssocKind::Type) .filter(|item| item.is_type())
// Ignore GATs with `Self: Sized` // Ignore GATs with `Self: Sized`
.filter(|item| !tcx.generics_require_sized_self(item.def_id)) .filter(|item| !tcx.generics_require_sized_self(item.def_id))
.flat_map(|item| tcx.explicit_item_bounds(item.def_id).iter_identity_copied()) .flat_map(|item| tcx.explicit_item_bounds(item.def_id).iter_identity_copied())
@ -298,10 +298,11 @@ pub fn dyn_compatibility_violations_for_assoc_item(
match item.kind { match item.kind {
// Associated consts are never dyn-compatible, as they can't have `where` bounds yet at all, // Associated consts are never dyn-compatible, as they can't have `where` bounds yet at all,
// and associated const bounds in trait objects aren't a thing yet either. // and associated const bounds in trait objects aren't a thing yet either.
ty::AssocKind::Const => { ty::AssocKind::Const { name } => {
vec![DynCompatibilityViolation::AssocConst(item.name, item.ident(tcx).span)] vec![DynCompatibilityViolation::AssocConst(name, item.ident(tcx).span)]
} }
ty::AssocKind::Fn => virtual_call_violations_for_method(tcx, trait_def_id, item) ty::AssocKind::Fn { name, .. } => {
virtual_call_violations_for_method(tcx, trait_def_id, item)
.into_iter() .into_iter()
.map(|v| { .map(|v| {
let node = tcx.hir_get_if_local(item.def_id); let node = tcx.hir_get_if_local(item.def_id);
@ -316,13 +317,14 @@ pub fn dyn_compatibility_violations_for_assoc_item(
_ => item.ident(tcx).span, _ => item.ident(tcx).span,
}; };
DynCompatibilityViolation::Method(item.name, v, span) DynCompatibilityViolation::Method(name, v, span)
}) })
.collect(), .collect()
}
// Associated types can only be dyn-compatible if they have `Self: Sized` bounds. // Associated types can only be dyn-compatible if they have `Self: Sized` bounds.
ty::AssocKind::Type => { ty::AssocKind::Type { .. } => {
if !tcx.generics_of(item.def_id).is_own_empty() && !item.is_impl_trait_in_trait() { if !tcx.generics_of(item.def_id).is_own_empty() && !item.is_impl_trait_in_trait() {
vec![DynCompatibilityViolation::GAT(item.name, item.ident(tcx).span)] vec![DynCompatibilityViolation::GAT(item.name(), item.ident(tcx).span)]
} else { } else {
// We will permit associated types if they are explicitly mentioned in the trait object. // We will permit associated types if they are explicitly mentioned in the trait object.
// We can't check this here, as here we only check if it is guaranteed to not be possible. // We can't check this here, as here we only check if it is guaranteed to not be possible.
@ -344,7 +346,7 @@ fn virtual_call_violations_for_method<'tcx>(
let sig = tcx.fn_sig(method.def_id).instantiate_identity(); let sig = tcx.fn_sig(method.def_id).instantiate_identity();
// The method's first parameter must be named `self` // The method's first parameter must be named `self`
if !method.fn_has_self_parameter { if !method.is_method() {
let sugg = if let Some(hir::Node::TraitItem(hir::TraitItem { let sugg = if let Some(hir::Node::TraitItem(hir::TraitItem {
generics, generics,
kind: hir::TraitItemKind::Fn(sig, _), kind: hir::TraitItemKind::Fn(sig, _),

View file

@ -1393,7 +1393,7 @@ fn confirm_future_candidate<'cx, 'tcx>(
coroutine_sig, coroutine_sig,
); );
debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Output); debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name(), sym::Output);
let predicate = ty::ProjectionPredicate { let predicate = ty::ProjectionPredicate {
projection_term: ty::AliasTerm::new_from_args( projection_term: ty::AliasTerm::new_from_args(
@ -1439,7 +1439,7 @@ fn confirm_iterator_candidate<'cx, 'tcx>(
gen_sig, gen_sig,
); );
debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Item); debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name(), sym::Item);
let predicate = ty::ProjectionPredicate { let predicate = ty::ProjectionPredicate {
projection_term: ty::AliasTerm::new_from_args( projection_term: ty::AliasTerm::new_from_args(
@ -1485,7 +1485,7 @@ fn confirm_async_iterator_candidate<'cx, 'tcx>(
gen_sig, gen_sig,
); );
debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Item); debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name(), sym::Item);
let ty::Adt(_poll_adt, args) = *yield_ty.kind() else { let ty::Adt(_poll_adt, args) = *yield_ty.kind() else {
bug!(); bug!();
@ -2005,7 +2005,8 @@ fn confirm_impl_candidate<'cx, 'tcx>(
if !assoc_ty.item.defaultness(tcx).has_value() { if !assoc_ty.item.defaultness(tcx).has_value() {
debug!( debug!(
"confirm_impl_candidate: no associated type {:?} for {:?}", "confirm_impl_candidate: no associated type {:?} for {:?}",
assoc_ty.item.name, obligation.predicate assoc_ty.item.name(),
obligation.predicate
); );
if tcx.impl_self_is_guaranteed_unsized(impl_def_id) { if tcx.impl_self_is_guaranteed_unsized(impl_def_id) {
// We treat this projection as rigid here, which is represented via // We treat this projection as rigid here, which is represented via

View file

@ -594,9 +594,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// Associated types that require `Self: Sized` do not show up in the built-in // Associated types that require `Self: Sized` do not show up in the built-in
// implementation of `Trait for dyn Trait`, and can be dropped here. // implementation of `Trait for dyn Trait`, and can be dropped here.
.filter(|item| !tcx.generics_require_sized_self(item.def_id)) .filter(|item| !tcx.generics_require_sized_self(item.def_id))
.filter_map( .filter_map(|item| if item.is_type() { Some(item.def_id) } else { None })
|item| if item.kind == ty::AssocKind::Type { Some(item.def_id) } else { None },
)
.collect(); .collect();
for assoc_type in assoc_types { for assoc_type in assoc_types {

View file

@ -197,10 +197,8 @@ fn own_existential_vtable_entries_iter(
tcx: TyCtxt<'_>, tcx: TyCtxt<'_>,
trait_def_id: DefId, trait_def_id: DefId,
) -> impl Iterator<Item = DefId> { ) -> impl Iterator<Item = DefId> {
let trait_methods = tcx let trait_methods =
.associated_items(trait_def_id) tcx.associated_items(trait_def_id).in_definition_order().filter(|item| item.is_fn());
.in_definition_order()
.filter(|item| item.kind == ty::AssocKind::Fn);
// Now list each method's DefId (for within its trait). // Now list each method's DefId (for within its trait).
let own_entries = trait_methods.filter_map(move |&trait_method| { let own_entries = trait_methods.filter_map(move |&trait_method| {

View file

@ -6,7 +6,6 @@ use rustc_hir::{self as hir, AmbigArg};
use rustc_middle::query::Providers; use rustc_middle::query::Providers;
use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt}; use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt};
use rustc_middle::{bug, span_bug}; use rustc_middle::{bug, span_bug};
use rustc_span::kw;
pub(crate) fn provide(providers: &mut Providers) { pub(crate) fn provide(providers: &mut Providers) {
*providers = Providers { *providers = Providers {
@ -129,39 +128,35 @@ fn associated_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AssocItem {
fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty::AssocItem { fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty::AssocItem {
let owner_id = trait_item_ref.id.owner_id; let owner_id = trait_item_ref.id.owner_id;
let (kind, has_self) = match trait_item_ref.kind { let name = trait_item_ref.ident.name;
hir::AssocItemKind::Const => (ty::AssocKind::Const, false), let kind = match trait_item_ref.kind {
hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self), hir::AssocItemKind::Const => ty::AssocKind::Const { name },
hir::AssocItemKind::Type => (ty::AssocKind::Type, false), hir::AssocItemKind::Fn { has_self } => ty::AssocKind::Fn { name, has_self },
hir::AssocItemKind::Type => ty::AssocKind::Type { data: ty::AssocTypeData::Normal(name) },
}; };
ty::AssocItem { ty::AssocItem {
name: trait_item_ref.ident.name,
kind, kind,
def_id: owner_id.to_def_id(), def_id: owner_id.to_def_id(),
trait_item_def_id: Some(owner_id.to_def_id()), trait_item_def_id: Some(owner_id.to_def_id()),
container: ty::AssocItemContainer::Trait, container: ty::AssocItemContainer::Trait,
fn_has_self_parameter: has_self,
opt_rpitit_info: None,
} }
} }
fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::AssocItem { fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::AssocItem {
let def_id = impl_item_ref.id.owner_id; let def_id = impl_item_ref.id.owner_id;
let (kind, has_self) = match impl_item_ref.kind { let name = impl_item_ref.ident.name;
hir::AssocItemKind::Const => (ty::AssocKind::Const, false), let kind = match impl_item_ref.kind {
hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self), hir::AssocItemKind::Const => ty::AssocKind::Const { name },
hir::AssocItemKind::Type => (ty::AssocKind::Type, false), hir::AssocItemKind::Fn { has_self } => ty::AssocKind::Fn { name, has_self },
hir::AssocItemKind::Type => ty::AssocKind::Type { data: ty::AssocTypeData::Normal(name) },
}; };
ty::AssocItem { ty::AssocItem {
name: impl_item_ref.ident.name,
kind, kind,
def_id: def_id.to_def_id(), def_id: def_id.to_def_id(),
trait_item_def_id: impl_item_ref.trait_item_def_id, trait_item_def_id: impl_item_ref.trait_item_def_id,
container: ty::AssocItemContainer::Impl, container: ty::AssocItemContainer::Impl,
fn_has_self_parameter: has_self,
opt_rpitit_info: None,
} }
} }
@ -264,16 +259,15 @@ fn associated_type_for_impl_trait_in_trait(
trait_assoc_ty.def_ident_span(Some(span)); trait_assoc_ty.def_ident_span(Some(span));
trait_assoc_ty.associated_item(ty::AssocItem { trait_assoc_ty.associated_item(ty::AssocItem {
name: kw::Empty, kind: ty::AssocKind::Type {
kind: ty::AssocKind::Type, data: ty::AssocTypeData::Rpitit(ImplTraitInTraitData::Trait {
def_id,
trait_item_def_id: None,
container: ty::AssocItemContainer::Trait,
fn_has_self_parameter: false,
opt_rpitit_info: Some(ImplTraitInTraitData::Trait {
fn_def_id: fn_def_id.to_def_id(), fn_def_id: fn_def_id.to_def_id(),
opaque_def_id: opaque_ty_def_id.to_def_id(), opaque_def_id: opaque_ty_def_id.to_def_id(),
}), }),
},
def_id,
trait_item_def_id: None,
container: ty::AssocItemContainer::Trait,
}); });
// Copy visility of the containing function. // Copy visility of the containing function.
@ -317,13 +311,14 @@ fn associated_type_for_impl_trait_in_impl(
impl_assoc_ty.def_ident_span(Some(span)); impl_assoc_ty.def_ident_span(Some(span));
impl_assoc_ty.associated_item(ty::AssocItem { impl_assoc_ty.associated_item(ty::AssocItem {
name: kw::Empty, kind: ty::AssocKind::Type {
kind: ty::AssocKind::Type, data: ty::AssocTypeData::Rpitit(ImplTraitInTraitData::Impl {
fn_def_id: impl_fn_def_id.to_def_id(),
}),
},
def_id, def_id,
trait_item_def_id: Some(trait_assoc_def_id), trait_item_def_id: Some(trait_assoc_def_id),
container: ty::AssocItemContainer::Impl, container: ty::AssocItemContainer::Impl,
fn_has_self_parameter: false,
opt_rpitit_info: Some(ImplTraitInTraitData::Impl { fn_def_id: impl_fn_def_id.to_def_id() }),
}); });
// Copy visility of the containing function. // Copy visility of the containing function.

View file

@ -490,17 +490,17 @@ pub(crate) fn build_impl(
return true; return true;
} }
if let Some(associated_trait) = associated_trait { if let Some(associated_trait) = associated_trait {
let assoc_kind = match item.kind { let assoc_tag = match item.kind {
hir::ImplItemKind::Const(..) => ty::AssocKind::Const, hir::ImplItemKind::Const(..) => ty::AssocTag::Const,
hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn, hir::ImplItemKind::Fn(..) => ty::AssocTag::Fn,
hir::ImplItemKind::Type(..) => ty::AssocKind::Type, hir::ImplItemKind::Type(..) => ty::AssocTag::Type,
}; };
let trait_item = tcx let trait_item = tcx
.associated_items(associated_trait.def_id) .associated_items(associated_trait.def_id)
.find_by_ident_and_kind( .find_by_ident_and_kind(
tcx, tcx,
item.ident, item.ident,
assoc_kind, assoc_tag,
associated_trait.def_id, associated_trait.def_id,
) )
.unwrap(); // SAFETY: For all impl items there exists trait item that has the same name. .unwrap(); // SAFETY: For all impl items there exists trait item that has the same name.
@ -527,7 +527,7 @@ pub(crate) fn build_impl(
.find_by_ident_and_kind( .find_by_ident_and_kind(
tcx, tcx,
item.ident(tcx), item.ident(tcx),
item.kind, item.as_tag(),
associated_trait.def_id, associated_trait.def_id,
) )
.unwrap(); // corresponding associated item has to exist .unwrap(); // corresponding associated item has to exist

View file

@ -521,7 +521,7 @@ fn projection_to_path_segment<'tcx>(
let item = cx.tcx.associated_item(def_id); let item = cx.tcx.associated_item(def_id);
let generics = cx.tcx.generics_of(def_id); let generics = cx.tcx.generics_of(def_id);
PathSegment { PathSegment {
name: item.name, name: item.name(),
args: GenericArgs::AngleBracketed { args: GenericArgs::AngleBracketed {
args: clean_middle_generic_args( args: clean_middle_generic_args(
cx, cx,
@ -1340,7 +1340,7 @@ pub(crate) fn clean_impl_item<'tcx>(
pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocContext<'_>) -> Item { pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocContext<'_>) -> Item {
let tcx = cx.tcx; let tcx = cx.tcx;
let kind = match assoc_item.kind { let kind = match assoc_item.kind {
ty::AssocKind::Const => { ty::AssocKind::Const { .. } => {
let ty = clean_middle_ty( let ty = clean_middle_ty(
ty::Binder::dummy(tcx.type_of(assoc_item.def_id).instantiate_identity()), ty::Binder::dummy(tcx.type_of(assoc_item.def_id).instantiate_identity()),
cx, cx,
@ -1374,10 +1374,10 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
} }
} }
} }
ty::AssocKind::Fn => { ty::AssocKind::Fn { has_self, .. } => {
let mut item = inline::build_function(cx, assoc_item.def_id); let mut item = inline::build_function(cx, assoc_item.def_id);
if assoc_item.fn_has_self_parameter { if has_self {
let self_ty = match assoc_item.container { let self_ty = match assoc_item.container {
ty::AssocItemContainer::Impl => { ty::AssocItemContainer::Impl => {
tcx.type_of(assoc_item.container_id(tcx)).instantiate_identity() tcx.type_of(assoc_item.container_id(tcx)).instantiate_identity()
@ -1412,8 +1412,8 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
RequiredMethodItem(item) RequiredMethodItem(item)
} }
} }
ty::AssocKind::Type => { ty::AssocKind::Type { .. } => {
let my_name = assoc_item.name; let my_name = assoc_item.name();
fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool { fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
match (&param.kind, arg) { match (&param.kind, arg) {
@ -1554,7 +1554,7 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
} }
}; };
Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name), kind, cx) Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name()), kind, cx)
} }
fn first_non_private_clean_path<'tcx>( fn first_non_private_clean_path<'tcx>(
@ -2223,7 +2223,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
Type::QPath(Box::new(QPathData { Type::QPath(Box::new(QPathData {
assoc: PathSegment { assoc: PathSegment {
name: cx.tcx.associated_item(def_id).name, name: cx.tcx.associated_item(def_id).name(),
args: GenericArgs::AngleBracketed { args: GenericArgs::AngleBracketed {
args: clean_middle_generic_args( args: clean_middle_generic_args(
cx, cx,

View file

@ -2504,7 +2504,7 @@ impl Impl {
self.trait_ self.trait_
.as_ref() .as_ref()
.map(|t| t.def_id()) .map(|t| t.def_id())
.map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name).collect()) .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name()).collect())
.unwrap_or_default() .unwrap_or_default()
} }

View file

@ -60,7 +60,7 @@ fn filter_assoc_items_by_name_and_namespace(
ns: Namespace, ns: Namespace,
) -> impl Iterator<Item = &ty::AssocItem> { ) -> impl Iterator<Item = &ty::AssocItem> {
tcx.associated_items(assoc_items_of).filter_by_name_unhygienic(ident.name).filter(move |item| { tcx.associated_items(assoc_items_of).filter_by_name_unhygienic(ident.name).filter(move |item| {
item.kind.namespace() == ns && tcx.hygienic_eq(ident, item.ident(tcx), assoc_items_of) item.namespace() == ns && tcx.hygienic_eq(ident, item.ident(tcx), assoc_items_of)
}) })
} }
@ -743,7 +743,7 @@ impl<'tcx> LinkCollector<'_, 'tcx> {
ns, ns,
) )
.map(|item| { .map(|item| {
let res = Res::Def(item.kind.as_def_kind(), item.def_id); let res = Res::Def(item.as_def_kind(), item.def_id);
(res, item.def_id) (res, item.def_id)
}) })
.collect::<Vec<_>>(), .collect::<Vec<_>>(),

View file

@ -111,8 +111,8 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones {
// Only suggest if `clone_from`/`clone_into` is explicitly implemented // Only suggest if `clone_from`/`clone_into` is explicitly implemented
&& resolved_assoc_items.in_definition_order().any(|assoc| && resolved_assoc_items.in_definition_order().any(|assoc|
match which_trait { match which_trait {
CloneTrait::Clone => assoc.name == sym::clone_from, CloneTrait::Clone => assoc.name() == sym::clone_from,
CloneTrait::ToOwned => assoc.name.as_str() == "clone_into", CloneTrait::ToOwned => assoc.name().as_str() == "clone_into",
} }
) )
&& !clone_source_borrows_from_dest(cx, lhs, rhs.span) && !clone_source_borrows_from_dest(cx, lhs, rhs.span)

View file

@ -56,7 +56,7 @@ fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -
cx.tcx.associated_items(trait_id).find_by_ident_and_kind( cx.tcx.associated_items(trait_id).find_by_ident_and_kind(
cx.tcx, cx.tcx,
Ident::from_str("Output"), Ident::from_str("Output"),
ty::AssocKind::Type, ty::AssocTag::Type,
trait_id, trait_id,
) )
}) })

View file

@ -550,7 +550,7 @@ impl<'tcx> FormatArgsExpr<'_, 'tcx> {
// a `Target` that is in `self.ty_msrv_map`. // a `Target` that is in `self.ty_msrv_map`.
if let Some(deref_trait_id) = self.cx.tcx.lang_items().deref_trait() if let Some(deref_trait_id) = self.cx.tcx.lang_items().deref_trait()
&& implements_trait(self.cx, ty, deref_trait_id, &[]) && implements_trait(self.cx, ty, deref_trait_id, &[])
&& let Some(target_ty) = self.cx.get_associated_type(ty, deref_trait_id, "Target") && let Some(target_ty) = self.cx.get_associated_type(ty, deref_trait_id, sym::Target)
&& let Some(msrv) = self.ty_msrv_map.get(&target_ty) && let Some(msrv) = self.ty_msrv_map.get(&target_ty)
&& msrv.is_none_or(|msrv| self.msrv.meets(self.cx, msrv)) && msrv.is_none_or(|msrv| self.msrv.meets(self.cx, msrv))
{ {

View file

@ -315,7 +315,7 @@ fn check<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds<'tcx>) {
assocs assocs
.filter_by_name_unhygienic(constraint.ident.name) .filter_by_name_unhygienic(constraint.ident.name)
.next() .next()
.is_some_and(|assoc| assoc.kind == ty::AssocKind::Type) .is_some_and(|assoc| assoc.is_type())
}) })
{ {
emit_lint(cx, poly_trait, bounds, index, implied_constraints, bound); emit_lint(cx, poly_trait, bounds, index, implied_constraints, bound);

View file

@ -13,7 +13,7 @@ use rustc_hir::{
QPath, TraitItemRef, TyKind, QPath, TraitItemRef, TyKind,
}; };
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, AssocKind, FnSig, Ty}; use rustc_middle::ty::{self, FnSig, Ty};
use rustc_session::declare_lint_pass; use rustc_session::declare_lint_pass;
use rustc_span::source_map::Spanned; use rustc_span::source_map::Spanned;
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
@ -288,8 +288,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, ident: Iden
.items() .items()
.flat_map(|&i| cx.tcx.associated_items(i).filter_by_name_unhygienic(is_empty)) .flat_map(|&i| cx.tcx.associated_items(i).filter_by_name_unhygienic(is_empty))
.any(|i| { .any(|i| {
i.kind == AssocKind::Fn i.is_method()
&& i.fn_has_self_parameter
&& cx.tcx.fn_sig(i.def_id).skip_binder().inputs().skip_binder().len() == 1 && cx.tcx.fn_sig(i.def_id).skip_binder().inputs().skip_binder().len() == 1
}); });
@ -466,7 +465,7 @@ fn check_for_is_empty(
.inherent_impls(impl_ty) .inherent_impls(impl_ty)
.iter() .iter()
.flat_map(|&id| cx.tcx.associated_items(id).filter_by_name_unhygienic(is_empty)) .flat_map(|&id| cx.tcx.associated_items(id).filter_by_name_unhygienic(is_empty))
.find(|item| item.kind == AssocKind::Fn); .find(|item| item.is_fn());
let (msg, is_empty_span, self_kind) = match is_empty { let (msg, is_empty_span, self_kind) = match is_empty {
None => ( None => (
@ -486,7 +485,7 @@ fn check_for_is_empty(
None, None,
), ),
Some(is_empty) Some(is_empty)
if !(is_empty.fn_has_self_parameter if !(is_empty.is_method()
&& check_is_empty_sig( && check_is_empty_sig(
cx, cx,
cx.tcx.fn_sig(is_empty.def_id).instantiate_identity().skip_binder(), cx.tcx.fn_sig(is_empty.def_id).instantiate_identity().skip_binder(),
@ -608,7 +607,7 @@ fn is_empty_array(expr: &Expr<'_>) -> bool {
fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
/// Gets an `AssocItem` and return true if it matches `is_empty(self)`. /// Gets an `AssocItem` and return true if it matches `is_empty(self)`.
fn is_is_empty(cx: &LateContext<'_>, item: &ty::AssocItem) -> bool { fn is_is_empty(cx: &LateContext<'_>, item: &ty::AssocItem) -> bool {
if item.kind == AssocKind::Fn { if item.is_fn() {
let sig = cx.tcx.fn_sig(item.def_id).skip_binder(); let sig = cx.tcx.fn_sig(item.def_id).skip_binder();
let ty = sig.skip_binder(); let ty = sig.skip_binder();
ty.inputs().len() == 1 ty.inputs().len() == 1
@ -644,7 +643,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
&& cx.tcx.get_diagnostic_item(sym::Deref).is_some_and(|deref_id| { && cx.tcx.get_diagnostic_item(sym::Deref).is_some_and(|deref_id| {
implements_trait(cx, ty, deref_id, &[]) implements_trait(cx, ty, deref_id, &[])
&& cx && cx
.get_associated_type(ty, deref_id, "Target") .get_associated_type(ty, deref_id, sym::Target)
.is_some_and(|deref_ty| ty_has_is_empty(cx, deref_ty, depth + 1)) .is_some_and(|deref_ty| ty_has_is_empty(cx, deref_ty, depth + 1))
})) }))
}, },

View file

@ -24,7 +24,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, self_expr: &'_ Exp
&& let Ok(Some(fn_def)) = Instance::try_resolve(cx.tcx, cx.typing_env(), id, args) && let Ok(Some(fn_def)) = Instance::try_resolve(cx.tcx, cx.typing_env(), id, args)
// find the provided definition of Iterator::last // find the provided definition of Iterator::last
&& let Some(item) = cx.tcx.get_diagnostic_item(sym::Iterator) && let Some(item) = cx.tcx.get_diagnostic_item(sym::Iterator)
&& let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name.as_str() == "last") && let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name().as_str() == "last")
// if the resolved method is the same as the provided definition // if the resolved method is the same as the provided definition
&& fn_def.def_id() == last_def.def_id && fn_def.def_id() == last_def.def_id
{ {

View file

@ -48,7 +48,7 @@ pub(super) fn check<'tcx>(
&& let Some(method_id) = typeck.type_dependent_def_id(cloned_call.hir_id) && let Some(method_id) = typeck.type_dependent_def_id(cloned_call.hir_id)
&& cx.tcx.trait_of_item(method_id) == Some(iter_id) && cx.tcx.trait_of_item(method_id) == Some(iter_id)
&& let cloned_recv_ty = typeck.expr_ty_adjusted(cloned_recv) && let cloned_recv_ty = typeck.expr_ty_adjusted(cloned_recv)
&& let Some(iter_assoc_ty) = cx.get_associated_type(cloned_recv_ty, iter_id, "Item") && let Some(iter_assoc_ty) = cx.get_associated_type(cloned_recv_ty, iter_id, sym::Item)
&& matches!(*iter_assoc_ty.kind(), ty::Ref(_, ty, _) if !is_copy(cx, ty)) && matches!(*iter_assoc_ty.kind(), ty::Ref(_, ty, _) if !is_copy(cx, ty))
{ {
if needs_into_iter if needs_into_iter

View file

@ -17,7 +17,7 @@ use rustc_hir::{
}; };
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::hir::nested_filter; use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{self, AssocKind, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, Ty}; use rustc_middle::ty::{self, AssocTag, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, Ty};
use rustc_span::symbol::Ident; use rustc_span::symbol::Ident;
use rustc_span::{Span, sym}; use rustc_span::{Span, sym};
@ -241,7 +241,7 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) -
&& let Some(iter_item) = cx.tcx.associated_items(iter_trait).find_by_ident_and_kind( && let Some(iter_item) = cx.tcx.associated_items(iter_trait).find_by_ident_and_kind(
cx.tcx, cx.tcx,
Ident::with_dummy_span(sym::Item), Ident::with_dummy_span(sym::Item),
AssocKind::Type, AssocTag::Type,
iter_trait, iter_trait,
) )
&& let args = cx.tcx.mk_args(&[GenericArg::from(typeck.expr_ty_adjusted(iter_expr))]) && let args = cx.tcx.mk_args(&[GenericArg::from(typeck.expr_ty_adjusted(iter_expr))])

View file

@ -78,7 +78,7 @@ pub(super) fn check<'tcx>(
.iter() .iter()
.flat_map(|impl_id| cx.tcx.associated_items(impl_id).filter_by_name_unhygienic(sugg)) .flat_map(|impl_id| cx.tcx.associated_items(impl_id).filter_by_name_unhygienic(sugg))
.find_map(|assoc| { .find_map(|assoc| {
if assoc.fn_has_self_parameter if assoc.is_method()
&& cx.tcx.fn_sig(assoc.def_id).skip_binder().inputs().skip_binder().len() == 1 && cx.tcx.fn_sig(assoc.def_id).skip_binder().inputs().skip_binder().len() == 1
{ {
Some(assoc.def_id) Some(assoc.def_id)

View file

@ -99,7 +99,7 @@ pub fn check_for_loop_iter(
&& let Some(into_iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator) && let Some(into_iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator)
&& let collection_ty = cx.typeck_results().expr_ty(collection) && let collection_ty = cx.typeck_results().expr_ty(collection)
&& implements_trait(cx, collection_ty, into_iterator_trait_id, &[]) && implements_trait(cx, collection_ty, into_iterator_trait_id, &[])
&& let Some(into_iter_item_ty) = cx.get_associated_type(collection_ty, into_iterator_trait_id, "Item") && let Some(into_iter_item_ty) = cx.get_associated_type(collection_ty, into_iterator_trait_id, sym::Item)
&& iter_item_ty == into_iter_item_ty && iter_item_ty == into_iter_item_ty
&& let Some(collection_snippet) = collection.span.get_source_text(cx) && let Some(collection_snippet) = collection.span.get_source_text(cx)
{ {

View file

@ -153,7 +153,7 @@ fn check_addr_of_expr(
} }
if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref) if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref)
&& implements_trait(cx, receiver_ty, deref_trait_id, &[]) && implements_trait(cx, receiver_ty, deref_trait_id, &[])
&& cx.get_associated_type(receiver_ty, deref_trait_id, "Target") == Some(target_ty) && cx.get_associated_type(receiver_ty, deref_trait_id, sym::Target) == Some(target_ty)
// Make sure that it's actually calling the right `.to_string()`, (#10033) // Make sure that it's actually calling the right `.to_string()`, (#10033)
// *or* this is a `Cow::into_owned()` call (which would be the wrong into_owned receiver (str != Cow) // *or* this is a `Cow::into_owned()` call (which would be the wrong into_owned receiver (str != Cow)
// but that's ok for Cow::into_owned specifically) // but that's ok for Cow::into_owned specifically)
@ -322,7 +322,7 @@ fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symb
// add `.as_ref()` to the suggestion. // add `.as_ref()` to the suggestion.
let as_ref = if is_type_lang_item(cx, cx.typeck_results().expr_ty(expr), LangItem::String) let as_ref = if is_type_lang_item(cx, cx.typeck_results().expr_ty(expr), LangItem::String)
&& let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref) && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref)
&& cx.get_associated_type(cx.typeck_results().expr_ty(receiver), deref_trait_id, "Target") && cx.get_associated_type(cx.typeck_results().expr_ty(receiver), deref_trait_id, sym::Target)
!= Some(cx.tcx.types.str_) != Some(cx.tcx.types.str_)
{ {
".as_ref()" ".as_ref()"
@ -648,7 +648,7 @@ fn is_to_string_on_string_like<'a>(
&& let GenericArgKind::Type(ty) = generic_arg.unpack() && let GenericArgKind::Type(ty) = generic_arg.unpack()
&& let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref) && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref)
&& let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef) && let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef)
&& (cx.get_associated_type(ty, deref_trait_id, "Target") == Some(cx.tcx.types.str_) && (cx.get_associated_type(ty, deref_trait_id, sym::Target) == Some(cx.tcx.types.str_)
|| implements_trait(cx, ty, as_ref_trait_id, &[cx.tcx.types.str_.into()])) || implements_trait(cx, ty, as_ref_trait_id, &[cx.tcx.types.str_.into()]))
{ {
true true

View file

@ -81,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods {
cx, cx,
MISSING_TRAIT_METHODS, MISSING_TRAIT_METHODS,
cx.tcx.def_span(item.owner_id), cx.tcx.def_span(item.owner_id),
format!("missing trait method provided by default: `{}`", assoc.name), format!("missing trait method provided by default: `{}`", assoc.name()),
|diag| { |diag| {
diag.span_help(cx.tcx.def_span(assoc.def_id), "implement the method"); diag.span_help(cx.tcx.def_span(assoc.def_id), "implement the method");
}, },

View file

@ -299,7 +299,7 @@ fn has_ref_mut_self_method(cx: &LateContext<'_>, trait_def_id: DefId) -> bool {
.associated_items(trait_def_id) .associated_items(trait_def_id)
.in_definition_order() .in_definition_order()
.any(|assoc_item| { .any(|assoc_item| {
if assoc_item.fn_has_self_parameter { if assoc_item.is_method() {
let self_ty = cx let self_ty = cx
.tcx .tcx
.fn_sig(assoc_item.def_id) .fn_sig(assoc_item.def_id)

View file

@ -3,7 +3,6 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
use rustc_hir::{HirId, Impl, ItemKind, Node, Path, QPath, TraitRef, TyKind}; use rustc_hir::{HirId, Impl, ItemKind, Node, Path, QPath, TraitRef, TyKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::AssocKind;
use rustc_session::declare_lint_pass; use rustc_session::declare_lint_pass;
use rustc_span::Span; use rustc_span::Span;
use rustc_span::symbol::Symbol; use rustc_span::symbol::Symbol;
@ -85,8 +84,8 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
cx.tcx cx.tcx
.associated_items(did) .associated_items(did)
.in_definition_order() .in_definition_order()
.filter(|assoc_item| matches!(assoc_item.kind, AssocKind::Fn)) .filter(|assoc_item| assoc_item.is_fn())
.map(|assoc_item| assoc_item.name) .map(|assoc_item| assoc_item.name())
.collect() .collect()
} else { } else {
BTreeSet::new() BTreeSet::new()

View file

@ -10,7 +10,7 @@ use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, Item, ItemKind, Node, QPath
use rustc_hir_analysis::lower_ty; use rustc_hir_analysis::lower_ty;
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter; use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{self, AssocKind, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::symbol::{Ident, kw}; use rustc_span::symbol::{Ident, kw};
use rustc_span::{Span, sym}; use rustc_span::{Span, sym};
@ -322,7 +322,7 @@ impl UnconditionalRecursion {
.in_definition_order() .in_definition_order()
// We're not interested in foreign implementations of the `Default` trait. // We're not interested in foreign implementations of the `Default` trait.
.find(|item| { .find(|item| {
item.kind == AssocKind::Fn && item.def_id.is_local() && item.name == kw::Default item.is_fn() && item.def_id.is_local() && item.name() == kw::Default
}) })
&& let Some(body_node) = cx.tcx.hir_get_if_local(assoc_item.def_id) && let Some(body_node) = cx.tcx.hir_get_if_local(assoc_item.def_id)
&& let Some(body_id) = body_node.body_id() && let Some(body_id) = body_node.body_id()

View file

@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf {
.is_some() .is_some()
}; };
if let ItemKind::Impl(Impl { of_trait: None, .. }) = parent_item.kind if let ItemKind::Impl(Impl { of_trait: None, .. }) = parent_item.kind
&& assoc_item.fn_has_self_parameter && assoc_item.is_method()
&& let ImplItemKind::Fn(.., body_id) = &impl_item.kind && let ImplItemKind::Fn(.., body_id) = &impl_item.kind
&& (!cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) || !self.avoid_breaking_exported_api) && (!cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) || !self.avoid_breaking_exported_api)
&& let body = cx.tcx.hir_body(*body_id) && let body = cx.tcx.hir_body(*body_id)

View file

@ -19,7 +19,7 @@ use rustc_middle::mir::interpret::Scalar;
use rustc_middle::traits::EvaluationResult; use rustc_middle::traits::EvaluationResult;
use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::layout::ValidityRequirement;
use rustc_middle::ty::{ use rustc_middle::ty::{
self, AdtDef, AliasTy, AssocItem, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, self, AdtDef, AliasTy, AssocItem, AssocTag, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind,
GenericArgsRef, GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, GenericArgsRef, GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable,
TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr,
}; };
@ -156,7 +156,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'
pub fn get_iterator_item_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> { pub fn get_iterator_item_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
cx.tcx cx.tcx
.get_diagnostic_item(sym::Iterator) .get_diagnostic_item(sym::Iterator)
.and_then(|iter_did| cx.get_associated_type(ty, iter_did, "Item")) .and_then(|iter_did| cx.get_associated_type(ty, iter_did, sym::Item))
} }
/// Get the diagnostic name of a type, e.g. `sym::HashMap`. To check if a type /// Get the diagnostic name of a type, e.g. `sym::HashMap`. To check if a type
@ -1112,7 +1112,7 @@ pub fn make_projection<'tcx>(
let Some(assoc_item) = tcx.associated_items(container_id).find_by_ident_and_kind( let Some(assoc_item) = tcx.associated_items(container_id).find_by_ident_and_kind(
tcx, tcx,
Ident::with_dummy_span(assoc_ty), Ident::with_dummy_span(assoc_ty),
AssocKind::Type, AssocTag::Type,
container_id, container_id,
) else { ) else {
debug_assert!(false, "type `{assoc_ty}` not found in `{container_id:?}`"); debug_assert!(false, "type `{assoc_ty}` not found in `{container_id:?}`");
@ -1345,7 +1345,7 @@ pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_n
.associated_items(did) .associated_items(did)
.filter_by_name_unhygienic(method_name) .filter_by_name_unhygienic(method_name)
.next() .next()
.filter(|item| item.kind == AssocKind::Fn) .filter(|item| item.as_tag() == AssocTag::Fn)
}) })
} else { } else {
None None

View file

@ -57,14 +57,14 @@ note: required for `Fooy<T>` to implement `Copy`
| |
LL | #[derive(Copy, Clone)] LL | #[derive(Copy, Clone)]
| ^^^^ unsatisfied trait bound introduced in this `derive` macro | ^^^^ unsatisfied trait bound introduced in this `derive` macro
note: the requirement `Fooy<T>: Copy` appears on the `impl`'s method `d` but not on the corresponding trait's method note: the requirement `Fooy<T>: Copy` appears on the `impl`'s associated function `d` but not on the corresponding trait's associated function
--> $DIR/impl_bounds.rs:7:8 --> $DIR/impl_bounds.rs:7:8
| |
LL | trait Foo { LL | trait Foo {
| --- in this trait | --- in this trait
... ...
LL | fn d() where Self: Clone; LL | fn d() where Self: Clone;
| ^ this trait's method doesn't have the requirement `Fooy<T>: Copy` | ^ this trait's associated function doesn't have the requirement `Fooy<T>: Copy`
help: consider restricting type parameter `T` with trait `Copy` help: consider restricting type parameter `T` with trait `Copy`
| |
LL | impl<T: std::marker::Copy> Foo for Fooy<T> { LL | impl<T: std::marker::Copy> Foo for Fooy<T> {

View file

@ -4,14 +4,14 @@ error[E0275]: overflow evaluating the requirement `<() as A<T>>::Assoc: A<T>`
LL | Self::Assoc: A<T>, LL | Self::Assoc: A<T>,
| ^^^^ | ^^^^
| |
note: the requirement `<() as A<T>>::Assoc: A<T>` appears on the `impl`'s method `f` but not on the corresponding trait's method note: the requirement `<() as A<T>>::Assoc: A<T>` appears on the `impl`'s associated function `f` but not on the corresponding trait's associated function
--> $DIR/normalize-param-env-2.rs:12:8 --> $DIR/normalize-param-env-2.rs:12:8
| |
LL | trait A<T> { LL | trait A<T> {
| - in this trait | - in this trait
... ...
LL | fn f() LL | fn f()
| ^ this trait's method doesn't have the requirement `<() as A<T>>::Assoc: A<T>` | ^ this trait's associated function doesn't have the requirement `<() as A<T>>::Assoc: A<T>`
error[E0275]: overflow evaluating the requirement `<() as A<T>>::Assoc: A<T>` error[E0275]: overflow evaluating the requirement `<() as A<T>>::Assoc: A<T>`
--> $DIR/normalize-param-env-2.rs:24:22 --> $DIR/normalize-param-env-2.rs:24:22