Auto merge of #118668 - fmease:resolve-assoc-item-bindings-by-namespace, r=compiler-errors

Resolve associated item bindings by namespace

This is the 3rd commit split off from #118360 with tests reblessed (they no longer contain duplicated diags which were caused by 4c0addc80a) & slightly adapted (removed supertraits from a UI test, cc #118040).

> * Resolve all assoc item bindings (type, const, fn (feature `return_type_notation`)) by namespace instead of trying to resolve a type first (in the non-RTN case) and falling back to consts afterwards. This is consistent with RTN. E.g., for `Tr<K = {…}>` we now always try to look up assoc consts (this extends to supertrait bounds). This gets rid of assoc tys shadowing assoc consts in assoc item bindings which is undesirable & inconsistent (types and consts live in different namespaces after all)
> * Consolidate the resolution of assoc {ty, const} bindings and RTN (dedup, better diags for RTN)
> * Fix assoc consts being labeled as assoc *types* in several diagnostics
> * Make a bunch of diagnostics translatable

Fixes #112560 (error → pass).

As discussed
r? `@compiler-errors`

---

**Addendum**: What I call “associated item bindings” are commonly referred to as “type bindings” for historical reasons. Nowadays, “type bindings” include assoc type bindings, assoc const bindings and RTN (return type notation) which is why I prefer not to use this outdated term.
This commit is contained in:
bors 2023-12-08 09:30:52 +00:00
commit 5ea62560f2
27 changed files with 598 additions and 416 deletions

View File

@ -1,8 +1,28 @@
hir_analysis_ambiguous_assoc_item = ambiguous associated {$assoc_kind} `{$assoc_name}` in bounds of `{$ty_param_name}`
.label = ambiguous associated {$assoc_kind} `{$assoc_name}`
hir_analysis_ambiguous_lifetime_bound =
ambiguous lifetime bound, explicit lifetime bound required
hir_analysis_assoc_bound_on_const = expected associated type, found {$descr}
.note = trait bounds not allowed on {$descr}
hir_analysis_assoc_item_not_found = associated {$assoc_kind} `{$assoc_name}` not found for `{$ty_param_name}`
hir_analysis_assoc_item_not_found_found_in_other_trait_label = there is {$identically_named ->
[true] an
*[false] a similarly named
} associated {$assoc_kind} `{$suggested_name}` in the trait `{$trait_name}`
hir_analysis_assoc_item_not_found_label = associated {$assoc_kind} `{$assoc_name}` not found
hir_analysis_assoc_item_not_found_other_sugg = `{$ty_param_name}` has the following associated {$assoc_kind}
hir_analysis_assoc_item_not_found_similar_in_other_trait_sugg = change the associated {$assoc_kind} name to use `{$suggested_name}` from `{$trait_name}`
hir_analysis_assoc_item_not_found_similar_in_other_trait_with_bound_sugg = and also change the associated {$assoc_kind} name
hir_analysis_assoc_item_not_found_similar_sugg = there is an associated {$assoc_kind} with a similar name
hir_analysis_assoc_kind_mismatch = expected {$expected}, found {$got}
.label = unexpected {$got}
.expected_because_label = expected a {$expected} because of this associated {$expected}
.note = the associated {$assoc_kind} is defined here
.bound_on_assoc_const_label = bounds are not allowed on associated constants
hir_analysis_assoc_kind_mismatch_wrap_in_braces_sugg = consider adding braces here
hir_analysis_assoc_type_binding_not_allowed =
associated type bindings are not allowed here
@ -280,10 +300,6 @@ hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is no
hir_analysis_requires_note = the `{$trait_name}` impl for `{$ty}` requires that `{$error_predicate}`
hir_analysis_return_type_notation_conflicting_bound =
ambiguous associated function `{$assoc_name}` for `{$ty_name}`
.note = `{$assoc_name}` is declared in two supertraits: `{$first_bound}` and `{$second_bound}`
hir_analysis_return_type_notation_equality_bound =
return type notation is not allowed to use type equality
@ -294,9 +310,6 @@ hir_analysis_return_type_notation_illegal_param_type =
return type notation is not allowed for functions that have type parameters
.label = type parameter declared here
hir_analysis_return_type_notation_missing_method =
cannot find associated function `{$assoc_name}` for `{$ty_name}`
hir_analysis_return_type_notation_on_non_rpitit =
return type notation used on function that is not `async` and does not return `impl Trait`
.note = function returns `{$ty}`, which is not compatible with associated type return bounds

View File

