HIR ty lowering: Refactor the way the projectee ("QSelf") gets passed to diagnostics
This commit is contained in:
parent
ef121f28d8
commit
898448ca58
@ -1,4 +1,4 @@
|
||||
hir_analysis_ambiguous_assoc_item = ambiguous associated {$assoc_kind} `{$assoc_name}` in bounds of `{$ty_param_name}`
|
||||
hir_analysis_ambiguous_assoc_item = ambiguous associated {$assoc_kind} `{$assoc_name}` in bounds of `{$qself}`
|
||||
.label = ambiguous associated {$assoc_kind} `{$assoc_name}`
|
||||
|
||||
hir_analysis_ambiguous_lifetime_bound =
|
||||
@ -12,14 +12,14 @@ hir_analysis_assoc_item_is_private = {$kind} `{$name}` is private
|
||||
.label = private {$kind}
|
||||
.defined_here_label = the {$kind} is defined here
|
||||
|
||||
hir_analysis_assoc_item_not_found = associated {$assoc_kind} `{$assoc_name}` not found for `{$ty_param_name}`
|
||||
hir_analysis_assoc_item_not_found = associated {$assoc_kind} `{$assoc_name}` not found for `{$qself}`
|
||||
|
||||
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_other_sugg = `{$qself}` 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
|
||||
|
@ -22,7 +22,7 @@ pub struct AmbiguousAssocItem<'a> {
|
||||
pub span: Span,
|
||||
pub assoc_kind: &'static str,
|
||||
pub assoc_name: Ident,
|
||||
pub ty_param_name: &'a str,
|
||||
pub qself: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
@ -75,7 +75,7 @@ pub struct AssocItemNotFound<'a> {
|
||||
pub span: Span,
|
||||
pub assoc_name: Ident,
|
||||
pub assoc_kind: &'static str,
|
||||
pub ty_param_name: &'a str,
|
||||
pub qself: &'a str,
|
||||
#[subdiagnostic]
|
||||
pub label: Option<AssocItemNotFoundLabel<'a>>,
|
||||
#[subdiagnostic]
|
||||
@ -134,7 +134,7 @@ pub enum AssocItemNotFoundSugg<'a> {
|
||||
Other {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
ty_param_name: &'a str,
|
||||
qself: &'a str,
|
||||
assoc_kind: &'static str,
|
||||
suggested_name: Symbol,
|
||||
},
|
||||
|
@ -6,7 +6,6 @@
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::print::PrintTraitRefExt as _;
|
||||
use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TyCtxt};
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::{ErrorGuaranteed, Span, Symbol};
|
||||
@ -16,9 +15,8 @@
|
||||
|
||||
use crate::bounds::Bounds;
|
||||
use crate::errors;
|
||||
use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter};
|
||||
|
||||
use super::RegionInferReason;
|
||||
use crate::hir_ty_lowering::HirTyLowerer;
|
||||
use crate::hir_ty_lowering::{AssocItemQSelf, OnlySelfBounds, PredicateFilter, RegionInferReason};
|
||||
|
||||
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
/// Add a `Sized` bound to the `bounds` if appropriate.
|
||||
@ -288,8 +286,7 @@ pub(super) fn lower_assoc_item_constraint(
|
||||
// one that does define it.
|
||||
self.probe_single_bound_for_assoc_item(
|
||||
|| traits::supertraits(tcx, trait_ref),
|
||||
trait_ref.skip_binder().print_only_trait_name(),
|
||||
None,
|
||||
AssocItemQSelf::Trait(trait_ref.def_id()),
|
||||
assoc_kind,
|
||||
constraint.ident,
|
||||
path_span,
|
||||
|
@ -3,7 +3,7 @@
|
||||
ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits,
|
||||
};
|
||||
use crate::fluent_generated as fluent;
|
||||
use crate::hir_ty_lowering::HirTyLowerer;
|
||||
use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer};
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
use rustc_data_structures::unord::UnordMap;
|
||||
@ -11,9 +11,9 @@
|
||||
use rustc_errors::{
|
||||
codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::{self as hir, Node};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::query::Key;
|
||||
use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _};
|
||||
@ -116,8 +116,7 @@ pub(crate) fn complain_about_internal_fn_trait(
|
||||
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>,
|
||||
qself: AssocItemQSelf,
|
||||
assoc_kind: ty::AssocKind,
|
||||
assoc_name: Ident,
|
||||
span: Span,
|
||||
@ -139,7 +138,8 @@ pub(super) fn complain_about_assoc_item_not_found<I>(
|
||||
);
|
||||
}
|
||||
|
||||
let assoc_kind_str = super::assoc_kind_str(assoc_kind);
|
||||
let assoc_kind_str = assoc_kind_str(assoc_kind);
|
||||
let qself_str = qself.to_string(tcx);
|
||||
|
||||
// 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.
|
||||
@ -149,7 +149,7 @@ pub(super) fn complain_about_assoc_item_not_found<I>(
|
||||
span: if is_dummy { span } else { assoc_name.span },
|
||||
assoc_name,
|
||||
assoc_kind: assoc_kind_str,
|
||||
ty_param_name,
|
||||
qself: &qself_str,
|
||||
label: None,
|
||||
sugg: None,
|
||||
};
|
||||
@ -219,19 +219,28 @@ pub(super) fn complain_about_assoc_item_not_found<I>(
|
||||
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(tcx.local_def_id_to_hir_id(def_id))
|
||||
&& let Some(generics) = hir.get_generics(parent.def_id)
|
||||
if let AssocItemQSelf::TyParam(ty_param_def_id) = qself
|
||||
// Not using `self.item_def_id()` here as that would yield the opaque type itself if we're
|
||||
// inside an opaque type while we're interested in the overarching type alias (TAIT).
|
||||
// FIXME: However, for trait aliases, this incorrectly returns the enclosing module...
|
||||
&& let item_def_id =
|
||||
tcx.hir().get_parent_item(tcx.local_def_id_to_hir_id(ty_param_def_id))
|
||||
// FIXME: ...which obviously won't have any generics.
|
||||
&& let Some(generics) = tcx.hir().get_generics(item_def_id.def_id)
|
||||
{
|
||||
if generics.bounds_for_param(def_id).flat_map(|pred| pred.bounds.iter()).any(
|
||||
|b| match b {
|
||||
// FIXME: Suggest adding supertrait bounds if we have a `Self` type param.
|
||||
// FIXME(trait_alias): Suggest adding `Self: Trait` to
|
||||
// `trait Alias = where Self::Proj:;` with `trait Trait { type Proj; }`.
|
||||
if generics
|
||||
.bounds_for_param(ty_param_def_id)
|
||||
.flat_map(|pred| pred.bounds.iter())
|
||||
.any(|b| match b {
|
||||
hir::GenericBound::Trait(t, ..) => {
|
||||
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 item.
|
||||
err.sugg = Some(errors::AssocItemNotFoundSugg::SimilarInOtherTrait {
|
||||
@ -247,7 +256,7 @@ pub(super) fn complain_about_assoc_item_not_found<I>(
|
||||
tcx,
|
||||
generics,
|
||||
&mut err,
|
||||
&ty_param_name,
|
||||
&qself_str,
|
||||
&trait_name,
|
||||
None,
|
||||
None,
|
||||
@ -273,7 +282,7 @@ pub(super) fn complain_about_assoc_item_not_found<I>(
|
||||
if let [candidate_name] = all_candidate_names.as_slice() {
|
||||
err.sugg = Some(errors::AssocItemNotFoundSugg::Other {
|
||||
span: assoc_name.span,
|
||||
ty_param_name,
|
||||
qself: &qself_str,
|
||||
assoc_kind: assoc_kind_str,
|
||||
suggested_name: *candidate_name,
|
||||
});
|
||||
@ -339,10 +348,10 @@ fn complain_about_assoc_kind_mismatch(
|
||||
|
||||
self.dcx().emit_err(errors::AssocKindMismatch {
|
||||
span,
|
||||
expected: super::assoc_kind_str(expected),
|
||||
got: super::assoc_kind_str(got),
|
||||
expected: assoc_kind_str(expected),
|
||||
got: assoc_kind_str(got),
|
||||
expected_because_label,
|
||||
assoc_kind: super::assoc_kind_str(assoc_item.kind),
|
||||
assoc_kind: assoc_kind_str(assoc_item.kind),
|
||||
def_span: tcx.def_span(assoc_item.def_id),
|
||||
bound_on_assoc_const_label,
|
||||
wrap_in_braces_sugg,
|
||||
@ -736,7 +745,7 @@ pub(crate) fn complain_about_missing_assoc_tys(
|
||||
if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) {
|
||||
let grandparent = tcx.parent_hir_node(tcx.parent_hir_id(bound.trait_ref.hir_ref_id));
|
||||
in_expr_or_pat = match grandparent {
|
||||
Node::Expr(_) | Node::Pat(_) => true,
|
||||
hir::Node::Expr(_) | hir::Node::Pat(_) => true,
|
||||
_ => false,
|
||||
};
|
||||
match bound.trait_ref.path.segments {
|
||||
@ -1602,3 +1611,11 @@ fn generics_args_err_extend<'a>(
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn assoc_kind_str(kind: ty::AssocKind) -> &'static str {
|
||||
match kind {
|
||||
ty::AssocKind::Fn => "function",
|
||||
ty::AssocKind::Const => "constant",
|
||||
ty::AssocKind::Type => "type",
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,6 @@
|
||||
use rustc_trait_selection::traits::wf::object_region_bounds;
|
||||
use rustc_trait_selection::traits::{self, ObligationCtxt};
|
||||
|
||||
use std::fmt::Display;
|
||||
use std::slice;
|
||||
|
||||
/// A path segment that is semantically allowed to have generic arguments.
|
||||
@ -193,6 +192,25 @@ fn lowerer(&self) -> &dyn HirTyLowerer<'tcx>
|
||||
}
|
||||
}
|
||||
|
||||
/// The "qualified self" of an associated item path.
|
||||
///
|
||||
/// For diagnostic purposes only.
|
||||
enum AssocItemQSelf {
|
||||
Trait(DefId),
|
||||
TyParam(LocalDefId),
|
||||
SelfTyAlias,
|
||||
}
|
||||
|
||||
impl AssocItemQSelf {
|
||||
fn to_string(&self, tcx: TyCtxt<'_>) -> String {
|
||||
match *self {
|
||||
Self::Trait(def_id) => tcx.def_path_str(def_id),
|
||||
Self::TyParam(def_id) => tcx.hir().ty_param_name(def_id).to_string(),
|
||||
Self::SelfTyAlias => kw::SelfUpper.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// New-typed boolean indicating whether explicit late-bound lifetimes
|
||||
/// are present in a set of generic arguments.
|
||||
///
|
||||
@ -811,19 +829,14 @@ fn probe_single_ty_param_bound_for_assoc_ty(
|
||||
let predicates = &self.probe_ty_param_bounds(span, ty_param_def_id, assoc_name).predicates;
|
||||
debug!("predicates={:#?}", predicates);
|
||||
|
||||
let param_name = tcx.hir().ty_param_name(ty_param_def_id);
|
||||
self.probe_single_bound_for_assoc_item(
|
||||
|| {
|
||||
traits::transitive_bounds_that_define_assoc_item(
|
||||
tcx,
|
||||
predicates
|
||||
.iter()
|
||||
.filter_map(|(p, _)| Some(p.as_trait_clause()?.map_bound(|t| t.trait_ref))),
|
||||
assoc_name,
|
||||
)
|
||||
let trait_refs = predicates
|
||||
.iter()
|
||||
.filter_map(|(p, _)| Some(p.as_trait_clause()?.map_bound(|t| t.trait_ref)));
|
||||
traits::transitive_bounds_that_define_assoc_item(tcx, trait_refs, assoc_name)
|
||||
},
|
||||
param_name,
|
||||
Some(ty_param_def_id),
|
||||
AssocItemQSelf::TyParam(ty_param_def_id),
|
||||
ty::AssocKind::Type,
|
||||
assoc_name,
|
||||
span,
|
||||
@ -835,12 +848,11 @@ fn probe_single_ty_param_bound_for_assoc_ty(
|
||||
///
|
||||
/// This fails if there is no such bound in the list of candidates or if there are multiple
|
||||
/// candidates in which case it reports ambiguity.
|
||||
#[instrument(level = "debug", skip(self, all_candidates, ty_param_name, constraint), ret)]
|
||||
#[instrument(level = "debug", skip(self, all_candidates, qself, constraint), ret)]
|
||||
fn probe_single_bound_for_assoc_item<I>(
|
||||
&self,
|
||||
all_candidates: impl Fn() -> I,
|
||||
ty_param_name: impl Display,
|
||||
ty_param_def_id: Option<LocalDefId>,
|
||||
qself: AssocItemQSelf,
|
||||
assoc_kind: ty::AssocKind,
|
||||
assoc_name: Ident,
|
||||
span: Span,
|
||||
@ -858,8 +870,7 @@ fn probe_single_bound_for_assoc_item<I>(
|
||||
let Some(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,
|
||||
qself,
|
||||
assoc_kind,
|
||||
assoc_name,
|
||||
span,
|
||||
@ -872,13 +883,13 @@ fn probe_single_bound_for_assoc_item<I>(
|
||||
if let Some(bound2) = matching_candidates.next() {
|
||||
debug!(?bound2);
|
||||
|
||||
let assoc_kind_str = assoc_kind_str(assoc_kind);
|
||||
let ty_param_name = &ty_param_name.to_string();
|
||||
let assoc_kind_str = errors::assoc_kind_str(assoc_kind);
|
||||
let qself_str = qself.to_string(tcx);
|
||||
let mut err = self.dcx().create_err(crate::errors::AmbiguousAssocItem {
|
||||
span,
|
||||
assoc_kind: assoc_kind_str,
|
||||
assoc_name,
|
||||
ty_param_name,
|
||||
qself: &qself_str,
|
||||
});
|
||||
// Provide a more specific error code index entry for equality bindings.
|
||||
err.code(
|
||||
@ -929,7 +940,7 @@ trait = bound.print_only_trait_path(),
|
||||
err.span_suggestion_verbose(
|
||||
span.with_hi(assoc_name.span.lo()),
|
||||
"use fully-qualified syntax to disambiguate",
|
||||
format!("<{ty_param_name} as {}>::", bound.print_only_trait_path()),
|
||||
format!("<{qself_str} as {}>::", bound.print_only_trait_path()),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
@ -943,7 +954,7 @@ trait = bound.print_only_trait_path(),
|
||||
if !where_bounds.is_empty() {
|
||||
err.help(format!(
|
||||
"consider introducing a new type parameter `T` and adding `where` constraints:\
|
||||
\n where\n T: {ty_param_name},\n{}",
|
||||
\n where\n T: {qself_str},\n{}",
|
||||
where_bounds.join(",\n"),
|
||||
));
|
||||
}
|
||||
@ -997,11 +1008,6 @@ pub fn lower_assoc_path(
|
||||
let tcx = self.tcx();
|
||||
|
||||
let assoc_ident = assoc_segment.ident;
|
||||
let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
|
||||
path.res
|
||||
} else {
|
||||
Res::Err
|
||||
};
|
||||
|
||||
// Check if we have an enum variant or an inherent associated type.
|
||||
let mut variant_resolution = None;
|
||||
@ -1038,6 +1044,12 @@ pub fn lower_assoc_path(
|
||||
}
|
||||
}
|
||||
|
||||
let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
|
||||
path.res
|
||||
} else {
|
||||
Res::Err
|
||||
};
|
||||
|
||||
// Find the type of the associated item, and the trait where the associated
|
||||
// item is declared.
|
||||
let bound = match (&qself_ty.kind(), qself_res) {
|
||||
@ -1056,8 +1068,7 @@ pub fn lower_assoc_path(
|
||||
ty::Binder::dummy(trait_ref.instantiate_identity()),
|
||||
)
|
||||
},
|
||||
kw::SelfUpper,
|
||||
None,
|
||||
AssocItemQSelf::SelfTyAlias,
|
||||
ty::AssocKind::Type,
|
||||
assoc_ident,
|
||||
span,
|
||||
@ -2522,11 +2533,3 @@ fn compute_object_lifetime_bound(
|
||||
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",
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user