Skip to content

Commit 898448c

Browse files
committed
HIR ty lowering: Refactor the way the projectee ("QSelf") gets passed to diagnostics
1 parent ef121f2 commit 898448c

File tree

5 files changed

+86
-69
lines changed

5 files changed

+86
-69
lines changed

compiler/rustc_hir_analysis/messages.ftl

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
hir_analysis_ambiguous_assoc_item = ambiguous associated {$assoc_kind} `{$assoc_name}` in bounds of `{$ty_param_name}`
1+
hir_analysis_ambiguous_assoc_item = ambiguous associated {$assoc_kind} `{$assoc_name}` in bounds of `{$qself}`
22
.label = ambiguous associated {$assoc_kind} `{$assoc_name}`
33
44
hir_analysis_ambiguous_lifetime_bound =
@@ -12,14 +12,14 @@ hir_analysis_assoc_item_is_private = {$kind} `{$name}` is private
1212
.label = private {$kind}
1313
.defined_here_label = the {$kind} is defined here
1414
15-
hir_analysis_assoc_item_not_found = associated {$assoc_kind} `{$assoc_name}` not found for `{$ty_param_name}`
15+
hir_analysis_assoc_item_not_found = associated {$assoc_kind} `{$assoc_name}` not found for `{$qself}`
1616
1717
hir_analysis_assoc_item_not_found_found_in_other_trait_label = there is {$identically_named ->
1818
[true] an
1919
*[false] a similarly named
2020
} associated {$assoc_kind} `{$suggested_name}` in the trait `{$trait_name}`
2121
hir_analysis_assoc_item_not_found_label = associated {$assoc_kind} `{$assoc_name}` not found
22-
hir_analysis_assoc_item_not_found_other_sugg = `{$ty_param_name}` has the following associated {$assoc_kind}
22+
hir_analysis_assoc_item_not_found_other_sugg = `{$qself}` has the following associated {$assoc_kind}
2323
hir_analysis_assoc_item_not_found_similar_in_other_trait_sugg = change the associated {$assoc_kind} name to use `{$suggested_name}` from `{$trait_name}`
2424
hir_analysis_assoc_item_not_found_similar_in_other_trait_with_bound_sugg = and also change the associated {$assoc_kind} name
2525
hir_analysis_assoc_item_not_found_similar_sugg = there is an associated {$assoc_kind} with a similar name

compiler/rustc_hir_analysis/src/errors.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub struct AmbiguousAssocItem<'a> {
2222
pub span: Span,
2323
pub assoc_kind: &'static str,
2424
pub assoc_name: Ident,
25-
pub ty_param_name: &'a str,
25+
pub qself: &'a str,
2626
}
2727

2828
#[derive(Diagnostic)]
@@ -75,7 +75,7 @@ pub struct AssocItemNotFound<'a> {
7575
pub span: Span,
7676
pub assoc_name: Ident,
7777
pub assoc_kind: &'static str,
78-
pub ty_param_name: &'a str,
78+
pub qself: &'a str,
7979
#[subdiagnostic]
8080
pub label: Option<AssocItemNotFoundLabel<'a>>,
8181
#[subdiagnostic]
@@ -134,7 +134,7 @@ pub enum AssocItemNotFoundSugg<'a> {
134134
Other {
135135
#[primary_span]
136136
span: Span,
137-
ty_param_name: &'a str,
137+
qself: &'a str,
138138
assoc_kind: &'static str,
139139
suggested_name: Symbol,
140140
},

compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use rustc_hir as hir;
66
use rustc_hir::def::{DefKind, Res};
77
use rustc_hir::def_id::{DefId, LocalDefId};
88
use rustc_middle::bug;
9-
use rustc_middle::ty::print::PrintTraitRefExt as _;
109
use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TyCtxt};
1110
use rustc_span::symbol::Ident;
1211
use rustc_span::{ErrorGuaranteed, Span, Symbol};
@@ -16,9 +15,8 @@ use smallvec::SmallVec;
1615

1716
use crate::bounds::Bounds;
1817
use crate::errors;
19-
use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter};
20-
21-
use super::RegionInferReason;
18+
use crate::hir_ty_lowering::HirTyLowerer;
19+
use crate::hir_ty_lowering::{AssocItemQSelf, OnlySelfBounds, PredicateFilter, RegionInferReason};
2220