@ -3,8 +3,7 @@ use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_lint_defs::Applicability;
use rustc_middle::ty::{self as ty, Ty, TypeVisitableExt};
use rustc_middle::ty::{self as ty, Ty};
use rustc_span::symbol::Ident;
use rustc_span::{ErrorGuaranteed, Span};
use rustc_trait_selection::traits;
@ -256,64 +255,49 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
let tcx = self.tcx();
let return_type_notation =
binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation;
let candidate = if return_type_notation {
if self.trait_defines_associated_item_named(
trait_ref.def_id(),
ty::AssocKind::Fn,
binding.item_name,
) {
trait_ref
let assoc_kind =
if binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation {
ty::AssocKind::Fn
} else if let ConvertedBindingKind::Equality(term) = binding.kind
&& let ty::TermKind::Const(_) = term.node.unpack()
{
ty::AssocKind::Const
} else {
self.one_bound_for_assoc_method(
traits::supertraits(tcx, trait_ref),
trait_ref.print_only_trait_path(),
binding.item_name,
path_span,
)?
}
} else if self.trait_defines_associated_item_named(
ty::AssocKind::Type
};
let candidate = if self.trait_defines_associated_item_named(
trait_ref.def_id(),
ty::AssocKind::Type,
assoc_kind,
binding.item_name,
) {
// Simple case: X is defined in the current trait.
// Simple case: The assoc item is defined in the current trait.
trait_ref
} else {
// Otherwise, we have to walk through the supertraits to find
// those that do.
self.one_bound_for_assoc_type(
// one that does define it.
self.one_bound_for_assoc_item(
|| traits::supertraits(tcx, trait_ref),
trait_ref.skip_binder().print_only_trait_name(),
None,
assoc_kind,
binding.item_name,
path_span,
match binding.kind {
ConvertedBindingKind::Equality(term) => Some(term),
_ => None,
},
Some(&binding),
)?
};
let (assoc_ident, def_scope) =
tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id);
// We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead
// of calling `filter_by_name_and_kind`.
let find_item_of_kind = |kind| {
tcx.associated_items(candidate.def_id())
.filter_by_name_unhygienic(assoc_ident.name)
.find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident)
};
let assoc_item = if return_type_notation {
find_item_of_kind(ty::AssocKind::Fn)
} else {
find_item_of_kind(ty::AssocKind::Type)
.or_else(|| find_item_of_kind(ty::AssocKind::Const))
}
.expect("missing associated type");
// We have already adjusted the item name above, so compare with `.normalize_to_macros_2_0()`
// instead of calling `filter_by_name_and_kind` which would needlessly normalize the
// `assoc_ident` again and again.
let assoc_item = tcx
.associated_items(candidate.def_id())
.filter_by_name_unhygienic(assoc_ident.name)
.find(|i| i.kind == assoc_kind && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident)
.expect("missing associated item");
if !assoc_item.visibility(tcx).is_accessible_from(def_scope, tcx) {
tcx.sess
@ -340,7 +324,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
.or_insert(binding.span);
}
let projection_ty = if return_type_notation {
let projection_ty = if let ty::AssocKind::Fn = assoc_kind {
let mut emitted_bad_param_err = false;
// If we have an method return type bound, then we need to substitute
// the method's early bound params with suitable late-bound params.
@ -467,7 +451,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
let late_bound_in_trait_ref =
tcx.collect_constrained_late_bound_regions(&projection_ty);
let late_bound_in_ty =
tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(ty));
tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(ty.node));
debug!(?late_bound_in_trait_ref);
debug!(?late_bound_in_ty);
@ -492,77 +476,27 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
}
}
let assoc_item_def_id = projection_ty.skip_binder().def_id;
let def_kind = tcx.def_kind(assoc_item_def_id);
match binding.kind {
ConvertedBindingKind::Equality(..) if return_type_notation => {
ConvertedBindingKind::Equality(..) if let ty::AssocKind::Fn = assoc_kind => {
return Err(self.tcx().sess.emit_err(
crate::errors::ReturnTypeNotationEqualityBound { span: binding.span },
));
}
ConvertedBindingKind::Equality(mut term) => {
ConvertedBindingKind::Equality(term) => {
// "Desugar" a constraint like `T: Iterator<Item = u32>` this to
// the "projection predicate" for:
//
// `<T as Iterator>::Item = u32`
match (def_kind, term.unpack()) {
(DefKind::AssocTy, ty::TermKind::Ty(_))
| (DefKind::AssocConst, ty::TermKind::Const(_)) => (),
(_, _) => {
let got = if let Some(_) = term.ty() { "type" } else { "constant" };
let expected = tcx.def_descr(assoc_item_def_id);
let mut err = tcx.sess.struct_span_err(
binding.span,
format!("expected {expected} bound, found {got}"),
);
err.span_note(
tcx.def_span(assoc_item_def_id),
format!("{expected} defined here"),
);
if let DefKind::AssocConst = def_kind
&& let Some(t) = term.ty()
&& (t.is_enum() || t.references_error())
&& tcx.features().associated_const_equality
{
err.span_suggestion(
binding.span,
"if equating a const, try wrapping with braces",
format!("{} = {{ const }}", binding.item_name),
Applicability::HasPlaceholders,
);
}
let reported = err.emit();
term = match def_kind {
DefKind::AssocTy => Ty::new_error(tcx, reported).into(),
DefKind::AssocConst => ty::Const::new_error(
tcx,
reported,
tcx.type_of(assoc_item_def_id)
.instantiate(tcx, projection_ty.skip_binder().args),
)
.into(),
_ => unreachable!(),
};
}
}
bounds.push_projection_bound(
tcx,
projection_ty
.map_bound(|projection_ty| ty::ProjectionPredicate { projection_ty, term }),
projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate {
projection_ty,
term: term.node,
}),
binding.span,
);
}
ConvertedBindingKind::Constraint(ast_bounds) => {
match def_kind {
DefKind::AssocTy => {}
_ => {
return Err(tcx.sess.emit_err(errors::AssocBoundOnConst {
span: assoc_ident.span,
descr: tcx.def_descr(assoc_item_def_id),
}));
}
}
// "Desugar" a constraint like `T: Iterator<Item: Debug>` to
//
// `<T as Iterator>::Item: Debug`

View File

@ -1,15 +1,16 @@
use crate::astconv::AstConv;
use crate::astconv::{AstConv, ConvertedBindingKind};
use crate::errors::{
AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
self, AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
ParenthesizedFnTraitExpansion,
};
use crate::fluent_generated as fluent;
use crate::traits::error_reporting::report_object_safety_error;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_infer::traits::FulfillmentError;
use rustc_middle::ty::{self, suggest_constraining_type_param, AssocItem, AssocKind, Ty, TyCtxt};
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TyCtxt, TypeVisitableExt};
use rustc_session::parse::feature_err;
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::symbol::{sym, Ident};
@ -97,83 +98,88 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
}
pub(crate) fn complain_about_assoc_type_not_found<I>(
pub(super) fn complain_about_assoc_item_not_found<I>(
&self,
all_candidates: impl Fn() -> I,
ty_param_name: &str,
ty_param_def_id: Option<LocalDefId>,
assoc_kind: ty::AssocKind,
assoc_name: Ident,
span: Span,
binding: Option<&super::ConvertedBinding<'_, 'tcx>>,
) -> ErrorGuaranteed
where
I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
{
let tcx = self.tcx();
// First and foremost, provide a more user-friendly & “intuitive” error on kind mismatches.
if let Some(assoc_item) = all_candidates().find_map(|r| {
tcx.associated_items(r.def_id())
.filter_by_name_unhygienic(assoc_name.name)
.find(|item| tcx.hygienic_eq(assoc_name, item.ident(tcx), r.def_id()))
}) {
return self.complain_about_assoc_kind_mismatch(
assoc_item, assoc_kind, assoc_name, span, binding,
);
}
let assoc_kind_str = super::assoc_kind_str(assoc_kind);
// The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a
// valid span, so we point at the whole path segment instead.
let is_dummy = assoc_name.span == DUMMY_SP;
let mut err = struct_span_err!(
self.tcx().sess,
if is_dummy { span } else { assoc_name.span },
E0220,
"associated type `{}` not found for `{}`",
let mut err = errors::AssocItemNotFound {
span: if is_dummy { span } else { assoc_name.span },
assoc_name,
ty_param_name
);
assoc_kind: assoc_kind_str,
ty_param_name,
label: None,
sugg: None,
};
if is_dummy {
err.span_label(span, format!("associated type `{assoc_name}` not found"));
return err.emit();
err.label = Some(errors::AssocItemNotFoundLabel::NotFound { span });
return tcx.sess.emit_err(err);
}
let all_candidate_names: Vec<_> = all_candidates()
.flat_map(|r| self.tcx().associated_items(r.def_id()).in_definition_order())
.flat_map(|r| tcx.associated_items(r.def_id()).in_definition_order())
.filter_map(|item| {
if !item.is_impl_trait_in_trait() && item.kind == ty::AssocKind::Type {
Some(item.name)
} else {
None
}
(!item.is_impl_trait_in_trait() && item.kind == assoc_kind).then_some(item.name)
})
.collect();
if let Some(suggested_name) =
find_best_match_for_name(&all_candidate_names, assoc_name.name, None)
{
err.span_suggestion(
assoc_name.span,
"there is an associated type with a similar name",
err.sugg = Some(errors::AssocItemNotFoundSugg::Similar {
span: assoc_name.span,
assoc_kind: assoc_kind_str,
suggested_name,
Applicability::MaybeIncorrect,
);
return err.emit();
});
return tcx.sess.emit_err(err);
}
// If we didn't find a good item in the supertraits (or couldn't get
// the supertraits), like in ItemCtxt, then look more generally from
// all visible traits. If there's one clear winner, just suggest that.
let visible_traits: Vec<_> = self
.tcx()
let visible_traits: Vec<_> = tcx
.all_traits()
.filter(|trait_def_id| {
let viz = self.tcx().visibility(*trait_def_id);
let viz = tcx.visibility(*trait_def_id);
let def_id = self.item_def_id();
viz.is_accessible_from(def_id, self.tcx())
viz.is_accessible_from(def_id, tcx)
})
.collect();
let wider_candidate_names: Vec<_> = visible_traits
.iter()
.flat_map(|trait_def_id| {
self.tcx().associated_items(*trait_def_id).in_definition_order()
})
.flat_map(|trait_def_id| tcx.associated_items(*trait_def_id).in_definition_order())
.filter_map(|item| {
if !item.is_impl_trait_in_trait() && item.kind == ty::AssocKind::Type {
Some(item.name)
} else {
None
}
(!item.is_impl_trait_in_trait() && item.kind == assoc_kind).then_some(item.name)
})
.collect();
@ -182,52 +188,51 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
{
if let [best_trait] = visible_traits
.iter()
.copied()
.filter(|trait_def_id| {
self.tcx()
.associated_items(*trait_def_id)
tcx.associated_items(trait_def_id)
.filter_by_name_unhygienic(suggested_name)
.any(|item| item.kind == ty::AssocKind::Type)
.any(|item| item.kind == assoc_kind)
})
.collect::<Vec<_>>()[..]
{
let trait_name = self.tcx().def_path_str(*best_trait);
let an = if suggested_name != assoc_name.name { "a similarly named" } else { "an" };
err.span_label(
assoc_name.span,
format!(
"there is {an} associated type `{suggested_name}` in the \
trait `{trait_name}`",
),
);
let hir = self.tcx().hir();
let trait_name = tcx.def_path_str(best_trait);
err.label = Some(errors::AssocItemNotFoundLabel::FoundInOtherTrait {
span: assoc_name.span,
assoc_kind: assoc_kind_str,
trait_name: &trait_name,
suggested_name,
identically_named: suggested_name == assoc_name.name,
});
let hir = tcx.hir();
if let Some(def_id) = ty_param_def_id
&& let parent = hir.get_parent_item(self.tcx().local_def_id_to_hir_id(def_id))
&& let parent = hir.get_parent_item(tcx.local_def_id_to_hir_id(def_id))
&& let Some(generics) = hir.get_generics(parent.def_id)
{
if generics.bounds_for_param(def_id).flat_map(|pred| pred.bounds.iter()).any(
|b| match b {
hir::GenericBound::Trait(t, ..) => {
t.trait_ref.trait_def_id().as_ref() == Some(best_trait)
t.trait_ref.trait_def_id() == Some(best_trait)
}
_ => false,
},
) {
// The type param already has a bound for `trait_name`, we just need to
// change the associated type.
err.span_suggestion_verbose(
assoc_name.span,
format!(
"change the associated type name to use `{suggested_name}` from \
`{trait_name}`",
),
suggested_name.to_string(),
Applicability::MaybeIncorrect,
);
} else if suggest_constraining_type_param(
self.tcx(),
// change the associated item.
err.sugg = Some(errors::AssocItemNotFoundSugg::SimilarInOtherTrait {
span: assoc_name.span,
assoc_kind: assoc_kind_str,
suggested_name,
});
return tcx.sess.emit_err(err);
}
let mut err = tcx.sess.create_err(err);
if suggest_constraining_type_param(
tcx,
generics,
&mut err,
ty_param_name,
&ty_param_name,
&trait_name,
None,
None,
@ -237,39 +242,101 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// was also not an exact match, so we also suggest changing it.
err.span_suggestion_verbose(
assoc_name.span,
"and also change the associated type name",
fluent::hir_analysis_assoc_item_not_found_similar_in_other_trait_with_bound_sugg,
suggested_name.to_string(),
Applicability::MaybeIncorrect,
);
}
return err.emit();
}
return err.emit();
return tcx.sess.emit_err(err);
}
}
// If we still couldn't find any associated type, and only one associated type exists,
// suggests using it.
if all_candidate_names.len() == 1 {
if let [candidate_name] = all_candidate_names.as_slice() {
// this should still compile, except on `#![feature(associated_type_defaults)]`
// where it could suggests `type A = Self::A`, thus recursing infinitely
let applicability = if self.tcx().features().associated_type_defaults {
let applicability = if tcx.features().associated_type_defaults {
Applicability::Unspecified
} else {
Applicability::MaybeIncorrect
};
err.span_suggestion(
assoc_name.span,
format!("`{ty_param_name}` has the following associated type"),
all_candidate_names.first().unwrap().to_string(),
err.sugg = Some(errors::AssocItemNotFoundSugg::Other {
span: assoc_name.span,
applicability,
);
ty_param_name,
assoc_kind: assoc_kind_str,
suggested_name: *candidate_name,
});
} else {
err.span_label(assoc_name.span, format!("associated type `{assoc_name}` not found"));
err.label = Some(errors::AssocItemNotFoundLabel::NotFound { span: assoc_name.span });
}
err.emit()
tcx.sess.emit_err(err)
}
fn complain_about_assoc_kind_mismatch(
&self,
assoc_item: &ty::AssocItem,
assoc_kind: ty::AssocKind,
ident: Ident,
span: Span,
binding: Option<&super::ConvertedBinding<'_, 'tcx>>,
) -> ErrorGuaranteed {
let tcx = self.tcx();
let bound_on_assoc_const_label = if let ty::AssocKind::Const = assoc_item.kind
&& let Some(binding) = binding
&& let ConvertedBindingKind::Constraint(_) = binding.kind
{
let lo = if binding.gen_args.span_ext.is_dummy() {
ident.span
} else {
binding.gen_args.span_ext
};
Some(lo.between(span.shrink_to_hi()))
} else {
None
};
// FIXME(associated_const_equality): This has quite a few false positives and negatives.
let wrap_in_braces_sugg = if let Some(binding) = binding
&& let ConvertedBindingKind::Equality(term) = binding.kind
&& let ty::TermKind::Ty(ty) = term.node.unpack()
&& (ty.is_enum() || ty.references_error())
&& tcx.features().associated_const_equality
{
Some(errors::AssocKindMismatchWrapInBracesSugg {
lo: term.span.shrink_to_lo(),
hi: term.span.shrink_to_hi(),
})
} else {
None
};
// For equality bounds, we want to blame the term (RHS) instead of the item (LHS) since
// one can argue that that's more “untuitive” to the user.
let (span, expected_because_label, expected, got) = if let Some(binding) = binding
&& let ConvertedBindingKind::Equality(term) = binding.kind
{
(term.span, Some(ident.span), assoc_item.kind, assoc_kind)
} else {
(ident.span, None, assoc_kind, assoc_item.kind)
};
tcx.sess.emit_err(errors::AssocKindMismatch {
span,
expected: super::assoc_kind_str(expected),
got: super::assoc_kind_str(got),
expected_because_label,
assoc_kind: super::assoc_kind_str(assoc_item.kind),
def_span: tcx.def_span(assoc_item.def_id),
bound_on_assoc_const_label,
wrap_in_braces_sugg,
})
}
pub(crate) fn complain_about_ambiguous_inherent_assoc_type(
@ -598,7 +665,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let assoc_item = tcx.associated_items(trait_def).find_by_name_and_kind(
tcx,
ident,
AssocKind::Type,
ty::AssocKind::Type,
trait_def,
);
@ -606,7 +673,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}))
})
.flatten()
.collect::<FxHashMap<Symbol, &AssocItem>>();
.collect::<FxHashMap<Symbol, &ty::AssocItem>>();
let mut names = names
.into_iter()

