1
Fork 0

Move has_self field to hir::AssocKind::Fn.

`hir::AssocItem` currently has a boolean `fn_has_self_parameter` field,
which is misplaced, because it's only relevant for associated fns, not
for associated consts or types. This commit moves it (and renames it) to
the `AssocKind::Fn` variant, where it belongs.

This requires introducing a new C-style enum, `AssocTag`, which is like
`AssocKind` but without the fields. This is because `AssocKind` values
are passed to various functions like `find_by_ident_and_kind` to
indicate what kind of associated item should be searched for, and having
to specify `has_self` isn't relevant there.

New methods:
- Predicates `AssocItem::is_fn` and `AssocItem::is_method`.
- `AssocItem::as_tag` which converts `AssocItem::kind` to `AssocTag`.

Removed `find_by_name_and_kinds`, which is unused.

`AssocItem::descr` can now distinguish between methods and associated
functions, which slightly improves some error messages.
This commit is contained in:
Nicholas Nethercote 2025-04-11 06:28:59 +10:00
parent abce592029
commit ce2aa97cd6
60 changed files with 288 additions and 284 deletions

View file

@ -443,7 +443,7 @@ fn best_definition_site_of_opaque<'tcx>(
let impl_def_id = tcx.local_parent(parent);
for assoc in tcx.associated_items(impl_def_id).in_definition_order() {
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())
{
return Some(span);
@ -942,7 +942,7 @@ fn check_impl_items_against_trait<'tcx>(
if res.is_ok() {
match ty_impl_item.kind {
ty::AssocKind::Fn => {
ty::AssocKind::Fn { .. } => {
compare_impl_item::refine::check_refining_return_position_impl_trait_in_trait(
tcx,
ty_impl_item,

View file

@ -43,7 +43,7 @@ pub(super) fn compare_impl_item(
debug!(?impl_trait_ref);
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::Const => compare_impl_const(tcx, impl_item, trait_item, impl_trait_ref),
}
@ -1036,7 +1036,7 @@ fn report_trait_method_mismatch<'tcx>(
);
match &terr {
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 sugg = get_self_string(ty, |ty| ty == impl_trait_ref.self_ty());
@ -1255,7 +1255,7 @@ fn compare_self_type<'tcx>(
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, true) => {
@ -1363,7 +1363,7 @@ fn compare_number_of_generics<'tcx>(
let mut err_occurred = None;
for (kind, trait_count, impl_count) in matchings {
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
.params
.iter()
@ -1373,7 +1373,7 @@ fn compare_number_of_generics<'tcx>(
} => {
// A fn can have an arbitrary number of extra elided lifetimes for the
// same signature.
!matches!(kind, ty::AssocKind::Fn)
!item.is_fn()
}
_ => true,
})
@ -1386,7 +1386,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_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
.generics
.params
@ -1412,7 +1412,7 @@ fn compare_number_of_generics<'tcx>(
_ => None,
})
.collect();
let spans = arg_spans(impl_.kind, impl_item.generics);
let spans = arg_spans(&impl_, impl_item.generics);
let span = spans.first().copied();
let mut err = tcx.dcx().struct_span_err(

View file

@ -407,14 +407,14 @@ fn fn_sig_suggestion<'tcx>(
.enumerate()
.map(|(i, ty)| {
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 => {
let reg = format!("{reg} ");
let reg = match &reg[..] {
"'_ " | " " => "",
reg => reg,
};
if assoc.fn_has_self_parameter {
if assoc.is_method() {
match ref_ty.kind() {
ty::Param(param) if param.name == kw::SelfUpper => {
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}")
} else {
format!("_: {ty}")
@ -489,7 +489,7 @@ fn suggestion_signature<'tcx>(
);
match assoc.kind {
ty::AssocKind::Fn => fn_sig_suggestion(
ty::AssocKind::Fn { .. } => fn_sig_suggestion(
tcx,
tcx.liberate_late_bound_regions(
assoc.def_id,

View file

@ -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 {
// 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
// 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.
@ -1089,7 +1089,7 @@ fn check_associated_item(
);
Ok(())
}
ty::AssocKind::Fn => {
ty::AssocKind::Fn { .. } => {
let sig = tcx.fn_sig(item.def_id).instantiate_identity();
let hir_sig = sig_if_method.expect("bad signature for method");
check_fn_or_method(
@ -1716,7 +1716,7 @@ fn check_method_receiver<'tcx>(
) -> Result<(), ErrorGuaranteed> {
let tcx = wfcx.tcx();
if !method.fn_has_self_parameter {
if !method.is_method() {
return Ok(());
}

View file

@ -44,7 +44,7 @@ use rustc_trait_selection::traits::ObligationCtxt;
use tracing::{debug, instrument};
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};
pub(crate) mod dump;
@ -450,7 +450,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
item_def_id: DefId,
item_segment: &rustc_hir::PathSegment<'tcx>,
poly_trait_ref: ty::PolyTraitRef<'tcx>,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> {
if let Some(trait_ref) = poly_trait_ref.no_bound_vars() {
let item_args = self.lowerer().lower_generic_args_of_assoc_item(
@ -525,7 +525,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
inferred_sugg,
bound,
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,
type_def_id,
constraint.ident,
ty::AssocKind::Fn,
ty::AssocTag::Fn,
) {
bound_vars.extend(
self.tcx
@ -1843,7 +1843,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
self.tcx,
type_def_id,
constraint.ident,
ty::AssocKind::Type,
ty::AssocTag::Type,
)
.map(|(bound_vars, _)| bound_vars);
self.with(scope, |this| {
@ -1875,13 +1875,13 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
def_id: DefId,
assoc_ident: Ident,
assoc_kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
) -> Option<(Vec<ty::BoundVariableKind>, &'tcx ty::AssocItem)> {
let trait_defines_associated_item_named = |trait_def_id: DefId| {
tcx.associated_items(trait_def_id).find_by_ident_and_kind(
tcx,
assoc_ident,
assoc_kind,
assoc_tag,
trait_def_id,
)
};
@ -1894,8 +1894,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
let Some((def_id, bound_vars)) = stack.pop() else {
break None;
};
// See issue #83753. If someone writes an associated type on a non-trait, just treat it as
// there being no supertrait HRTBs.
// See issue #83753. If someone writes an associated type on a non-trait, just treat it
// as there being no supertrait HRTBs.
match tcx.def_kind(def_id) {
DefKind::Trait | DefKind::TraitAlias | DefKind::Impl { .. } => {}
_ => break None,
@ -2067,7 +2067,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
self.tcx,
trait_def_id,
item_segment.ident,
ty::AssocKind::Fn,
ty::AssocTag::Fn,
)
});
@ -2112,7 +2112,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
self.tcx,
trait_def_id,
item_segment.ident,
ty::AssocKind::Fn,
ty::AssocTag::Fn,
) else {
return;
};

View file

@ -32,7 +32,9 @@ 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) {
let assoc = tcx.associated_item(assoc_id);
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
ty::AssocKind::Type => {}
}

View file

@ -431,16 +431,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
) -> Result<(), ErrorGuaranteed> {
let tcx = self.tcx();
let assoc_kind = if constraint.gen_args.parenthesized
let assoc_tag = if constraint.gen_args.parenthesized
== hir::GenericArgsParentheses::ReturnTypeNotation
{
ty::AssocKind::Fn
ty::AssocTag::Fn
} else if let hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(_) } =
constraint.kind
{
ty::AssocKind::Const
ty::AssocTag::Const
} else {
ty::AssocKind::Type
ty::AssocTag::Type
};
// 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; }
let candidate = if self.probe_trait_that_defines_assoc_item(
trait_ref.def_id(),
assoc_kind,
assoc_tag,
constraint.ident,
) {
// 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(
|| traits::supertraits(tcx, trait_ref),
AssocItemQSelf::Trait(trait_ref.def_id()),
assoc_kind,
assoc_tag,
constraint.ident,
path_span,
Some(constraint),
@ -474,7 +474,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let assoc_item = self
.probe_assoc_item(
constraint.ident,
assoc_kind,
assoc_tag,
hir_ref_id,
constraint.span,
candidate.def_id(),
@ -493,7 +493,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
})
.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);
ty::Binder::bind_with_vars(
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 {
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 {
span: constraint.span,
}));
@ -679,7 +679,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
trait_def_id,
hir_ty.span,
item_segment,
ty::AssocKind::Type,
ty::AssocTag::Type,
);
return Ty::new_error(tcx, guar);
};
@ -771,7 +771,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
)
},
AssocItemQSelf::SelfTyAlias,
ty::AssocKind::Fn,
ty::AssocTag::Fn,
assoc_ident,
span,
None,
@ -783,7 +783,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
) => self.probe_single_ty_param_bound_for_assoc_item(
param_did.expect_local(),
qself.span,
ty::AssocKind::Fn,
ty::AssocTag::Fn,
assoc_ident,
span,
)?,
@ -823,7 +823,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let trait_def_id = bound.def_id();
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");
Ok((bound, assoc_ty.def_id))

View file

@ -116,7 +116,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&self,
all_candidates: impl Fn() -> I,
qself: AssocItemQSelf,
assoc_kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
assoc_ident: Ident,
span: Span,
constraint: Option<&hir::AssocItemConstraint<'tcx>>,
@ -134,14 +134,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}) {
return self.complain_about_assoc_kind_mismatch(
assoc_item,
assoc_kind,
assoc_tag,
assoc_ident,
span,
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);
// The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a
@ -168,7 +168,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let all_candidate_names: Vec<_> = all_candidates()
.flat_map(|r| tcx.associated_items(r.def_id()).in_definition_order())
.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();
@ -200,7 +200,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.iter()
.flat_map(|trait_def_id| tcx.associated_items(*trait_def_id).in_definition_order())
.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();
@ -213,7 +213,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.filter(|trait_def_id| {
tcx.associated_items(trait_def_id)
.filter_by_name_unhygienic(suggested_name)
.any(|item| item.kind == assoc_kind)
.any(|item| item.as_tag() == assoc_tag)
})
.collect::<Vec<_>>()[..]
{
@ -330,7 +330,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
fn complain_about_assoc_kind_mismatch(
&self,
assoc_item: &ty::AssocItem,
assoc_kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
ident: Ident,
span: Span,
constraint: Option<&hir::AssocItemConstraint<'tcx>>,
@ -375,17 +375,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
hir::Term::Ty(ty) => ty.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 {
(ident.span, None, assoc_kind, assoc_item.kind)
(ident.span, None, assoc_tag, assoc_item.as_tag())
};
self.dcx().emit_err(errors::AssocKindMismatch {
span,
expected: assoc_kind_str(expected),
got: assoc_kind_str(got),
expected: assoc_tag_str(expected),
got: assoc_tag_str(got),
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),
bound_on_assoc_const_label,
wrap_in_braces_sugg,
@ -398,9 +398,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
types: &[String],
traits: &[String],
name: Symbol,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
) -> ErrorGuaranteed {
let kind_str = assoc_kind_str(kind);
let kind_str = assoc_tag_str(assoc_tag);
let mut err =
struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated {kind_str}");
if self
@ -569,7 +569,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
candidates: Vec<(DefId, (DefId, DefId))>,
fulfillment_errors: Vec<FulfillmentError<'tcx>>,
span: Span,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
) -> ErrorGuaranteed {
// FIXME(fmease): This was copied in parts from an old version of `rustc_hir_typeck::method::suggest`.
// Either
@ -579,14 +579,14 @@ impl<'tcx> dyn HirTyLowerer<'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 add_def_label = |err: &mut Diag<'_>| {
if let Some(did) = adt_did {
err.span_label(
tcx.def_span(did),
format!(
"associated {kind_str} `{name}` not found for this {}",
"associated {assoc_tag_str} `{name}` not found for this {}",
tcx.def_descr(did)
),
);
@ -615,11 +615,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self.dcx(),
name.span,
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.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);
return err.emit();
@ -700,7 +700,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let mut err = self.dcx().struct_span_err(
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() {
err.note(format!(
@ -710,7 +710,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
err.span_label(
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 {
@ -812,7 +812,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let assoc_item = tcx.associated_items(trait_def).find_by_ident_and_kind(
tcx,
ident,
ty::AssocKind::Type,
ty::AssocTag::Type,
trait_def,
);
@ -1022,12 +1022,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.map(|simple_ty| tcx.incoherent_impls(simple_ty))
})
&& let name = Symbol::intern(&format!("{ident2}_{ident3}"))
&& let Some(ty::AssocItem { kind: ty::AssocKind::Fn, .. }) = inherent_impls
&& let Some(item) = inherent_impls
.iter()
.flat_map(|inherent_impl| {
tcx.associated_items(inherent_impl).filter_by_name_unhygienic(name)
})
.next()
&& item.is_fn()
{
Err(struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type")
.with_span_suggestion_verbose(
@ -1629,10 +1630,10 @@ fn generics_args_err_extend<'a>(
}
}
pub(crate) fn assoc_kind_str(kind: ty::AssocKind) -> &'static str {
match kind {
ty::AssocKind::Fn => "function",
ty::AssocKind::Const => "constant",
ty::AssocKind::Type => "type",
pub(crate) fn assoc_tag_str(assoc_tag: ty::AssocTag) -> &'static str {
match assoc_tag {
ty::AssocTag::Fn => "function",
ty::AssocTag::Const => "constant",
ty::AssocTag::Type => "type",
}
}

View file

@ -38,8 +38,8 @@ use rustc_middle::middle::stability::AllowUnstable;
use rustc_middle::mir::interpret::LitToConstInput;
use rustc_middle::ty::print::PrintPolyTraitRefExt as _;
use rustc_middle::ty::{
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt,
TypeVisitableExt, TypingMode, Upcast, fold_regions,
self, AssocTag, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty,
TyCtxt, TypeVisitableExt, TypingMode, Upcast, fold_regions,
};
use rustc_middle::{bug, span_bug};
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
@ -51,7 +51,7 @@ use rustc_trait_selection::traits::wf::object_region_bounds;
use rustc_trait_selection::traits::{self, ObligationCtxt};
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::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, NoVariantNamed};
use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint};
@ -168,7 +168,7 @@ pub trait HirTyLowerer<'tcx> {
item_def_id: DefId,
item_segment: &hir::PathSegment<'tcx>,
poly_trait_ref: ty::PolyTraitRef<'tcx>,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed>;
fn lower_fn_sig(
@ -251,10 +251,10 @@ enum LowerAssocMode {
}
impl LowerAssocMode {
fn kind(self) -> ty::AssocKind {
fn assoc_tag(self) -> ty::AssocTag {
match self {
LowerAssocMode::Type { .. } => ty::AssocKind::Type,
LowerAssocMode::Const => ty::AssocKind::Const,
LowerAssocMode::Type { .. } => ty::AssocTag::Type,
LowerAssocMode::Const => ty::AssocTag::Const,
}
}
@ -268,7 +268,8 @@ impl LowerAssocMode {
fn permit_variants(self) -> bool {
match self {
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,
}
}
@ -932,12 +933,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
fn probe_trait_that_defines_assoc_item(
&self,
trait_def_id: DefId,
assoc_kind: ty::AssocKind,
assoc_tag: AssocTag,
assoc_ident: Ident,
) -> bool {
self.tcx()
.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()
}
@ -975,7 +976,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&self,
ty_param_def_id: LocalDefId,
ty_param_span: Span,
kind: ty::AssocKind,
assoc_tag: AssocTag,
assoc_ident: Ident,
span: Span,
) -> 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)
},
AssocItemQSelf::TyParam(ty_param_def_id, ty_param_span),
kind,
assoc_tag,
assoc_ident,
span,
None,
@ -1010,7 +1011,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&self,
all_candidates: impl Fn() -> I,
qself: AssocItemQSelf,
assoc_kind: ty::AssocKind,
assoc_tag: AssocTag,
assoc_ident: Ident,
span: Span,
constraint: Option<&hir::AssocItemConstraint<'tcx>>,
@ -1021,14 +1022,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let tcx = self.tcx();
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 reported = self.complain_about_assoc_item_not_found(
all_candidates,
qself,
assoc_kind,
assoc_tag,
assoc_ident,
span,
constraint,
@ -1040,7 +1041,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
if let Some(bound2) = matching_candidates.next() {
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 mut err = self.dcx().create_err(crate::errors::AmbiguousAssocItem {
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.
let mut where_bounds = vec![];
for bound in [bound, bound2].into_iter().chain(matching_candidates) {
let bound_id = bound.def_id();
let bound_span = tcx
.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));
if let Some(bound_span) = bound_span {
@ -1265,7 +1267,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
qself_ty,
hir_ref_id,
span,
mode.kind(),
mode.assoc_tag(),
)? {
return Ok(LoweredAssoc::Term(did, args));
}
@ -1296,7 +1298,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
)
},
AssocItemQSelf::SelfTyAlias,
mode.kind(),
mode.assoc_tag(),
assoc_ident,
span,
None,
@ -1308,12 +1310,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
) => self.probe_single_ty_param_bound_for_assoc_item(
param_did.expect_local(),
qself.span,
mode.kind(),
mode.assoc_tag(),
assoc_ident,
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() {
// Variant in type position
let msg = format!("expected {kind_str}, found variant `{assoc_ident}`");
@ -1420,7 +1422,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&[qself_ty.to_string()],
&traits,
assoc_ident.name,
mode.kind(),
mode.assoc_tag(),
)
};
return Err(reported);
@ -1429,10 +1431,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let trait_did = bound.def_id();
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");
let (def_id, args) =
self.lower_assoc_shared(span, assoc_item.def_id, assoc_segment, bound, mode.kind())?;
let (def_id, args) = self.lower_assoc_shared(
span,
assoc_item.def_id,
assoc_segment,
bound,
mode.assoc_tag(),
)?;
let result = LoweredAssoc::Term(def_id, args);
if let Some(variant_def_id) = variant_resolution {
@ -1469,20 +1476,21 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self_ty: Ty<'tcx>,
block: HirId,
span: Span,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
) -> Result<Option<(DefId, GenericArgsRef<'tcx>)>, ErrorGuaranteed> {
let tcx = self.tcx();
if !tcx.features().inherent_associated_types() {
match kind {
// Don't attempt to look up inherent associated types when the feature is not enabled.
// Theoretically it'd be fine to do so since we feature-gate their definition site.
// However, due to current limitations of the implementation (caused by us performing
// selection during HIR ty lowering instead of in the trait solver), IATs can lead to cycle
// errors (#108491) which mask the feature-gate error, needlessly confusing users
// who use IATs by accident (#113265).
ty::AssocKind::Type => return Ok(None),
ty::AssocKind::Const => {
match assoc_tag {
// Don't attempt to look up inherent associated types when the feature is not
// enabled. Theoretically it'd be fine to do so since we feature-gate their
// definition site. However, due to current limitations of the implementation
// (caused by us performing selection during HIR ty lowering instead of in the
// trait solver), IATs can lead to cycle errors (#108491) which mask the
// feature-gate error, needlessly confusing users who use IATs by accident
// (#113265).
ty::AssocTag::Type => return Ok(None),
ty::AssocTag::Const => {
// 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
// same machinery and has similar rough edges.
@ -1494,7 +1502,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
)
.emit());
}
ty::AssocKind::Fn => unreachable!(),
ty::AssocTag::Fn => unreachable!(),
}
}
@ -1503,7 +1511,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.inherent_impls(adt_did)
.iter()
.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)))
})
.collect();
@ -1542,7 +1551,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self_ty,
|self_ty| {
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>,
param_env: ParamEnv<'tcx>,
candidates: Vec<(DefId, (DefId, DefId))>,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
) -> Result<(DefId, (DefId, DefId)), ErrorGuaranteed> {
let tcx = self.tcx();
let mut fulfillment_errors = Vec::new();
@ -1621,7 +1630,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
candidates,
fulfillment_errors,
span,
kind,
assoc_tag,
)),
&[applicable_candidate] => Ok(applicable_candidate),
@ -1640,12 +1649,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
fn probe_assoc_item(
&self,
ident: Ident,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
block: HirId,
span: Span,
scope: DefId,
) -> 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);
Some(item)
}
@ -1657,7 +1666,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
fn probe_assoc_item_unchecked(
&self,
ident: Ident,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
block: HirId,
scope: DefId,
) -> Option<(ty::AssocItem, /*scope*/ DefId)> {
@ -1670,7 +1679,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let item = tcx
.associated_items(scope)
.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))
}
@ -1770,7 +1779,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
item_def_id,
trait_segment,
item_segment,
ty::AssocKind::Type,
ty::AssocTag::Type,
) {
Ok((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,
trait_segment,
item_segment,
ty::AssocKind::Const,
ty::AssocTag::Const,
) {
Ok((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,
trait_segment: &hir::PathSegment<'tcx>,
item_segment: &hir::PathSegment<'tcx>,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed> {
let tcx = self.tcx();
@ -1821,7 +1830,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
debug!(?trait_def_id);
let Some(self_ty) = opt_self_ty else {
return Err(self.error_missing_qpath_self_ty(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);
@ -1840,7 +1854,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
trait_def_id: DefId,
span: Span,
item_segment: &hir::PathSegment<'tcx>,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
) -> ErrorGuaranteed {
let tcx = self.tcx();
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
// references the trait. Relevant for the first case in
// `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs`
self.report_ambiguous_assoc(span, &type_names, &[path_str], item_segment.ident.name, kind)
self.report_ambiguous_assoc(
span,
&type_names,
&[path_str],
item_segment.ident.name,
assoc_tag,
)
}
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(
tcx,
*ident,
ty::AssocKind::Fn,
ty::AssocTag::Fn,
trait_ref.def_id,
)?;

View file

@ -119,7 +119,7 @@ pub(crate) fn enforce_impl_lifetime_params_are_constrained(
vec![]
}
}
ty::AssocKind::Fn | ty::AssocKind::Const => vec![],
ty::AssocKind::Fn { .. } | ty::AssocKind::Const => vec![],
}
})
.collect();