Resolve assoc item bindings by namespace

If a const is expected, resolve a const.
If a type is expected, resolve a type.
Don't try to resolve a type first falling back to consts.
This commit is contained in:
León Orell Valerian Liehr 2023-11-24 09:53:10 +01:00
parent dd6126ef56
commit 55559d93e7
No known key found for this signature in database
GPG Key ID: D17A07215F68E713
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())
// 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 == 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");
.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 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(
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,
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,
E0222,
"ambiguous associated type `{}` in bounds of `{}`",
assoc_kind: assoc_kind_str,
assoc_name,
ty_param_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 {
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}`"));
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 {
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} = {constraint}",
" 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
//~^ ERROR associated constant `Z` not found for `Foo`
fn foo2<F: Foo<Z = usize>>() {}
//~^ ERROR associated type
//~^ ERROR associated type `Z` not found for `Foo`
fn foo3<F: Foo<Z = 5>>() {}
//~^ ERROR associated type
//~^ 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
| ^ 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>>() {}
| ^ 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
| ^ 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

@ -21,9 +21,9 @@ impl FooTy for Bar {
fn foo<F: Foo<N = usize>>() {}
//~^ ERROR expected associated constant bound, found type
//~^ ERROR expected constant, found type
fn foo2<F: FooTy<T = 3usize>>() {}
//~^ ERROR expected associated type bound, found constant
//~^ ERROR expected type, found constant
fn main() {
foo::<Bar>();

View File

@ -1,23 +1,27 @@
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>>() {}
| ^^^^^^^
| - ^^^^^ 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;
| ^^^^^^^^^^^^^^
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>>() {}
| ^^^^^^^^
| - ^^^^^^ 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;
| ^^^^^^

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!