mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-21 04:03:11 +00:00
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:
parent
dd6126ef56
commit
55559d93e7
@ -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 =
|
hir_analysis_ambiguous_lifetime_bound =
|
||||||
ambiguous lifetime bound, explicit lifetime bound required
|
ambiguous lifetime bound, explicit lifetime bound required
|
||||||
|
|
||||||
hir_analysis_assoc_bound_on_const = expected associated type, found {$descr}
|
hir_analysis_assoc_item_not_found = associated {$assoc_kind} `{$assoc_name}` not found for `{$ty_param_name}`
|
||||||
.note = trait bounds not allowed on {$descr}
|
|
||||||
|
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 =
|
hir_analysis_assoc_type_binding_not_allowed =
|
||||||
associated type bindings are not allowed here
|
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_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 =
|
hir_analysis_return_type_notation_equality_bound =
|
||||||
return type notation is not allowed to use type equality
|
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
|
return type notation is not allowed for functions that have type parameters
|
||||||
.label = type parameter declared here
|
.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 =
|
hir_analysis_return_type_notation_on_non_rpitit =
|
||||||
return type notation used on function that is not `async` and does not return `impl Trait`
|
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
|
.note = function returns `{$ty}`, which is not compatible with associated type return bounds
|
||||||
|
@ -3,8 +3,7 @@ use rustc_errors::struct_span_err;
|
|||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_lint_defs::Applicability;
|
use rustc_middle::ty::{self as ty, Ty};
|
||||||
use rustc_middle::ty::{self as ty, Ty, TypeVisitableExt};
|
|
||||||
use rustc_span::symbol::Ident;
|
use rustc_span::symbol::Ident;
|
||||||
use rustc_span::{ErrorGuaranteed, Span};
|
use rustc_span::{ErrorGuaranteed, Span};
|
||||||
use rustc_trait_selection::traits;
|
use rustc_trait_selection::traits;
|
||||||
@ -256,64 +255,49 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
|||||||
|
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
|
|
||||||
let return_type_notation =
|
let assoc_kind =
|
||||||
binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation;
|
if binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation {
|
||||||
|
ty::AssocKind::Fn
|
||||||
let candidate = if return_type_notation {
|
} else if let ConvertedBindingKind::Equality(term) = binding.kind
|
||||||
if self.trait_defines_associated_item_named(
|
&& let ty::TermKind::Const(_) = term.node.unpack()
|
||||||
trait_ref.def_id(),
|
{
|
||||||
ty::AssocKind::Fn,
|
ty::AssocKind::Const
|
||||||
binding.item_name,
|
|
||||||
) {
|
|
||||||
trait_ref
|
|
||||||
} else {
|
} else {
|
||||||
self.one_bound_for_assoc_method(
|
ty::AssocKind::Type
|
||||||
traits::supertraits(tcx, trait_ref),
|
};
|
||||||
trait_ref.print_only_trait_path(),
|
|
||||||
binding.item_name,
|
let candidate = if self.trait_defines_associated_item_named(
|
||||||
path_span,
|
|
||||||
)?
|
|
||||||
}
|
|
||||||
} else if self.trait_defines_associated_item_named(
|
|
||||||
trait_ref.def_id(),
|
trait_ref.def_id(),
|
||||||
ty::AssocKind::Type,
|
assoc_kind,
|
||||||
binding.item_name,
|
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
|
trait_ref
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, we have to walk through the supertraits to find
|
// Otherwise, we have to walk through the supertraits to find
|
||||||
// those that do.
|
// one that does define it.
|
||||||
self.one_bound_for_assoc_type(
|
self.one_bound_for_assoc_item(
|
||||||
|| traits::supertraits(tcx, trait_ref),
|
|| traits::supertraits(tcx, trait_ref),
|
||||||
trait_ref.skip_binder().print_only_trait_name(),
|
trait_ref.skip_binder().print_only_trait_name(),
|
||||||
None,
|
None,
|
||||||
|
assoc_kind,
|
||||||
binding.item_name,
|
binding.item_name,
|
||||||
path_span,
|
path_span,
|
||||||
match binding.kind {
|
Some(&binding),
|
||||||
ConvertedBindingKind::Equality(term) => Some(term),
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
)?
|
)?
|
||||||
};
|
};
|
||||||
|
|
||||||
let (assoc_ident, def_scope) =
|
let (assoc_ident, def_scope) =
|
||||||
tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id);
|
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
|
// We have already adjusted the item name above, so compare with `.normalize_to_macros_2_0()`
|
||||||
// of calling `filter_by_name_and_kind`.
|
// instead of calling `filter_by_name_and_kind` which would needlessly normalize the
|
||||||
let find_item_of_kind = |kind| {
|
// `assoc_ident` again and again.
|
||||||
tcx.associated_items(candidate.def_id())
|
let assoc_item = tcx
|
||||||
.filter_by_name_unhygienic(assoc_ident.name)
|
.associated_items(candidate.def_id())
|
||||||
.find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident)
|
.filter_by_name_unhygienic(assoc_ident.name)
|
||||||
};
|
.find(|i| i.kind == assoc_kind && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident)
|
||||||
let assoc_item = if return_type_notation {
|
.expect("missing associated item");
|
||||||
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");
|
|
||||||
|
|
||||||
if !assoc_item.visibility(tcx).is_accessible_from(def_scope, tcx) {
|
if !assoc_item.visibility(tcx).is_accessible_from(def_scope, tcx) {
|
||||||
tcx.sess
|
tcx.sess
|
||||||
@ -340,7 +324,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
|||||||
.or_insert(binding.span);
|
.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;
|
let mut emitted_bad_param_err = false;
|
||||||
// If we have an method return type bound, then we need to substitute
|
// If we have an method return type bound, then we need to substitute
|
||||||
// the method's early bound params with suitable late-bound params.
|
// 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 =
|
let late_bound_in_trait_ref =
|
||||||
tcx.collect_constrained_late_bound_regions(&projection_ty);
|
tcx.collect_constrained_late_bound_regions(&projection_ty);
|
||||||
let late_bound_in_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_trait_ref);
|
||||||
debug!(?late_bound_in_ty);
|
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 {
|
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(
|
return Err(self.tcx().sess.emit_err(
|
||||||
crate::errors::ReturnTypeNotationEqualityBound { span: binding.span },
|
crate::errors::ReturnTypeNotationEqualityBound { span: binding.span },
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
ConvertedBindingKind::Equality(mut term) => {
|
ConvertedBindingKind::Equality(term) => {
|
||||||
// "Desugar" a constraint like `T: Iterator<Item = u32>` this to
|
// "Desugar" a constraint like `T: Iterator<Item = u32>` this to
|
||||||
// the "projection predicate" for:
|
// the "projection predicate" for:
|
||||||
//
|
//
|
||||||
// `<T as Iterator>::Item = u32`
|
// `<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(
|
bounds.push_projection_bound(
|
||||||
tcx,
|
tcx,
|
||||||
projection_ty
|
projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate {
|
||||||
.map_bound(|projection_ty| ty::ProjectionPredicate { projection_ty, term }),
|
projection_ty,
|
||||||
|
term: term.node,
|
||||||
|
}),
|
||||||
binding.span,
|
binding.span,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ConvertedBindingKind::Constraint(ast_bounds) => {
|
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
|
// "Desugar" a constraint like `T: Iterator<Item: Debug>` to
|
||||||
//
|
//
|
||||||
// `<T as Iterator>::Item: Debug`
|
// `<T as Iterator>::Item: Debug`
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
use crate::astconv::AstConv;
|
use crate::astconv::{AstConv, ConvertedBindingKind};
|
||||||
use crate::errors::{
|
use crate::errors::{
|
||||||
AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
|
self, AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
|
||||||
ParenthesizedFnTraitExpansion,
|
ParenthesizedFnTraitExpansion,
|
||||||
};
|
};
|
||||||
|
use crate::fluent_generated as fluent;
|
||||||
use crate::traits::error_reporting::report_object_safety_error;
|
use crate::traits::error_reporting::report_object_safety_error;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
|
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
|
||||||
use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, ErrorGuaranteed};
|
use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, ErrorGuaranteed};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_infer::traits::FulfillmentError;
|
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_session::parse::feature_err;
|
||||||
use rustc_span::edit_distance::find_best_match_for_name;
|
use rustc_span::edit_distance::find_best_match_for_name;
|
||||||
use rustc_span::symbol::{sym, Ident};
|
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,
|
&self,
|
||||||
all_candidates: impl Fn() -> I,
|
all_candidates: impl Fn() -> I,
|
||||||
ty_param_name: &str,
|
ty_param_name: &str,
|
||||||
ty_param_def_id: Option<LocalDefId>,
|
ty_param_def_id: Option<LocalDefId>,
|
||||||
|
assoc_kind: ty::AssocKind,
|
||||||
assoc_name: Ident,
|
assoc_name: Ident,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
binding: Option<&super::ConvertedBinding<'_, 'tcx>>,
|
||||||
) -> ErrorGuaranteed
|
) -> ErrorGuaranteed
|
||||||
where
|
where
|
||||||
I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
|
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
|
// 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.
|
// valid span, so we point at the whole path segment instead.
|
||||||
let is_dummy = assoc_name.span == DUMMY_SP;
|
let is_dummy = assoc_name.span == DUMMY_SP;
|
||||||
|
|
||||||
let mut err = struct_span_err!(
|
let mut err = errors::AssocItemNotFound {
|
||||||
self.tcx().sess,
|
span: if is_dummy { span } else { assoc_name.span },
|
||||||
if is_dummy { span } else { assoc_name.span },
|
|
||||||
E0220,
|
|
||||||
"associated type `{}` not found for `{}`",
|
|
||||||
assoc_name,
|
assoc_name,
|
||||||
ty_param_name
|
assoc_kind: assoc_kind_str,
|
||||||
);
|
ty_param_name,
|
||||||
|
label: None,
|
||||||
|
sugg: None,
|
||||||
|
};
|
||||||
|
|
||||||
if is_dummy {
|
if is_dummy {
|
||||||
err.span_label(span, format!("associated type `{assoc_name}` not found"));
|
err.label = Some(errors::AssocItemNotFoundLabel::NotFound { span });
|
||||||
return err.emit();
|
return tcx.sess.emit_err(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
let all_candidate_names: Vec<_> = all_candidates()
|
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| {
|
.filter_map(|item| {
|
||||||
if !item.is_impl_trait_in_trait() && item.kind == ty::AssocKind::Type {
|
(!item.is_impl_trait_in_trait() && item.kind == assoc_kind).then_some(item.name)
|
||||||
Some(item.name)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if let Some(suggested_name) =
|
if let Some(suggested_name) =
|
||||||
find_best_match_for_name(&all_candidate_names, assoc_name.name, None)
|
find_best_match_for_name(&all_candidate_names, assoc_name.name, None)
|
||||||
{
|
{
|
||||||
err.span_suggestion(
|
err.sugg = Some(errors::AssocItemNotFoundSugg::Similar {
|
||||||
assoc_name.span,
|
span: assoc_name.span,
|
||||||
"there is an associated type with a similar name",
|
assoc_kind: assoc_kind_str,
|
||||||
suggested_name,
|
suggested_name,
|
||||||
Applicability::MaybeIncorrect,
|
});
|
||||||
);
|
return tcx.sess.emit_err(err);
|
||||||
return err.emit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we didn't find a good item in the supertraits (or couldn't get
|
// 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
|
// the supertraits), like in ItemCtxt, then look more generally from
|
||||||
// all visible traits. If there's one clear winner, just suggest that.
|
// all visible traits. If there's one clear winner, just suggest that.
|
||||||
|
|
||||||
let visible_traits: Vec<_> = self
|
let visible_traits: Vec<_> = tcx
|
||||||
.tcx()
|
|
||||||
.all_traits()
|
.all_traits()
|
||||||
.filter(|trait_def_id| {
|
.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();
|
let def_id = self.item_def_id();
|
||||||
viz.is_accessible_from(def_id, self.tcx())
|
viz.is_accessible_from(def_id, tcx)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let wider_candidate_names: Vec<_> = visible_traits
|
let wider_candidate_names: Vec<_> = visible_traits
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|trait_def_id| {
|
.flat_map(|trait_def_id| tcx.associated_items(*trait_def_id).in_definition_order())
|
||||||
self.tcx().associated_items(*trait_def_id).in_definition_order()
|
|
||||||
})
|
|
||||||
.filter_map(|item| {
|
.filter_map(|item| {
|
||||||
if !item.is_impl_trait_in_trait() && item.kind == ty::AssocKind::Type {
|
(!item.is_impl_trait_in_trait() && item.kind == assoc_kind).then_some(item.name)
|
||||||
Some(item.name)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
@ -182,52 +188,51 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
{
|
{
|
||||||
if let [best_trait] = visible_traits
|
if let [best_trait] = visible_traits
|
||||||
.iter()
|
.iter()
|
||||||
|
.copied()
|
||||||
.filter(|trait_def_id| {
|
.filter(|trait_def_id| {
|
||||||
self.tcx()
|
tcx.associated_items(trait_def_id)
|
||||||
.associated_items(*trait_def_id)
|
|
||||||
.filter_by_name_unhygienic(suggested_name)
|
.filter_by_name_unhygienic(suggested_name)
|
||||||
.any(|item| item.kind == ty::AssocKind::Type)
|
.any(|item| item.kind == assoc_kind)
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>()[..]
|
.collect::<Vec<_>>()[..]
|
||||||
{
|
{
|
||||||
let trait_name = self.tcx().def_path_str(*best_trait);
|
let trait_name = tcx.def_path_str(best_trait);
|
||||||
let an = if suggested_name != assoc_name.name { "a similarly named" } else { "an" };
|
err.label = Some(errors::AssocItemNotFoundLabel::FoundInOtherTrait {
|
||||||
err.span_label(
|
span: assoc_name.span,
|
||||||
assoc_name.span,
|
assoc_kind: assoc_kind_str,
|
||||||
format!(
|
trait_name: &trait_name,
|
||||||
"there is {an} associated type `{suggested_name}` in the \
|
suggested_name,
|
||||||
trait `{trait_name}`",
|
identically_named: suggested_name == assoc_name.name,
|
||||||
),
|
});
|
||||||
);
|
let hir = tcx.hir();
|
||||||
let hir = self.tcx().hir();
|
|
||||||
if let Some(def_id) = ty_param_def_id
|
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)
|
&& let Some(generics) = hir.get_generics(parent.def_id)
|
||||||
{
|
{
|
||||||
if generics.bounds_for_param(def_id).flat_map(|pred| pred.bounds.iter()).any(
|
if generics.bounds_for_param(def_id).flat_map(|pred| pred.bounds.iter()).any(
|
||||||
|b| match b {
|
|b| match b {
|
||||||
hir::GenericBound::Trait(t, ..) => {
|
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,
|
_ => false,
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
// The type param already has a bound for `trait_name`, we just need to
|
// The type param already has a bound for `trait_name`, we just need to
|
||||||
// change the associated type.
|
// change the associated item.
|
||||||
err.span_suggestion_verbose(
|
err.sugg = Some(errors::AssocItemNotFoundSugg::SimilarInOtherTrait {
|
||||||
assoc_name.span,
|
span: assoc_name.span,
|
||||||
format!(
|
assoc_kind: assoc_kind_str,
|
||||||
"change the associated type name to use `{suggested_name}` from \
|
suggested_name,
|
||||||
`{trait_name}`",
|
});
|
||||||
),
|
return tcx.sess.emit_err(err);
|
||||||
suggested_name.to_string(),
|
}
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
);
|
let mut err = tcx.sess.create_err(err);
|
||||||
} else if suggest_constraining_type_param(
|
if suggest_constraining_type_param(
|
||||||
self.tcx(),
|
tcx,
|
||||||
generics,
|
generics,
|
||||||
&mut err,
|
&mut err,
|
||||||
ty_param_name,
|
&ty_param_name,
|
||||||
&trait_name,
|
&trait_name,
|
||||||
None,
|
None,
|
||||||
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.
|
// was also not an exact match, so we also suggest changing it.
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
assoc_name.span,
|
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(),
|
suggested_name.to_string(),
|
||||||
Applicability::MaybeIncorrect,
|
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,
|
// If we still couldn't find any associated type, and only one associated type exists,
|
||||||
// suggests using it.
|
// suggests using it.
|
||||||
|
if let [candidate_name] = all_candidate_names.as_slice() {
|
||||||
if all_candidate_names.len() == 1 {
|
|
||||||
// this should still compile, except on `#![feature(associated_type_defaults)]`
|
// this should still compile, except on `#![feature(associated_type_defaults)]`
|
||||||
// where it could suggests `type A = Self::A`, thus recursing infinitely
|
// 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
|
Applicability::Unspecified
|
||||||
} else {
|
} else {
|
||||||
Applicability::MaybeIncorrect
|
Applicability::MaybeIncorrect
|
||||||
};
|
};
|
||||||
|
|
||||||
err.span_suggestion(
|
err.sugg = Some(errors::AssocItemNotFoundSugg::Other {
|
||||||
assoc_name.span,
|
span: assoc_name.span,
|
||||||
format!("`{ty_param_name}` has the following associated type"),
|
|
||||||
all_candidate_names.first().unwrap().to_string(),
|
|
||||||
applicability,
|
applicability,
|
||||||
);
|
ty_param_name,
|
||||||
|
assoc_kind: assoc_kind_str,
|
||||||
|
suggested_name: *candidate_name,
|
||||||
|
});
|
||||||
} else {
|
} 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(
|
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(
|
let assoc_item = tcx.associated_items(trait_def).find_by_name_and_kind(
|
||||||
tcx,
|
tcx,
|
||||||
ident,
|
ident,
|
||||||
AssocKind::Type,
|
ty::AssocKind::Type,
|
||||||
trait_def,
|
trait_def,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -606,7 +673,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
.flatten()
|
.flatten()
|
||||||
.collect::<FxHashMap<Symbol, &AssocItem>>();
|
.collect::<FxHashMap<Symbol, &ty::AssocItem>>();
|
||||||
|
|
||||||
let mut names = names
|
let mut names = names
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -18,8 +18,8 @@ use crate::require_c_abi_if_c_variadic;
|
|||||||
use rustc_ast::TraitObjectSyntax;
|
use rustc_ast::TraitObjectSyntax;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
use rustc_errors::{
|
use rustc_errors::{
|
||||||
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, FatalError,
|
error_code, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
|
||||||
MultiSpan,
|
FatalError, MultiSpan,
|
||||||
};
|
};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
|
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_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
|
||||||
use rustc_span::edit_distance::find_best_match_for_name;
|
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::symbol::{kw, Ident, Symbol};
|
||||||
use rustc_span::{sym, BytePos, Span, DUMMY_SP};
|
use rustc_span::{sym, BytePos, Span, DUMMY_SP};
|
||||||
use rustc_target::spec::abi;
|
use rustc_target::spec::abi;
|
||||||
@ -162,7 +163,7 @@ struct ConvertedBinding<'a, 'tcx> {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum ConvertedBindingKind<'a, 'tcx> {
|
enum ConvertedBindingKind<'a, 'tcx> {
|
||||||
Equality(ty::Term<'tcx>),
|
Equality(Spanned<ty::Term<'tcx>>),
|
||||||
Constraint(&'a [hir::GenericBound<'a>]),
|
Constraint(&'a [hir::GenericBound<'a>]),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -595,12 +596,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
.map(|binding| {
|
.map(|binding| {
|
||||||
let kind = match &binding.kind {
|
let kind = match &binding.kind {
|
||||||
hir::TypeBindingKind::Equality { term } => match term {
|
hir::TypeBindingKind::Equality { term } => match term {
|
||||||
hir::Term::Ty(ty) => {
|
hir::Term::Ty(ty) => ConvertedBindingKind::Equality(respan(
|
||||||
ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty).into())
|
ty.span,
|
||||||
}
|
self.ast_ty_to_ty(ty).into(),
|
||||||
|
)),
|
||||||
hir::Term::Const(c) => {
|
hir::Term::Const(c) => {
|
||||||
|
let span = self.tcx().def_span(c.def_id);
|
||||||
let c = Const::from_anon_const(self.tcx(), 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 } => {
|
hir::TypeBindingKind::Constraint { bounds } => {
|
||||||
@ -1056,7 +1059,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
debug!("find_bound_for_assoc_item: predicates={:#?}", predicates);
|
debug!("find_bound_for_assoc_item: predicates={:#?}", predicates);
|
||||||
|
|
||||||
let param_name = tcx.hir().ty_param_name(ty_param_def_id);
|
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(
|
traits::transitive_bounds_that_define_assoc_item(
|
||||||
tcx,
|
tcx,
|
||||||
@ -1068,6 +1071,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
},
|
},
|
||||||
param_name,
|
param_name,
|
||||||
Some(ty_param_def_id),
|
Some(ty_param_def_id),
|
||||||
|
ty::AssocKind::Type,
|
||||||
assoc_name,
|
assoc_name,
|
||||||
span,
|
span,
|
||||||
None,
|
None,
|
||||||
@ -1076,48 +1080,45 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
|
|
||||||
// Checks that `bounds` contains exactly one element and reports appropriate
|
// Checks that `bounds` contains exactly one element and reports appropriate
|
||||||
// errors otherwise.
|
// errors otherwise.
|
||||||
#[instrument(level = "debug", skip(self, all_candidates, ty_param_name, is_equality), ret)]
|
#[instrument(level = "debug", skip(self, all_candidates, ty_param_name, binding), ret)]
|
||||||
fn one_bound_for_assoc_type<I>(
|
fn one_bound_for_assoc_item<I>(
|
||||||
&self,
|
&self,
|
||||||
all_candidates: impl Fn() -> I,
|
all_candidates: impl Fn() -> I,
|
||||||
ty_param_name: impl Display,
|
ty_param_name: impl Display,
|
||||||
ty_param_def_id: Option<LocalDefId>,
|
ty_param_def_id: Option<LocalDefId>,
|
||||||
|
assoc_kind: ty::AssocKind,
|
||||||
assoc_name: Ident,
|
assoc_name: Ident,
|
||||||
span: Span,
|
span: Span,
|
||||||
is_equality: Option<ty::Term<'tcx>>,
|
binding: Option<&ConvertedBinding<'_, 'tcx>>,
|
||||||
) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed>
|
) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed>
|
||||||
where
|
where
|
||||||
I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
|
I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
|
||||||
{
|
{
|
||||||
|
let tcx = self.tcx();
|
||||||
|
|
||||||
let mut matching_candidates = all_candidates().filter(|r| {
|
let mut matching_candidates = all_candidates().filter(|r| {
|
||||||
self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Type, assoc_name)
|
self.trait_defines_associated_item_named(r.def_id(), assoc_kind, assoc_name)
|
||||||
});
|
|
||||||
let mut const_candidates = all_candidates().filter(|r| {
|
|
||||||
self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Const, assoc_name)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let (mut bound, mut next_cand) = match (matching_candidates.next(), const_candidates.next())
|
let Some(mut bound) = matching_candidates.next() else {
|
||||||
{
|
let reported = self.complain_about_assoc_item_not_found(
|
||||||
(Some(bound), _) => (bound, matching_candidates.next()),
|
all_candidates,
|
||||||
(None, Some(bound)) => (bound, const_candidates.next()),
|
&ty_param_name.to_string(),
|
||||||
(None, None) => {
|
ty_param_def_id,
|
||||||
let reported = self.complain_about_assoc_type_not_found(
|
assoc_kind,
|
||||||
all_candidates,
|
assoc_name,
|
||||||
&ty_param_name.to_string(),
|
span,
|
||||||
ty_param_def_id,
|
binding,
|
||||||
assoc_name,
|
);
|
||||||
span,
|
return Err(reported);
|
||||||
);
|
|
||||||
return Err(reported);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
debug!(?bound);
|
debug!(?bound);
|
||||||
|
|
||||||
// look for a candidate that is not the same as our first bound, disregarding
|
// look for a candidate that is not the same as our first bound, disregarding
|
||||||
// whether the bound is const.
|
// whether the bound is const.
|
||||||
|
let mut next_cand = matching_candidates.next();
|
||||||
while let Some(mut bound2) = next_cand {
|
while let Some(mut bound2) = next_cand {
|
||||||
debug!(?bound2);
|
debug!(?bound2);
|
||||||
let tcx = self.tcx();
|
|
||||||
if bound2.bound_vars() != bound.bound_vars() {
|
if bound2.bound_vars() != bound.bound_vars() {
|
||||||
break;
|
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 });
|
.map(|(n, arg)| if host_index == n { tcx.consts.true_.into() } else { arg });
|
||||||
|
|
||||||
if unconsted_args.eq(bound2.skip_binder().args.iter()) {
|
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 {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1147,48 +1148,53 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
if let Some(bound2) = next_cand {
|
if let Some(bound2) = next_cand {
|
||||||
debug!(?bound2);
|
debug!(?bound2);
|
||||||
|
|
||||||
let bounds = IntoIterator::into_iter([bound, bound2]).chain(matching_candidates);
|
let assoc_kind_str = assoc_kind_str(assoc_kind);
|
||||||
let mut err = if is_equality.is_some() {
|
let ty_param_name = &ty_param_name.to_string();
|
||||||
// More specific Error Index entry.
|
let mut err = tcx.sess.create_err(crate::errors::AmbiguousAssocItem {
|
||||||
struct_span_err!(
|
span,
|
||||||
self.tcx().sess,
|
assoc_kind: assoc_kind_str,
|
||||||
span,
|
assoc_name,
|
||||||
E0222,
|
ty_param_name,
|
||||||
"ambiguous associated type `{}` in bounds of `{}`",
|
});
|
||||||
assoc_name,
|
// Provide a more specific error code index entry for equality bindings.
|
||||||
ty_param_name
|
err.code(
|
||||||
)
|
if let Some(binding) = binding
|
||||||
} else {
|
&& let ConvertedBindingKind::Equality(_) = binding.kind
|
||||||
struct_span_err!(
|
{
|
||||||
self.tcx().sess,
|
error_code!(E0222)
|
||||||
span,
|
} else {
|
||||||
E0221,
|
error_code!(E0221)
|
||||||
"ambiguous associated type `{}` in bounds of `{}`",
|
},
|
||||||
assoc_name,
|
);
|
||||||
ty_param_name
|
|
||||||
)
|
|
||||||
};
|
|
||||||
err.span_label(span, format!("ambiguous associated type `{assoc_name}`"));
|
|
||||||
|
|
||||||
|
// FIXME(#97583): Resugar equality bounds to type/const bindings.
|
||||||
|
// FIXME: Turn this into a structured, translateable & more actionable suggestion.
|
||||||
let mut where_bounds = vec![];
|
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_id = bound.def_id();
|
||||||
let bound_span = self
|
let bound_span = tcx
|
||||||
.tcx()
|
|
||||||
.associated_items(bound_id)
|
.associated_items(bound_id)
|
||||||
.find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, bound_id)
|
.find_by_name_and_kind(tcx, assoc_name, assoc_kind, bound_id)
|
||||||
.and_then(|item| self.tcx().hir().span_if_local(item.def_id));
|
.and_then(|item| tcx.hir().span_if_local(item.def_id));
|
||||||
|
|
||||||
if let Some(bound_span) = bound_span {
|
if let Some(bound_span) = bound_span {
|
||||||
err.span_label(
|
err.span_label(
|
||||||
bound_span,
|
bound_span,
|
||||||
format!("ambiguous `{assoc_name}` from `{}`", bound.print_trait_sugared(),),
|
format!("ambiguous `{assoc_name}` from `{}`", bound.print_trait_sugared(),),
|
||||||
);
|
);
|
||||||
if let Some(constraint) = &is_equality {
|
if let Some(binding) = binding {
|
||||||
where_bounds.push(format!(
|
match binding.kind {
|
||||||
" T: {trait}::{assoc_name} = {constraint}",
|
ConvertedBindingKind::Equality(term) => {
|
||||||
trait=bound.print_only_trait_path(),
|
// 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 {
|
} else {
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
span.with_hi(assoc_name.span.lo()),
|
span.with_hi(assoc_name.span.lo()),
|
||||||
@ -1199,7 +1205,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err.note(format!(
|
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(),
|
bound.print_only_trait_path(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -1220,46 +1226,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
Ok(bound)
|
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.
|
// 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`
|
// 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
|
// 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);
|
return Err(guar);
|
||||||
};
|
};
|
||||||
|
|
||||||
self.one_bound_for_assoc_type(
|
self.one_bound_for_assoc_item(
|
||||||
|| {
|
|| {
|
||||||
traits::supertraits(
|
traits::supertraits(
|
||||||
tcx,
|
tcx,
|
||||||
@ -1430,6 +1396,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
},
|
},
|
||||||
kw::SelfUpper,
|
kw::SelfUpper,
|
||||||
None,
|
None,
|
||||||
|
ty::AssocKind::Type,
|
||||||
assoc_ident,
|
assoc_ident,
|
||||||
span,
|
span,
|
||||||
None,
|
None,
|
||||||
@ -1510,15 +1477,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let trait_did = bound.def_id();
|
let trait_did = bound.def_id();
|
||||||
let Some(assoc_ty_did) = self.lookup_assoc_ty(assoc_ident, hir_ref_id, span, trait_did)
|
let assoc_ty_did = self.lookup_assoc_ty(assoc_ident, hir_ref_id, span, trait_did).unwrap();
|
||||||
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 ty = self.projected_ty_from_poly_trait_ref(span, assoc_ty_did, assoc_segment, bound);
|
let ty = self.projected_ty_from_poly_trait_ref(span, assoc_ty_did, assoc_segment, bound);
|
||||||
|
|
||||||
if let Some(variant_def_id) = variant_resolution {
|
if let Some(variant_def_id) = variant_resolution {
|
||||||
@ -1731,8 +1690,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let (ident, def_scope) = tcx.adjust_ident_and_get_scope(name, scope, block);
|
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
|
// We have already adjusted the item name above, so compare with `.normalize_to_macros_2_0()`
|
||||||
// of calling `find_by_name_and_kind`.
|
// 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| {
|
let item = tcx.associated_items(scope).in_definition_order().find(|i| {
|
||||||
i.kind.namespace() == Namespace::TypeNS
|
i.kind.namespace() == Namespace::TypeNS
|
||||||
&& i.ident(tcx).normalize_to_macros_2_0() == ident
|
&& i.ident(tcx).normalize_to_macros_2_0() == ident
|
||||||
@ -2858,3 +2818,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
Some(r)
|
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",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,9 +6,121 @@ use rustc_errors::{
|
|||||||
MultiSpan,
|
MultiSpan,
|
||||||
};
|
};
|
||||||
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
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};
|
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)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(hir_analysis_unrecognized_atomic_operation, code = "E0092")]
|
#[diag(hir_analysis_unrecognized_atomic_operation, code = "E0092")]
|
||||||
pub struct UnrecognizedAtomicOperation<'a> {
|
pub struct UnrecognizedAtomicOperation<'a> {
|
||||||
@ -537,27 +649,6 @@ pub(crate) struct ReturnTypeNotationEqualityBound {
|
|||||||
pub span: Span,
|
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)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(hir_analysis_placeholder_not_allowed_item_signatures, code = "E0121")]
|
#[diag(hir_analysis_placeholder_not_allowed_item_signatures, code = "E0121")]
|
||||||
pub(crate) struct PlaceholderNotAllowedItemSignatures {
|
pub(crate) struct PlaceholderNotAllowedItemSignatures {
|
||||||
@ -954,15 +1045,6 @@ pub(crate) struct ReturnPositionImplTraitInTraitRefined<'tcx> {
|
|||||||
pub return_ty: Ty<'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)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(hir_analysis_inherent_ty_outside, code = "E0390")]
|
#[diag(hir_analysis_inherent_ty_outside, code = "E0390")]
|
||||||
#[help]
|
#[help]
|
||||||
|
19
tests/ui/associated-consts/assoc-const-eq-ambiguity.rs
Normal file
19
tests/ui/associated-consts/assoc-const-eq-ambiguity.rs
Normal 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() {}
|
38
tests/ui/associated-consts/assoc-const-eq-ambiguity.stderr
Normal file
38
tests/ui/associated-consts/assoc-const-eq-ambiguity.stderr
Normal 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`.
|
@ -11,13 +11,12 @@ impl Foo for Bar {
|
|||||||
const N: usize = 3;
|
const N: usize = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn foo1<F: Foo<Z = 3>>() {}
|
||||||
fn foo1<F: Foo<Z=3>>() {}
|
//~^ ERROR associated constant `Z` not found for `Foo`
|
||||||
//~^ ERROR associated type
|
fn foo2<F: Foo<Z = usize>>() {}
|
||||||
fn foo2<F: Foo<Z=usize>>() {}
|
//~^ ERROR associated type `Z` not found for `Foo`
|
||||||
//~^ ERROR associated type
|
fn foo3<F: Foo<Z = 5>>() {}
|
||||||
fn foo3<F: Foo<Z=5>>() {}
|
//~^ ERROR associated constant `Z` not found for `Foo`
|
||||||
//~^ ERROR associated type
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
foo1::<Bar>();
|
foo1::<Bar>();
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
error[E0220]: associated type `Z` not found for `Foo`
|
error[E0220]: associated constant `Z` not found for `Foo`
|
||||||
--> $DIR/assoc-const-eq-missing.rs:15:16
|
--> $DIR/assoc-const-eq-missing.rs:14:16
|
||||||
|
|
|
|
||||||
LL | fn foo1<F: Foo<Z=3>>() {}
|
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`
|
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
|
| ^ associated type `Z` not found
|
||||||
|
|
||||||
error[E0220]: associated type `Z` not found for `Foo`
|
error[E0220]: associated constant `Z` not found for `Foo`
|
||||||
--> $DIR/assoc-const-eq-missing.rs:19:16
|
--> $DIR/assoc-const-eq-missing.rs:18:16
|
||||||
|
|
|
|
||||||
LL | fn foo3<F: Foo<Z=5>>() {}
|
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
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
@ -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() {}
|
@ -2,30 +2,30 @@
|
|||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
|
|
||||||
pub trait Foo {
|
pub trait Foo {
|
||||||
const N: usize;
|
const N: usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FooTy {
|
pub trait FooTy {
|
||||||
type T;
|
type T;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Bar;
|
pub struct Bar;
|
||||||
|
|
||||||
impl Foo for Bar {
|
impl Foo for Bar {
|
||||||
const N: usize = 3;
|
const N: usize = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FooTy for Bar {
|
impl FooTy for Bar {
|
||||||
type T = usize;
|
type T = usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn foo<F: Foo<N=usize>>() {}
|
fn foo<F: Foo<N = usize>>() {}
|
||||||
//~^ ERROR expected associated constant bound, found type
|
//~^ ERROR expected constant, found type
|
||||||
fn foo2<F: FooTy<T=3usize>>() {}
|
fn foo2<F: FooTy<T = 3usize>>() {}
|
||||||
//~^ ERROR expected associated type bound, found constant
|
//~^ ERROR expected type, found constant
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
foo::<Bar>();
|
foo::<Bar>();
|
||||||
foo2::<Bar>();
|
foo2::<Bar>();
|
||||||
}
|
}
|
||||||
|
@ -1,26 +1,30 @@
|
|||||||
error: expected associated constant bound, found type
|
error: expected constant, found type
|
||||||
--> $DIR/assoc-const-ty-mismatch.rs:23:15
|
--> $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
|
note: the associated constant is defined here
|
||||||
--> $DIR/assoc-const-ty-mismatch.rs:5:3
|
--> $DIR/assoc-const-ty-mismatch.rs:5:5
|
||||||
|
|
|
|
||||||
LL | const N: usize;
|
LL | const N: usize;
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: expected associated type bound, found constant
|
error: expected type, found constant
|
||||||
--> $DIR/assoc-const-ty-mismatch.rs:25:18
|
--> $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
|
note: the associated type is defined here
|
||||||
--> $DIR/assoc-const-ty-mismatch.rs:9:3
|
--> $DIR/assoc-const-ty-mismatch.rs:9:5
|
||||||
|
|
|
|
||||||
LL | type T;
|
LL | type T;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ trait Baz2: Foo {
|
|||||||
trait Baz3 {
|
trait Baz3 {
|
||||||
const BAR: usize;
|
const BAR: usize;
|
||||||
const QUX: Self::BAR;
|
const QUX: Self::BAR;
|
||||||
//~^ ERROR found associated const
|
//~^ ERROR expected type, found constant
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
error: found associated const `BAR` when type was expected
|
error: expected type, found constant
|
||||||
--> $DIR/shadowed-const.rs:19:14
|
--> $DIR/shadowed-const.rs:19:20
|
||||||
|
|
|
|
||||||
LL | const QUX: Self::BAR;
|
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
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#![feature(associated_type_bounds)]
|
#![feature(associated_type_bounds)]
|
||||||
|
|
||||||
pub fn accept(_: impl Trait<K: Copy>) {}
|
pub fn accept(_: impl Trait<K: Copy>) {}
|
||||||
//~^ ERROR expected associated type, found associated constant
|
//~^ ERROR expected type, found constant
|
||||||
|
|
||||||
pub trait Trait {
|
pub trait Trait {
|
||||||
const K: i32;
|
const K: i32;
|
||||||
|
@ -1,10 +1,16 @@
|
|||||||
error: expected associated type, found associated constant
|
error: expected type, found constant
|
||||||
--> $DIR/consts.rs:3:29
|
--> $DIR/consts.rs:3:29
|
||||||
|
|
|
|
||||||
LL | pub fn accept(_: impl Trait<K: Copy>) {}
|
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
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
fn get_iter(vec: &[i32]) -> impl Iterator<Item = {}> + '_ {
|
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
|
//~| ERROR associated const equality is incomplete
|
||||||
vec.iter()
|
vec.iter()
|
||||||
}
|
}
|
||||||
|
@ -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
|
= 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
|
= help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
|
||||||
|
|
||||||
error: expected associated type bound, found constant
|
error: expected type, found constant
|
||||||
--> $DIR/issue-99828.rs:1:43
|
--> $DIR/issue-99828.rs:1:50
|
||||||
|
|
|
|
||||||
LL | fn get_iter(vec: &[i32]) -> impl Iterator<Item = {}> + '_ {
|
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
|
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
@ -8,6 +8,6 @@ trait Trait {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn bar<T: Trait<methid(): Send>>() {}
|
fn bar<T: Trait<methid(): Send>>() {}
|
||||||
//~^ ERROR cannot find associated function `methid` for `Trait`
|
//~^ ERROR associated function `methid` not found for `Trait`
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
@ -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: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
|
||||||
= note: `#[warn(incomplete_features)]` on by default
|
= 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
|
--> $DIR/missing.rs:10:17
|
||||||
|
|
|
|
||||||
LL | fn bar<T: Trait<methid(): Send>>() {}
|
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
|
error: aborting due to 1 previous error; 1 warning emitted
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0220`.
|
||||||
|
@ -23,7 +23,7 @@ impl Foo for () {}
|
|||||||
fn test<T>()
|
fn test<T>()
|
||||||
where
|
where
|
||||||
T: Foo<test(): Send>,
|
T: Foo<test(): Send>,
|
||||||
//~^ ERROR ambiguous associated function `test` for `Foo`
|
//~^ ERROR ambiguous associated function `test` in bounds of `Foo`
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
|
||||||
= note: `#[warn(incomplete_features)]` on by default
|
= 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
|
--> $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>,
|
LL | T: Foo<test(): Send>,
|
||||||
| ^^^^^^^^^^^^
|
| ^^^^^^^^^^^^ ambiguous associated function `test`
|
||||||
|
|
|
||||||
= note: `test` is declared in two supertraits: `Super2` and `Super1<'a>`
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error; 1 warning emitted
|
error: aborting due to 1 previous error; 1 warning emitted
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0221`.
|
||||||
|
@ -9,9 +9,9 @@ pub trait Parse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait CoolStuff: Parse<MODE = Mode::Cool> {}
|
pub trait CoolStuff: Parse<MODE = Mode::Cool> {}
|
||||||
//~^ ERROR expected associated constant bound
|
//~^ ERROR expected type, found variant
|
||||||
//~| ERROR expected associated constant bound
|
//~| ERROR expected constant, found type
|
||||||
//~| ERROR expected type
|
//~| ERROR expected constant, found type
|
||||||
|
|
||||||
fn no_help() -> Mode::Cool {}
|
fn no_help() -> Mode::Cool {}
|
||||||
//~^ ERROR expected type, found variant
|
//~^ ERROR expected type, found variant
|
||||||
|
@ -16,30 +16,42 @@ LL | fn no_help() -> Mode::Cool {}
|
|||||||
| not a type
|
| not a type
|
||||||
| help: try using the variant's enum: `Mode`
|
| help: try using the variant's enum: `Mode`
|
||||||
|
|
||||||
error: expected associated constant bound, found type
|
error: expected constant, found type
|
||||||
--> $DIR/assoc_const_eq_diagnostic.rs:11:28
|
--> $DIR/assoc_const_eq_diagnostic.rs:11:35
|
||||||
|
|
|
|
||||||
LL | pub trait CoolStuff: Parse<MODE = Mode::Cool> {}
|
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
|
--> $DIR/assoc_const_eq_diagnostic.rs:8:5
|
||||||
|
|
|
|
||||||
LL | const MODE: Mode;
|
LL | const MODE: Mode;
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
help: consider adding braces here
|
||||||
|
|
|
||||||
|
LL | pub trait CoolStuff: Parse<MODE = { Mode::Cool }> {}
|
||||||
|
| + +
|
||||||
|
|
||||||
error: expected associated constant bound, found type
|
error: expected constant, found type
|
||||||
--> $DIR/assoc_const_eq_diagnostic.rs:11:28
|
--> $DIR/assoc_const_eq_diagnostic.rs:11:35
|
||||||
|
|
|
|
||||||
LL | pub trait CoolStuff: Parse<MODE = Mode::Cool> {}
|
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
|
--> $DIR/assoc_const_eq_diagnostic.rs:8:5
|
||||||
|
|
|
|
||||||
LL | const MODE: Mode;
|
LL | const MODE: Mode;
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
= 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
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ LL | fn test() {
|
|||||||
LL | let _: Self::Err;
|
LL | let _: Self::Err;
|
||||||
| ^^^^^^^^^ ambiguous associated type `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
|
help: use fully-qualified syntax to disambiguate
|
||||||
|
|
|
|
||||||
LL | let _: <Self as My>::Err;
|
LL | let _: <Self as My>::Err;
|
||||||
|
@ -15,13 +15,18 @@ LL | fn foo<T: Trait<m(): Send>>() {}
|
|||||||
| |
|
| |
|
||||||
| help: remove these parentheses
|
| 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
|
--> $DIR/feature-gate-return_type_notation.rs:14:17
|
||||||
|
|
|
|
||||||
LL | fn foo<T: Trait<m(): Send>>() {}
|
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
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
Some errors have detailed explanations: E0220, E0658.
|
For more information about this error, try `rustc --explain E0658`.
|
||||||
For more information about an error, try `rustc --explain E0220`.
|
|
||||||
|
@ -14,7 +14,7 @@ trait Trait {
|
|||||||
fn foo<T: Trait<m(): Send>>() {}
|
fn foo<T: Trait<m(): Send>>() {}
|
||||||
//[cfg]~^ ERROR return type notation is experimental
|
//[cfg]~^ ERROR return type notation is experimental
|
||||||
//[cfg]~| ERROR parenthesized generic arguments cannot be used in associated type constraints
|
//[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 return type notation is experimental
|
||||||
//[no]~| WARN unstable syntax can change at any point in the future, causing a hard error!
|
//[no]~| WARN unstable syntax can change at any point in the future, causing a hard error!
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user