2321
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
2422
/// Add a `Sized` bound to the `bounds` if appropriate.
@@ -288,8 +286,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
288286
// one that does define it.
289287
self.probe_single_bound_for_assoc_item(
290288
|| traits::supertraits(tcx, trait_ref),
291-
trait_ref.skip_binder().print_only_trait_name(),
292-
None,
289+
AssocItemQSelf::Trait(trait_ref.def_id()),
293290
assoc_kind,
294291
constraint.ident,
295292
path_span,

compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs

+38-21
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,17 @@ use crate::errors::{
33
ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits,
44
};
55
use crate::fluent_generated as fluent;
6-
use crate::hir_ty_lowering::HirTyLowerer;
6+
use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer};
77
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
88
use rustc_data_structures::sorted_map::SortedMap;
99
use rustc_data_structures::unord::UnordMap;
1010
use rustc_errors::MultiSpan;
1111
use rustc_errors::{
1212
codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed,
1313
};
14+
use rustc_hir as hir;
1415
use rustc_hir::def::{DefKind, Res};
15-
use rustc_hir::def_id::{DefId, LocalDefId};
16-
use rustc_hir::{self as hir, Node};
16+
use rustc_hir::def_id::DefId;
1717
use rustc_middle::bug;
1818
use rustc_middle::query::Key;
1919
use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _};
@@ -116,8 +116,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
116116
pub(super) fn complain_about_assoc_item_not_found<I>(
117117
&self,
118118
all_candidates: impl Fn() -> I,
119-
ty_param_name: &str,
120-
ty_param_def_id: Option<LocalDefId>,
119+
qself: AssocItemQSelf,
121120
assoc_kind: ty::AssocKind,
122121
assoc_name: Ident,
123122
span: Span,
@@ -139,7 +138,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
139138
);
140139
}
141140

142-
let assoc_kind_str = super::assoc_kind_str(assoc_kind);
141+
let assoc_kind_str = assoc_kind_str(assoc_kind);
142+
let qself_str = qself.to_string(tcx);
143143