View File

@ -18,8 +18,8 @@ use crate::require_c_abi_if_c_variadic;
use rustc_ast::TraitObjectSyntax;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, FatalError,
MultiSpan,
error_code, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
FatalError, MultiSpan,
};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
@ -36,6 +36,7 @@ use rustc_middle::ty::{
};
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::source_map::{respan, Spanned};
use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::{sym, BytePos, Span, DUMMY_SP};
use rustc_target::spec::abi;
@ -162,7 +163,7 @@ struct ConvertedBinding<'a, 'tcx> {
#[derive(Debug)]
enum ConvertedBindingKind<'a, 'tcx> {
Equality(ty::Term<'tcx>),
Equality(Spanned<ty::Term<'tcx>>),
Constraint(&'a [hir::GenericBound<'a>]),
}
@ -595,12 +596,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.map(|binding| {
let kind = match &binding.kind {
hir::TypeBindingKind::Equality { term } => match term {
hir::Term::Ty(ty) => {
ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty).into())
}
hir::Term::Ty(ty) => ConvertedBindingKind::Equality(respan(
ty.span,
self.ast_ty_to_ty(ty).into(),
)),
hir::Term::Const(c) => {
let span = self.tcx().def_span(c.def_id);
let c = Const::from_anon_const(self.tcx(), c.def_id);
ConvertedBindingKind::Equality(c.into())
ConvertedBindingKind::Equality(respan(span, c.into()))
}
},
hir::TypeBindingKind::Constraint { bounds } => {
@ -1056,7 +1059,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
debug!("find_bound_for_assoc_item: predicates={:#?}", predicates);
let param_name = tcx.hir().ty_param_name(ty_param_def_id);
self.one_bound_for_assoc_type(
self.one_bound_for_assoc_item(
|| {
traits::transitive_bounds_that_define_assoc_item(
tcx,
@ -1068,6 +1071,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
},
param_name,
Some(ty_param_def_id),
ty::AssocKind::Type,
assoc_name,
span,
None,
@ -1076,48 +1080,45 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// Checks that `bounds` contains exactly one element and reports appropriate
// errors otherwise.
#[instrument(level = "debug", skip(self, all_candidates, ty_param_name, is_equality), ret)]
fn one_bound_for_assoc_type<I>(
#[instrument(level = "debug", skip(self, all_candidates, ty_param_name, binding), ret)]
fn one_bound_for_assoc_item<I>(
&self,
all_candidates: impl Fn() -> I,
ty_param_name: impl Display,
ty_param_def_id: Option<LocalDefId>,
assoc_kind: ty::AssocKind,
assoc_name: Ident,
span: Span,
is_equality: Option<ty::Term<'tcx>>,
binding: Option<&ConvertedBinding<'_, 'tcx>>,
) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed>
where
I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
{
let tcx = self.tcx();
let mut matching_candidates = all_candidates().filter(|r| {
self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Type, assoc_name)
});
let mut const_candidates = all_candidates().filter(|r| {
self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Const, assoc_name)
self.trait_defines_associated_item_named(r.def_id(), assoc_kind, assoc_name)
});
let (mut bound, mut next_cand) = match (matching_candidates.next(), const_candidates.next())
{
(Some(bound), _) => (bound, matching_candidates.next()),
(None, Some(bound)) => (bound, const_candidates.next()),
(None, None) => {
let reported = self.complain_about_assoc_type_not_found(
all_candidates,
&ty_param_name.to_string(),
ty_param_def_id,
assoc_name,
span,
);
return Err(reported);
}
let Some(mut bound) = matching_candidates.next() else {
let reported = self.complain_about_assoc_item_not_found(
all_candidates,
&ty_param_name.to_string(),
ty_param_def_id,
assoc_kind,
assoc_name,
span,
binding,
);
return Err(reported);
};
debug!(?bound);
// look for a candidate that is not the same as our first bound, disregarding
// whether the bound is const.
let mut next_cand = matching_candidates.next();
while let Some(mut bound2) = next_cand {
debug!(?bound2);
let tcx = self.tcx();
if bound2.bound_vars() != bound.bound_vars() {
break;
}
@ -1138,7 +1139,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.map(|(n, arg)| if host_index == n { tcx.consts.true_.into() } else { arg });
if unconsted_args.eq(bound2.skip_binder().args.iter()) {
next_cand = matching_candidates.next().or_else(|| const_candidates.next());
next_cand = matching_candidates.next();
} else {
break;
}
@ -1147,48 +1148,53 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
if let Some(bound2) = next_cand {
debug!(?bound2);
let bounds = IntoIterator::into_iter([bound, bound2]).chain(matching_candidates);
let mut err = if is_equality.is_some() {
// More specific Error Index entry.
struct_span_err!(
self.tcx().sess,
span,
E0222,
"ambiguous associated type `{}` in bounds of `{}`",
assoc_name,
ty_param_name
)
} else {
struct_span_err!(
self.tcx().sess,
span,
E0221,
"ambiguous associated type `{}` in bounds of `{}`",
assoc_name,
ty_param_name
)
};
err.span_label(span, format!("ambiguous associated type `{assoc_name}`"));
let assoc_kind_str = assoc_kind_str(assoc_kind);
let ty_param_name = &ty_param_name.to_string();
let mut err = tcx.sess.create_err(crate::errors::AmbiguousAssocItem {
span,
assoc_kind: assoc_kind_str,
assoc_name,
ty_param_name,
});
// Provide a more specific error code index entry for equality bindings.
err.code(
if let Some(binding) = binding
&& let ConvertedBindingKind::Equality(_) = binding.kind
{
error_code!(E0222)
} else {
error_code!(E0221)
},
);
// FIXME(#97583): Resugar equality bounds to type/const bindings.
// FIXME: Turn this into a structured, translateable & more actionable suggestion.
let mut where_bounds = vec![];
for bound in bounds {
for bound in [bound, bound2].into_iter().chain(matching_candidates) {
let bound_id = bound.def_id();
let bound_span = self
.tcx()
let bound_span = tcx
.associated_items(bound_id)
.find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, bound_id)
.and_then(|item| self.tcx().hir().span_if_local(item.def_id));
.find_by_name_and_kind(tcx, assoc_name, assoc_kind, bound_id)
.and_then(|item| tcx.hir().span_if_local(item.def_id));
if let Some(bound_span) = bound_span {
err.span_label(
bound_span,
format!("ambiguous `{assoc_name}` from `{}`", bound.print_trait_sugared(),),
);
if let Some(constraint) = &is_equality {
where_bounds.push(format!(
" T: {trait}::{assoc_name} = {constraint}",
trait=bound.print_only_trait_path(),
));
if let Some(binding) = binding {
match binding.kind {
ConvertedBindingKind::Equality(term) => {
// FIXME(#97583): This isn't syntactically well-formed!
where_bounds.push(format!(
" T: {trait}::{assoc_name} = {term}",
trait = bound.print_only_trait_path(),
term = term.node,
));
}
// FIXME: Provide a suggestion.
ConvertedBindingKind::Constraint(_bounds) => {}
}
} else {
err.span_suggestion_verbose(
span.with_hi(assoc_name.span.lo()),
@ -1199,7 +1205,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
} else {
err.note(format!(
"associated type `{ty_param_name}` could derive from `{}`",
"associated {assoc_kind_str} `{assoc_name}` could derive from `{}`",
bound.print_only_trait_path(),
));
}
@ -1220,46 +1226,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
Ok(bound)
}
#[instrument(level = "debug", skip(self, all_candidates, ty_name), ret)]
fn one_bound_for_assoc_method(
&self,
all_candidates: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
ty_name: impl Display,
assoc_name: Ident,
span: Span,
) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed> {
let mut matching_candidates = all_candidates.filter(|r| {
self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Fn, assoc_name)
});
let candidate = match matching_candidates.next() {
Some(candidate) => candidate,
None => {
return Err(self.tcx().sess.emit_err(
crate::errors::ReturnTypeNotationMissingMethod {
span,
ty_name: ty_name.to_string(),
assoc_name: assoc_name.name,
},
));
}
};
if let Some(conflicting_candidate) = matching_candidates.next() {
return Err(self.tcx().sess.emit_err(
crate::errors::ReturnTypeNotationConflictingBound {
span,
ty_name: ty_name.to_string(),
assoc_name: assoc_name.name,
first_bound: candidate.print_only_trait_path(),
second_bound: conflicting_candidate.print_only_trait_path(),
},
));
}
Ok(candidate)
}
// Create a type from a path to an associated type or to an enum variant.
// For a path `A::B::C::D`, `qself_ty` and `qself_def` are the type and def for `A::B::C`
// and item_segment is the path segment for `D`. We return a type and a def for
@ -1421,7 +1387,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
return Err(guar);
};
self.one_bound_for_assoc_type(
self.one_bound_for_assoc_item(
|| {
traits::supertraits(
tcx,
@ -1430,6 +1396,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
},
kw::SelfUpper,
None,
ty::AssocKind::Type,
assoc_ident,
span,
None,
@ -1510,15 +1477,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
};
let trait_did = bound.def_id();
let Some(assoc_ty_did) = self.lookup_assoc_ty(assoc_ident, hir_ref_id, span, trait_did)
else {
// Assume that if it's not matched, there must be a const defined with the same name
// but it was used in a type position.
let msg = format!("found associated const `{assoc_ident}` when type was expected");
let guar = tcx.sess.struct_span_err(span, msg).emit();
return Err(guar);
};
let assoc_ty_did = self.lookup_assoc_ty(assoc_ident, hir_ref_id, span, trait_did).unwrap();
let ty = self.projected_ty_from_poly_trait_ref(span, assoc_ty_did, assoc_segment, bound);
if let Some(variant_def_id) = variant_resolution {
@ -1731,8 +1690,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let tcx = self.tcx();
let (ident, def_scope) = tcx.adjust_ident_and_get_scope(name, scope, block);
// We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead
// of calling `find_by_name_and_kind`.
// We have already adjusted the item name above, so compare with `.normalize_to_macros_2_0()`
// instead of calling `filter_by_name_and_kind` which would needlessly normalize the
// `ident` again and again.
let item = tcx.associated_items(scope).in_definition_order().find(|i| {
i.kind.namespace() == Namespace::TypeNS
&& i.ident(tcx).normalize_to_macros_2_0() == ident
@ -2858,3 +2818,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
Some(r)
}
}
fn assoc_kind_str(kind: ty::AssocKind) -> &'static str {
match kind {
ty::AssocKind::Fn => "function",
ty::AssocKind::Const => "constant",
ty::AssocKind::Type => "type",
}
}

View File

@ -6,9 +6,121 @@ use rustc_errors::{
MultiSpan,
};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::{self, print::TraitRefPrintOnlyTraitPath, Ty};
use rustc_middle::ty::Ty;
use rustc_span::{symbol::Ident, Span, Symbol};
#[derive(Diagnostic)]
#[diag(hir_analysis_ambiguous_assoc_item)]
pub struct AmbiguousAssocItem<'a> {
#[primary_span]
#[label]
pub span: Span,
pub assoc_kind: &'static str,
pub assoc_name: Ident,
pub ty_param_name: &'a str,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_assoc_kind_mismatch)]
pub struct AssocKindMismatch {
#[primary_span]
#[label]
pub span: Span,
pub expected: &'static str,
pub got: &'static str,
#[label(hir_analysis_expected_because_label)]
pub expected_because_label: Option<Span>,
pub assoc_kind: &'static str,
#[note]
pub def_span: Span,
#[label(hir_analysis_bound_on_assoc_const_label)]
pub bound_on_assoc_const_label: Option<Span>,
#[subdiagnostic]
pub wrap_in_braces_sugg: Option<AssocKindMismatchWrapInBracesSugg>,
}
#[derive(Subdiagnostic)]
#[multipart_suggestion(
hir_analysis_assoc_kind_mismatch_wrap_in_braces_sugg,
applicability = "maybe-incorrect"
)]
pub struct AssocKindMismatchWrapInBracesSugg {
#[suggestion_part(code = "{{ ")]
pub lo: Span,
#[suggestion_part(code = " }}")]
pub hi: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_assoc_item_not_found, code = "E0220")]
pub struct AssocItemNotFound<'a> {
#[primary_span]
pub span: Span,
pub assoc_name: Ident,
pub assoc_kind: &'static str,
pub ty_param_name: &'a str,
#[subdiagnostic]
pub label: Option<AssocItemNotFoundLabel<'a>>,
#[subdiagnostic]
pub sugg: Option<AssocItemNotFoundSugg<'a>>,
}
#[derive(Subdiagnostic)]
pub enum AssocItemNotFoundLabel<'a> {
#[label(hir_analysis_assoc_item_not_found_label)]
NotFound {
#[primary_span]
span: Span,
},
#[label(hir_analysis_assoc_item_not_found_found_in_other_trait_label)]
FoundInOtherTrait {
#[primary_span]
span: Span,
assoc_kind: &'static str,
trait_name: &'a str,
suggested_name: Symbol,
identically_named: bool,
},
}
#[derive(Subdiagnostic)]
pub enum AssocItemNotFoundSugg<'a> {
#[suggestion(
hir_analysis_assoc_item_not_found_similar_sugg,
code = "{suggested_name}",
applicability = "maybe-incorrect"
)]
Similar {
#[primary_span]
span: Span,
assoc_kind: &'static str,
suggested_name: Symbol,
},
#[suggestion(
hir_analysis_assoc_item_not_found_similar_in_other_trait_sugg,
code = "{suggested_name}",
style = "verbose",
applicability = "maybe-incorrect"
)]
SimilarInOtherTrait {
#[primary_span]
span: Span,
assoc_kind: &'static str,
suggested_name: Symbol,
},
#[suggestion(hir_analysis_assoc_item_not_found_other_sugg, code = "{suggested_name}")]
Other {
#[primary_span]
span: Span,
#[applicability]
applicability: Applicability,
ty_param_name: &'a str,
assoc_kind: &'static str,
suggested_name: Symbol,
},
}
#[derive(Diagnostic)]
#[diag(hir_analysis_unrecognized_atomic_operation, code = "E0092")]
pub struct UnrecognizedAtomicOperation<'a> {
@ -537,27 +649,6 @@ pub(crate) struct ReturnTypeNotationEqualityBound {
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_return_type_notation_missing_method)]
pub(crate) struct ReturnTypeNotationMissingMethod {
#[primary_span]
pub span: Span,
pub ty_name: String,
pub assoc_name: Symbol,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_return_type_notation_conflicting_bound)]
#[note]
pub(crate) struct ReturnTypeNotationConflictingBound<'tcx> {
#[primary_span]
pub span: Span,
pub ty_name: String,
pub assoc_name: Symbol,
pub first_bound: ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
pub second_bound: ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_placeholder_not_allowed_item_signatures, code = "E0121")]
pub(crate) struct PlaceholderNotAllowedItemSignatures {
@ -954,15 +1045,6 @@ pub(crate) struct ReturnPositionImplTraitInTraitRefined<'tcx> {
pub return_ty: Ty<'tcx>,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_assoc_bound_on_const)]
#[note]
pub struct AssocBoundOnConst {
#[primary_span]
pub span: Span,
pub descr: &'static str,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_inherent_ty_outside, code = "E0390")]
#[help]

View File

@ -0,0 +1,19 @@
// We used to say "ambiguous associated type" on ambiguous associated consts.
// Ensure that we now use the correct label.
#![feature(associated_const_equality)]
trait Trait0: Parent0<i32> + Parent0<u32> {}
trait Parent0<T> { const K: (); }
fn take0(_: impl Trait0<K = { () }>) {}
//~^ ERROR ambiguous associated constant `K` in bounds of `Trait0`
trait Trait1: Parent1 + Parent2 {}
trait Parent1 { const C: i32; }
trait Parent2 { const C: &'static str; }
fn take1(_: impl Trait1<C = "?">) {}
//~^ ERROR ambiguous associated constant `C` in bounds of `Trait1`
fn main() {}

View File

@ -0,0 +1,38 @@
error[E0222]: ambiguous associated constant `K` in bounds of `Trait0`
--> $DIR/assoc-const-eq-ambiguity.rs:9:25
|
LL | trait Parent0<T> { const K: (); }
| -----------
| |
| ambiguous `K` from `Parent0<u32>`
| ambiguous `K` from `Parent0<i32>`
LL |
LL | fn take0(_: impl Trait0<K = { () }>) {}
| ^^^^^^^^^^ ambiguous associated constant `K`
|
= help: consider introducing a new type parameter `T` and adding `where` constraints:
where
T: Trait0,
T: Parent0<u32>::K = { () },
T: Parent0<i32>::K = { () }
error[E0222]: ambiguous associated constant `C` in bounds of `Trait1`
--> $DIR/assoc-const-eq-ambiguity.rs:16:25
|
LL | trait Parent1 { const C: i32; }
| ------------ ambiguous `C` from `Parent1`
LL | trait Parent2 { const C: &'static str; }
| --------------------- ambiguous `C` from `Parent2`
LL |
LL | fn take1(_: impl Trait1<C = "?">) {}
| ^^^^^^^ ambiguous associated constant `C`
|
= help: consider introducing a new type parameter `T` and adding `where` constraints:
where
T: Trait1,
T: Parent2::C = "?",
T: Parent1::C = "?"
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0222`.

View File

@ -11,13 +11,12 @@ impl Foo for Bar {
const N: usize = 3;
}
fn foo1<F: Foo<Z=3>>() {}
//~^ ERROR associated type
fn foo2<F: Foo<Z=usize>>() {}
//~^ ERROR associated type
fn foo3<F: Foo<Z=5>>() {}
//~^ ERROR associated type
fn foo1<F: Foo<Z = 3>>() {}
//~^ ERROR associated constant `Z` not found for `Foo`
fn foo2<F: Foo<Z = usize>>() {}
//~^ ERROR associated type `Z` not found for `Foo`
fn foo3<F: Foo<Z = 5>>() {}
//~^ ERROR associated constant `Z` not found for `Foo`
fn main() {
foo1::<Bar>();

View File

@ -1,20 +1,20 @@
error[E0220]: associated type `Z` not found for `Foo`
--> $DIR/assoc-const-eq-missing.rs:15:16
error[E0220]: associated constant `Z` not found for `Foo`
--> $DIR/assoc-const-eq-missing.rs:14:16
|
LL | fn foo1<F: Foo<Z=3>>() {}
| ^ associated type `Z` not found
LL | fn foo1<F: Foo<Z = 3>>() {}
| ^ help: there is an associated constant with a similar name: `N`
error[E0220]: associated type `Z` not found for `Foo`
--> $DIR/assoc-const-eq-missing.rs:17:16
--> $DIR/assoc-const-eq-missing.rs:16:16
|
LL | fn foo2<F: Foo<Z=usize>>() {}
LL | fn foo2<F: Foo<Z = usize>>() {}
| ^ associated type `Z` not found
error[E0220]: associated type `Z` not found for `Foo`
--> $DIR/assoc-const-eq-missing.rs:19:16
error[E0220]: associated constant `Z` not found for `Foo`
--> $DIR/assoc-const-eq-missing.rs:18:16
|
LL | fn foo3<F: Foo<Z=5>>() {}
| ^ associated type `Z` not found
LL | fn foo3<F: Foo<Z = 5>>() {}
| ^ help: there is an associated constant with a similar name: `N`
error: aborting due to 3 previous errors

View File

@ -0,0 +1,21 @@
// Regression test for issue #112560.
// Respect the fact that (associated) types and constants live in different namespaces and
// therefore equality bounds involving identically named associated items don't conflict if
// their kind (type vs. const) differs.
// FIXME(fmease): Extend this test to cover supertraits again
// once #118040 is fixed. See initial version of PR #118360.
// check-pass
#![feature(associated_const_equality)]
trait Trait {
type N;
const N: usize;
}
fn take(_: impl Trait<N = 0, N = ()>) {}
fn main() {}

View File

@ -2,30 +2,30 @@
#![allow(unused)]
pub trait Foo {
const N: usize;
const N: usize;
}
pub trait FooTy {
type T;
type T;
}
pub struct Bar;
impl Foo for Bar {
const N: usize = 3;
const N: usize = 3;
}
impl FooTy for Bar {
type T = usize;
type T = usize;
}
fn foo<F: Foo<N=usize>>() {}
//~^ ERROR expected associated constant bound, found type
fn foo2<F: FooTy<T=3usize>>() {}
//~^ ERROR expected associated type bound, found constant
fn foo<F: Foo<N = usize>>() {}
//~^ ERROR expected constant, found type
fn foo2<F: FooTy<T = 3usize>>() {}
//~^ ERROR expected type, found constant
fn main() {
foo::<Bar>();
foo2::<Bar>();
foo::<Bar>();
foo2::<Bar>();
}

View File

@ -1,26 +1,30 @@
error: expected associated constant bound, found type
--> $DIR/assoc-const-ty-mismatch.rs:23:15
error: expected constant, found type
--> $DIR/assoc-const-ty-mismatch.rs:23:19
|
LL | fn foo<F: Foo<N=usize>>() {}
| ^^^^^^^
LL | fn foo<F: Foo<N = usize>>() {}
| - ^^^^^ unexpected type
| |
| expected a constant because of this associated constant
|
note: associated constant defined here
--> $DIR/assoc-const-ty-mismatch.rs:5:3
note: the associated constant is defined here
--> $DIR/assoc-const-ty-mismatch.rs:5:5
|
LL | const N: usize;
| ^^^^^^^^^^^^^^
LL | const N: usize;
| ^^^^^^^^^^^^^^
error: expected associated type bound, found constant
--> $DIR/assoc-const-ty-mismatch.rs:25:18
error: expected type, found constant
--> $DIR/assoc-const-ty-mismatch.rs:25:22
|
LL | fn foo2<F: FooTy<T=3usize>>() {}
| ^^^^^^^^
LL | fn foo2<F: FooTy<T = 3usize>>() {}
| - ^^^^^^ unexpected constant
| |
| expected a type because of this associated type
|
note: associated type defined here
--> $DIR/assoc-const-ty-mismatch.rs:9:3
note: the associated type is defined here
--> $DIR/assoc-const-ty-mismatch.rs:9:5
|
LL | type T;
| ^^^^^^
LL | type T;
| ^^^^^^
error: aborting due to 2 previous errors

View File

@ -17,7 +17,7 @@ trait Baz2: Foo {
trait Baz3 {
const BAR: usize;
const QUX: Self::BAR;
//~^ ERROR found associated const
//~^ ERROR expected type, found constant
}
fn main() {}

View File

@ -1,8 +1,14 @@
error: found associated const `BAR` when type was expected
--> $DIR/shadowed-const.rs:19:14
error: expected type, found constant
--> $DIR/shadowed-const.rs:19:20
|
LL | const QUX: Self::BAR;
| ^^^^^^^^^
| ^^^ unexpected constant
|
note: the associated constant is defined here
--> $DIR/shadowed-const.rs:18:3
|
LL | const BAR: usize;
| ^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error

View File

@ -1,7 +1,7 @@
#![feature(associated_type_bounds)]
pub fn accept(_: impl Trait<K: Copy>) {}
//~^ ERROR expected associated type, found associated constant
//~^ ERROR expected type, found constant
pub trait Trait {
const K: i32;

View File

@ -1,10 +1,16 @@
error: expected associated type, found associated constant
error: expected type, found constant
--> $DIR/consts.rs:3:29
|
LL | pub fn accept(_: impl Trait<K: Copy>) {}
| ^
| ^------ bounds are not allowed on associated constants
| |
| unexpected constant
|
= note: trait bounds not allowed on associated constant
note: the associated constant is defined here
--> $DIR/consts.rs:7:5
|
LL | const K: i32;
| ^^^^^^^^^^^^
error: aborting due to 1 previous error

View File

@ -1,5 +1,5 @@
fn get_iter(vec: &[i32]) -> impl Iterator<Item = {}> + '_ {
//~^ ERROR expected associated type bound, found constant
//~^ ERROR expected type, found constant
//~| ERROR associated const equality is incomplete
vec.iter()
}

View File

@ -7,13 +7,15 @@ LL | fn get_iter(vec: &[i32]) -> impl Iterator<Item = {}> + '_ {
= note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
= help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
error: expected associated type bound, found constant
--> $DIR/issue-99828.rs:1:43
error: expected type, found constant
--> $DIR/issue-99828.rs:1:50
|
LL | fn get_iter(vec: &[i32]) -> impl Iterator<Item = {}> + '_ {
| ^^^^^^^^^
| ---- ^^ unexpected constant
| |
| expected a type because of this associated type
|
note: associated type defined here
note: the associated type is defined here
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
error: aborting due to 2 previous errors

View File

@ -8,6 +8,6 @@ trait Trait {
}
fn bar<T: Trait<methid(): Send>>() {}
//~^ ERROR cannot find associated function `methid` for `Trait`
//~^ ERROR associated function `methid` not found for `Trait`
fn main() {}

View File

@ -7,11 +7,12 @@ LL | #![feature(return_type_notation)]
= note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
= note: `#[warn(incomplete_features)]` on by default
error: cannot find associated function `methid` for `Trait`
error[E0220]: associated function `methid` not found for `Trait`
--> $DIR/missing.rs:10:17
|
LL | fn bar<T: Trait<methid(): Send>>() {}
| ^^^^^^^^^^^^^^
| ^^^^^^ help: there is an associated function with a similar name: `method`
error: aborting due to 1 previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0220`.

View File

@ -23,7 +23,7 @@ impl Foo for () {}
fn test<T>()
where
T: Foo<test(): Send>,
//~^ ERROR ambiguous associated function `test` for `Foo`
//~^ ERROR ambiguous associated function `test` in bounds of `Foo`
{
}

View File

@ -7,13 +7,18 @@ LL | #![feature(return_type_notation)]
= note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
= note: `#[warn(incomplete_features)]` on by default
error: ambiguous associated function `test` for `Foo`
error[E0221]: ambiguous associated function `test` in bounds of `Foo`
--> $DIR/super-method-bound-ambig.rs:25:12
|
LL | async fn test();
| ---------------- ambiguous `test` from `for<'a> Super1<'a>`
...
LL | async fn test();
| ---------------- ambiguous `test` from `Super2`
...
LL | T: Foo<test(): Send>,
| ^^^^^^^^^^^^
|
= note: `test` is declared in two supertraits: `Super2` and `Super1<'a>`
| ^^^^^^^^^^^^ ambiguous associated function `test`
error: aborting due to 1 previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0221`.

View File

@ -9,9 +9,9 @@ pub trait Parse {
}
pub trait CoolStuff: Parse<MODE = Mode::Cool> {}
//~^ ERROR expected associated constant bound
//~| ERROR expected associated constant bound
//~| ERROR expected type
//~^ ERROR expected type, found variant
//~| ERROR expected constant, found type
//~| ERROR expected constant, found type
fn no_help() -> Mode::Cool {}
//~^ ERROR expected type, found variant

View File

@ -16,30 +16,42 @@ LL | fn no_help() -> Mode::Cool {}
| not a type
| help: try using the variant's enum: `Mode`
error: expected associated constant bound, found type
--> $DIR/assoc_const_eq_diagnostic.rs:11:28
error: expected constant, found type
--> $DIR/assoc_const_eq_diagnostic.rs:11:35
|
LL | pub trait CoolStuff: Parse<MODE = Mode::Cool> {}
| ^^^^^^^^^^^^^^^^^ help: if equating a const, try wrapping with braces: `MODE = { const }`
| ---- ^^^^^^^^^^ unexpected type
| |
| expected a constant because of this associated constant
|
note: associated constant defined here
note: the associated constant is defined here
--> $DIR/assoc_const_eq_diagnostic.rs:8:5
|
LL | const MODE: Mode;
| ^^^^^^^^^^^^^^^^
help: consider adding braces here
|
LL | pub trait CoolStuff: Parse<MODE = { Mode::Cool }> {}
| + +
error: expected associated constant bound, found type
--> $DIR/assoc_const_eq_diagnostic.rs:11:28
error: expected constant, found type
--> $DIR/assoc_const_eq_diagnostic.rs:11:35
|
LL | pub trait CoolStuff: Parse<MODE = Mode::Cool> {}
| ^^^^^^^^^^^^^^^^^ help: if equating a const, try wrapping with braces: `MODE = { const }`
| ---- ^^^^^^^^^^ unexpected type
| |
| expected a constant because of this associated constant
|
note: associated constant defined here
note: the associated constant is defined here
--> $DIR/assoc_const_eq_diagnostic.rs:8:5
|
LL | const MODE: Mode;
| ^^^^^^^^^^^^^^^^
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: consider adding braces here
|
LL | pub trait CoolStuff: Parse<MODE = { Mode::Cool }> {}
| + +
error: aborting due to 4 previous errors

View File

@ -28,7 +28,7 @@ LL | fn test() {
LL | let _: Self::Err;
| ^^^^^^^^^ ambiguous associated type `Err`
|
= note: associated type `Self` could derive from `FromStr`
= note: associated type `Err` could derive from `FromStr`
help: use fully-qualified syntax to disambiguate
|
LL | let _: <Self as My>::Err;

View File

@ -15,13 +15,18 @@ LL | fn foo<T: Trait<m(): Send>>() {}
| |
| help: remove these parentheses
error[E0220]: associated type `m` not found for `Trait`
error: expected type, found function
--> $DIR/feature-gate-return_type_notation.rs:14:17
|
LL | fn foo<T: Trait<m(): Send>>() {}
| ^ associated type `m` not found
| ^ unexpected function
|
note: the associated function is defined here
--> $DIR/feature-gate-return_type_notation.rs:10:5
|
LL | async fn m();
| ^^^^^^^^^^^^^
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0220, E0658.
For more information about an error, try `rustc --explain E0220`.
For more information about this error, try `rustc --explain E0658`.

View File

@ -14,7 +14,7 @@ trait Trait {
fn foo<T: Trait<m(): Send>>() {}
//[cfg]~^ ERROR return type notation is experimental
//[cfg]~| ERROR parenthesized generic arguments cannot be used in associated type constraints
//[cfg]~| ERROR associated type `m` not found for `Trait`
//[cfg]~| ERROR expected type, found function
//[no]~^^^^ WARN return type notation is experimental
//[no]~| WARN unstable syntax can change at any point in the future, causing a hard error!