144144
// The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a
145145
// valid span, so we point at the whole path segment instead.
@@ -149,7 +149,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
149149
span: if is_dummy { span } else { assoc_name.span },
150150
assoc_name,
151151
assoc_kind: assoc_kind_str,
152-
ty_param_name,
152+
qself: &qself_str,
153153
label: None,
154154
sugg: None,
155155
};
@@ -219,19 +219,28 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
219219
suggested_name,
220220
identically_named: suggested_name == assoc_name.name,
221221
});
222-
let hir = tcx.hir();
223-
if let Some(def_id) = ty_param_def_id
224-
&& let parent = hir.get_parent_item(tcx.local_def_id_to_hir_id(def_id))
225-
&& let Some(generics) = hir.get_generics(parent.def_id)
222+
if let AssocItemQSelf::TyParam(ty_param_def_id) = qself
223+
// Not using `self.item_def_id()` here as that would yield the opaque type itself if we're
224+
// inside an opaque type while we're interested in the overarching type alias (TAIT).
225+
// FIXME: However, for trait aliases, this incorrectly returns the enclosing module...
226+
&& let item_def_id =
227+
tcx.hir().get_parent_item(tcx.local_def_id_to_hir_id(ty_param_def_id))
228+
// FIXME: ...which obviously won't have any generics.
229+
&& let Some(generics) = tcx.hir().get_generics(item_def_id.def_id)
226230
{
227-
if generics.bounds_for_param(def_id).flat_map(|pred| pred.bounds.iter()).any(
228-
|b| match b {
231+
// FIXME: Suggest adding supertrait bounds if we have a `Self` type param.
232+
// FIXME(trait_alias): Suggest adding `Self: Trait` to
233+
// `trait Alias = where Self::Proj:;` with `trait Trait { type Proj; }`.
234+
if generics
235+
.bounds_for_param(ty_param_def_id)
236+
.flat_map(|pred| pred.bounds.iter())
237+
.any(|b| match b {
229238
hir::GenericBound::Trait(t, ..) => {
230239
t.trait_ref.trait_def_id() == Some(best_trait)
231240
}
232241
_ => false,
233-
},
234-
) {
242+
})
243+
{
235244
// The type param already has a bound for `trait_name`, we just need to
236245
// change the associated item.
237246
err.sugg = Some(errors::AssocItemNotFoundSugg::SimilarInOtherTrait {
@@ -247,7 +256,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
247256
tcx,
248257
generics,
249258
&mut err,
250-
&ty_param_name,
259+
&qself_str,
251260
&trait_name,
252261
None,
253262
None,
@@ -273,7 +282,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
273282
if let [candidate_name] = all_candidate_names.as_slice() {
274283
err.sugg = Some(errors::AssocItemNotFoundSugg::Other {
275284
span: assoc_name.span,
276-
ty_param_name,
285+
qself: &qself_str,
277286
assoc_kind: assoc_kind_str,
278287
suggested_name: *candidate_name,
279288
});
@@ -339,10 +348,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
339348

340349
self.dcx().emit_err(errors::AssocKindMismatch {
341350
span,
342-
expected: super::assoc_kind_str(expected),
343-
got: super::assoc_kind_str(got),
351+
expected: assoc_kind_str(expected),
352+
got: assoc_kind_str(got),
344353
expected_because_label,
345-
assoc_kind: super::assoc_kind_str(assoc_item.kind),
354+
assoc_kind: assoc_kind_str(assoc_item.kind),
346355
def_span: tcx.def_span(assoc_item.def_id),
347356
bound_on_assoc_const_label,
348357
wrap_in_braces_sugg,
@@ -736,7 +745,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
736745
if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) {
737746
let grandparent = tcx.parent_hir_node(tcx.parent_hir_id(bound.trait_ref.hir_ref_id));
738747
in_expr_or_pat = match grandparent {
739-
Node::Expr(_) | Node::Pat(_) => true,
748+
hir::Node::Expr(_) | hir::Node::Pat(_) => true,
740749
_ => false,
741750
};
742751
match bound.trait_ref.path.segments {
@@ -1602,3 +1611,11 @@ fn generics_args_err_extend<'a>(
16021611
_ => {}
16031612
}
16041613
}
1614+
1615+
pub(super) fn assoc_kind_str(kind: ty::AssocKind) -> &'static str {
1616+
match kind {
1617+
ty::AssocKind::Fn => "function",
1618+
ty::AssocKind::Const => "constant",
1619+
ty::AssocKind::Type => "type",
1620+
}
1621+
}

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

+39-36
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ use rustc_trait_selection::infer::InferCtxtExt;
5555
use rustc_trait_selection::traits::wf::object_region_bounds;
5656
use rustc_trait_selection::traits::{self, ObligationCtxt};
5757

58-
use std::fmt::Display;
5958
use std::slice;
6059

6160
/// A path segment that is semantically allowed to have generic arguments.
@@ -193,6 +192,25 @@ pub trait HirTyLowerer<'tcx> {
193192
}
194193
}
195194

195+
/// The "qualified self" of an associated item path.
196+
///
197+
/// For diagnostic purposes only.
198+
enum AssocItemQSelf {
199+
Trait(DefId),
200+
TyParam(LocalDefId),
201+
SelfTyAlias,
202+
}
203+
204+
impl AssocItemQSelf {
205+
fn to_string(&self, tcx: TyCtxt<'_>) -> String {
206+
match *self {
207+
Self::Trait(def_id) => tcx.def_path_str(def_id),
208+
Self::TyParam(def_id) => tcx.hir().ty_param_name(def_id).to_string(),
209+
Self::SelfTyAlias => kw::SelfUpper.to_string(),
210+
}
211+
}
212+
}
213+
196214
/// New-typed boolean indicating whether explicit late-bound lifetimes
197215
/// are present in a set of generic arguments.
198216
///
@@ -811,19 +829,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
811829
let predicates = &self.probe_ty_param_bounds(span, ty_param_def_id, assoc_name).predicates;
812830
debug!("predicates={:#?}", predicates);
813831

814-
let param_name = tcx.hir().ty_param_name(ty_param_def_id);
815832
self.probe_single_bound_for_assoc_item(
816833
|| {
817-
traits::transitive_bounds_that_define_assoc_item(
818-
tcx,
819-
predicates
820-
.iter()
821-
.filter_map(|(p, _)| Some(p.as_trait_clause()?.map_bound(|t| t.trait_ref))),
822-
assoc_name,
823-
)
834+
let trait_refs = predicates
835+
.iter()
836+
.filter_map(|(p, _)| Some(p.as_trait_clause()?.map_bound(|t| t.trait_ref)));
837+
traits::transitive_bounds_that_define_assoc_item(tcx, trait_refs, assoc_name)
824838
},
825-
param_name,
826-
Some(ty_param_def_id),
839+
AssocItemQSelf::TyParam(ty_param_def_id),
827840
ty::AssocKind::Type,
828841
assoc_name,
829842
span,
@@ -835,12 +848,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
835848
///
836849
/// This fails if there is no such bound in the list of candidates or if there are multiple
837850
/// candidates in which case it reports ambiguity.
838-
#[instrument(level = "debug", skip(self, all_candidates, ty_param_name, constraint), ret)]
851+
#[instrument(level = "debug", skip(self, all_candidates, qself, constraint), ret)]
839852
fn probe_single_bound_for_assoc_item<I>(
840853
&self,
841854
all_candidates: impl Fn() -> I,
842-
ty_param_name: impl Display,
843-
ty_param_def_id: Option<LocalDefId>,
855+
qself: AssocItemQSelf,
844856
assoc_kind: ty::AssocKind,
845857
assoc_name: Ident,
846858
span: Span,
@@ -858,8 +870,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
858870
let Some(bound) = matching_candidates.next() else {
859871
let reported = self.complain_about_assoc_item_not_found(
860872
all_candidates,
861-
&ty_param_name.to_string(),
862-
ty_param_def_id,
873+
qself,
863874
assoc_kind,
864875
assoc_name,
865876
span,
@@ -872,13 +883,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
872883
if let Some(bound2) = matching_candidates.next() {
873884
debug!(?bound2);
874885

875-
let assoc_kind_str = assoc_kind_str(assoc_kind);
876-
let ty_param_name = &ty_param_name.to_string();
886+
let assoc_kind_str = errors::assoc_kind_str(assoc_kind);
887+
let qself_str = qself.to_string(tcx);
877888
let mut err = self.dcx().create_err(crate::errors::AmbiguousAssocItem {
878889
span,
879890
assoc_kind: assoc_kind_str,
880891
assoc_name,
881-
ty_param_name,
892+
qself: &qself_str,
882893
});
883894
// Provide a more specific error code index entry for equality bindings.
884895
err.code(
@@ -929,7 +940,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
929940
err.span_suggestion_verbose(
930941
span.with_hi(assoc_name.span.lo()),
931942
"use fully-qualified syntax to disambiguate",
932-
format!("<{ty_param_name} as {}>::", bound.print_only_trait_path()),
943+
format!("<{qself_str} as {}>::", bound.print_only_trait_path()),
933944
Applicability::MaybeIncorrect,
934945
);
935946
}
@@ -943,7 +954,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
943954
if !where_bounds.is_empty() {
944955
err.help(format!(
945956
"consider introducing a new type parameter `T` and adding `where` constraints:\
946-
\n where\n T: {ty_param_name},\n{}",
957+
\n where\n T: {qself_str},\n{}",
947958
where_bounds.join(",\n"),
948959
));
949960
}
@@ -997,11 +1008,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
9971008
let tcx = self.tcx();
9981009

9991010
let assoc_ident = assoc_segment.ident;
1000-
let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
1001-
path.res
1002-
} else {
1003-
Res::Err
1004-
};
10051011

10061012
// Check if we have an enum variant or an inherent associated type.
10071013
let mut variant_resolution = None;
@@ -1038,6 +1044,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
10381044
}
10391045
}
10401046

1047+
let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
1048+
path.res
1049+
} else {
1050+
Res::Err
1051+
};
1052+
10411053
// Find the type of the associated item, and the trait where the associated
10421054
// item is declared.
10431055
let bound = match (&qself_ty.kind(), qself_res) {
@@ -1056,8 +1068,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
10561068
ty::Binder::dummy(trait_ref.instantiate_identity()),
10571069
)
10581070
},
1059-
kw::SelfUpper,
1060-
None,
1071+
AssocItemQSelf::SelfTyAlias,
10611072
ty::AssocKind::Type,
10621073
assoc_ident,
10631074
span,
@@ -2522,11 +2533,3 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
25222533
Some(r)
25232534
}
25242535
}
2525-
2526-
fn assoc_kind_str(kind: ty::AssocKind) -> &'static str {
2527-
match kind {
2528-
ty::AssocKind::Fn => "function",
2529-
ty::AssocKind::Const => "constant",
2530-
ty::AssocKind::Type => "type",
2531-
}
2532-
}

0 commit comments

Comments
 (0)