Skip to content

Use tcx.short_string() in more diagnostics #144039

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
5 changes: 3 additions & 2 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1135,9 +1135,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
);
}
} else {
let trait_ =
tcx.short_string(bound.print_only_trait_path(), err.long_ty_path());
err.note(format!(
"associated {assoc_kind_str} `{assoc_ident}` could derive from `{}`",
bound.print_only_trait_path(),
"associated {assoc_kind_str} `{assoc_ident}` could derive from `{trait_}`",
));
}
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_typeck/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ hir_typeck_lossy_provenance_ptr2int =
.suggestion = use `.addr()` to obtain the address of a pointer
.help = if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead

hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}`
hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty}`

hir_typeck_naked_asm_outside_naked_fn =
the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]`
Expand All @@ -184,7 +184,7 @@ hir_typeck_never_type_fallback_flowing_into_unsafe_path = never type fallback af
hir_typeck_never_type_fallback_flowing_into_unsafe_union_field = never type fallback affects this union access
.help = specify the type explicitly

hir_typeck_no_associated_item = no {$item_kind} named `{$item_ident}` found for {$ty_prefix} `{$ty_str}`{$trait_missing_method ->
hir_typeck_no_associated_item = no {$item_kind} named `{$item_ident}` found for {$ty_prefix} `{$ty}`{$trait_missing_method ->
[true] {""}
*[other] {" "}in the current scope
}
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_hir_typeck/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,11 +200,11 @@ pub(crate) enum ExplicitDestructorCallSugg {

#[derive(Diagnostic)]
#[diag(hir_typeck_missing_parentheses_in_range, code = E0689)]
pub(crate) struct MissingParenthesesInRange {
pub(crate) struct MissingParenthesesInRange<'tcx> {
#[primary_span]
#[label(hir_typeck_missing_parentheses_in_range)]
pub span: Span,
pub ty_str: String,
pub ty: Ty<'tcx>,
pub method_name: String,
#[subdiagnostic]
pub add_missing_parentheses: Option<AddMissingParenthesesInRange>,
Expand Down Expand Up @@ -828,13 +828,13 @@ pub(crate) struct UnlabeledCfInWhileCondition<'a> {

#[derive(Diagnostic)]
#[diag(hir_typeck_no_associated_item, code = E0599)]
pub(crate) struct NoAssociatedItem {
pub(crate) struct NoAssociatedItem<'tcx> {
#[primary_span]
pub span: Span,
pub item_kind: &'static str,
pub item_ident: Ident,
pub ty_prefix: Cow<'static, str>,
pub ty_str: String,
pub ty: Ty<'tcx>,
pub trait_missing_method: bool,
}

Expand Down
125 changes: 53 additions & 72 deletions compiler/rustc_hir_typeck/src/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,16 +376,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}

fn suggest_missing_writer(&self, rcvr_ty: Ty<'tcx>, rcvr_expr: &hir::Expr<'tcx>) -> Diag<'_> {
let mut file = None;
fn suggest_missing_writer(
&self,
rcvr_ty: Ty<'tcx>,
rcvr_expr: &hir::Expr<'tcx>,
mut long_ty_path: Option<PathBuf>,
) -> Diag<'_> {
let mut err = struct_span_code_err!(
self.dcx(),
rcvr_expr.span,
E0599,
"cannot write into `{}`",
self.tcx.short_string(rcvr_ty, &mut file),
self.tcx.short_string(rcvr_ty, &mut long_ty_path),
);
*err.long_ty_path() = file;
*err.long_ty_path() = long_ty_path;
err.span_note(
rcvr_expr.span,
"must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method",
Expand All @@ -403,7 +407,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
self_source: SelfSource<'tcx>,
method_name: Ident,
ty_str_reported: &str,
ty: Ty<'tcx>,
err: &mut Diag<'_>,
) {
#[derive(Debug)]
Expand Down Expand Up @@ -478,7 +482,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}

// If the shadowed binding has an itializer expression,
// use the initializer expression'ty to try to find the method again.
// use the initializer expression's ty to try to find the method again.
// For example like: `let mut x = Vec::new();`,
// `Vec::new()` is the itializer expression.
if let Some(self_ty) = self.fcx.node_ty_opt(binding.init_hir_id)
Expand Down Expand Up @@ -566,17 +570,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut span = MultiSpan::from_span(sugg_let.span);
span.push_span_label(sugg_let.span,
format!("`{rcvr_name}` of type `{self_ty}` that has method `{method_name}` defined earlier here"));

let ty = self.tcx.short_string(ty, err.long_ty_path());
span.push_span_label(
self.tcx.hir_span(recv_id),
format!(
"earlier `{rcvr_name}` shadowed here with type `{ty_str_reported}`"
),
format!("earlier `{rcvr_name}` shadowed here with type `{ty}`"),
);
err.span_note(
span,
format!(
"there's an earlier shadowed binding `{rcvr_name}` of type `{self_ty}` \
that has method `{method_name}` available"
that has method `{method_name}` available"
),
);
}
Expand All @@ -602,15 +606,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let tcx = self.tcx;
let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty);
let mut ty_file = None;
let (ty_str, short_ty_str) =
if trait_missing_method && let ty::Dynamic(predicates, _, _) = rcvr_ty.kind() {
(predicates.to_string(), with_forced_trimmed_paths!(predicates.to_string()))
} else {
(
tcx.short_string(rcvr_ty, &mut ty_file),
with_forced_trimmed_paths!(rcvr_ty.to_string()),
)
};
let is_method = mode == Mode::MethodCall;
let unsatisfied_predicates = &no_match_data.unsatisfied_predicates;
let similar_candidate = no_match_data.similar_candidate;
Expand All @@ -629,15 +624,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

// We could pass the file for long types into these two, but it isn't strictly necessary
// given how targeted they are.
if let Err(guar) = self.report_failed_method_call_on_range_end(
tcx,
rcvr_ty,
source,
span,
item_ident,
&short_ty_str,
&mut ty_file,
) {
if let Err(guar) =
self.report_failed_method_call_on_range_end(tcx, rcvr_ty, source, span, item_ident)
{
return guar;
}
if let Err(guar) = self.report_failed_method_call_on_numerical_infer_var(
Expand All @@ -647,44 +636,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span,
item_kind,
item_ident,
&short_ty_str,
&mut ty_file,
) {
return guar;
}
span = item_ident.span;

// Don't show generic arguments when the method can't be found in any implementation (#81576).
let mut ty_str_reported = ty_str.clone();
if let ty::Adt(_, generics) = rcvr_ty.kind() {
if generics.len() > 0 {
let mut autoderef = self.autoderef(span, rcvr_ty).silence_errors();
let candidate_found = autoderef.any(|(ty, _)| {
if let ty::Adt(adt_def, _) = ty.kind() {
self.tcx
.inherent_impls(adt_def.did())
.into_iter()
.any(|def_id| self.associated_value(*def_id, item_ident).is_some())
} else {
false
}
});
let has_deref = autoderef.step_count() > 0;
if !candidate_found && !has_deref && unsatisfied_predicates.is_empty() {
if let Some((path_string, _)) = ty_str.split_once('<') {
ty_str_reported = path_string.to_string();
}
}
}
}

let is_write = sugg_span.ctxt().outer_expn_data().macro_def_id.is_some_and(|def_id| {
tcx.is_diagnostic_item(sym::write_macro, def_id)
|| tcx.is_diagnostic_item(sym::writeln_macro, def_id)
}) && item_ident.name == sym::write_fmt;
let mut err = if is_write && let SelfSource::MethodCall(rcvr_expr) = source {
self.suggest_missing_writer(rcvr_ty, rcvr_expr)
self.suggest_missing_writer(rcvr_ty, rcvr_expr, ty_file)
} else {
// Don't show expanded generic arguments when the method can't be found in any
// implementation (#81576).
let mut ty = rcvr_ty;
if let ty::Adt(def, generics) = rcvr_ty.kind() {
if generics.len() > 0 {
let mut autoderef = self.autoderef(span, rcvr_ty).silence_errors();
let candidate_found = autoderef.any(|(ty, _)| {
if let ty::Adt(adt_def, _) = ty.kind() {
self.tcx
.inherent_impls(adt_def.did())
.into_iter()
.any(|def_id| self.associated_value(*def_id, item_ident).is_some())
} else {
false
}
});
let has_deref = autoderef.step_count() > 0;
if !candidate_found && !has_deref && unsatisfied_predicates.is_empty() {
ty = self.tcx.at(span).type_of(def.did()).instantiate_identity();
}
}
}

let mut err = self.dcx().create_err(NoAssociatedItem {
span,
item_kind,
Expand All @@ -695,16 +682,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
rcvr_ty.prefix_string(self.tcx)
},
ty_str: ty_str_reported.clone(),
ty,
trait_missing_method,
});

if is_method {
self.suggest_use_shadowed_binding_with_method(
source,
item_ident,
&ty_str_reported,
&mut err,
source, item_ident, rcvr_ty, &mut err,
);
}

Expand Down Expand Up @@ -734,6 +718,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

err
};

if tcx.sess.source_map().is_multiline(sugg_span) {
err.span_label(sugg_span.with_hi(span.lo()), "");
}
Expand All @@ -750,6 +735,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}

if tcx.ty_is_opaque_future(rcvr_ty) && item_ident.name == sym::poll {
let ty_str = self.tcx.short_string(rcvr_ty, err.long_ty_path());
err.help(format!(
"method `poll` found on `Pin<&mut {ty_str}>`, \
see documentation for `std::pin::Pin`"
Expand Down Expand Up @@ -1339,14 +1325,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
let OnUnimplementedNote { message, label, notes, .. } = self
.err_ctxt()
.on_unimplemented_note(trait_ref, &obligation, &mut ty_file);
.on_unimplemented_note(trait_ref, &obligation, err.long_ty_path());
(message, label, notes)
})
.unwrap()
} else {
(None, None, Vec::new())
};
let primary_message = primary_message.unwrap_or_else(|| {
let ty_str = self.tcx.short_string(rcvr_ty, err.long_ty_path());
format!(
"the {item_kind} `{item_ident}` exists for {actual_prefix} `{ty_str}`, \
but its trait bounds were not satisfied"
Expand Down Expand Up @@ -1409,6 +1396,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut find_candidate_for_method = false;

let mut label_span_not_found = |err: &mut Diag<'_>| {
let ty_str = self.tcx.short_string(rcvr_ty, err.long_ty_path());
if unsatisfied_predicates.is_empty() {
err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
let is_string_or_ref_str = match rcvr_ty.kind() {
Expand Down Expand Up @@ -2520,8 +2508,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
source: SelfSource<'tcx>,
span: Span,
item_name: Ident,
ty_str: &str,
long_ty_path: &mut Option<PathBuf>,
) -> Result<(), ErrorGuaranteed> {
if let SelfSource::MethodCall(expr) = source {
for (_, parent) in tcx.hir_parent_iter(expr.hir_id).take(5) {
Expand Down Expand Up @@ -2583,18 +2569,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
if pick.is_ok() {
let range_span = parent_expr.span.with_hi(expr.span.hi());
let mut err = self.dcx().create_err(errors::MissingParenthesesInRange {
return Err(self.dcx().emit_err(errors::MissingParenthesesInRange {
span,
ty_str: ty_str.to_string(),
ty: actual,
method_name: item_name.as_str().to_string(),
add_missing_parentheses: Some(errors::AddMissingParenthesesInRange {
func_name: item_name.name.as_str().to_string(),
left: range_span.shrink_to_lo(),
right: range_span.shrink_to_hi(),
}),
});
*err.long_ty_path() = long_ty_path.take();
return Err(err.emit());
}));
}
}
}
Expand All @@ -2610,7 +2594,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span: Span,
item_kind: &str,
item_name: Ident,
ty_str: &str,
long_ty_path: &mut Option<PathBuf>,
) -> Result<(), ErrorGuaranteed> {
let found_candidate = all_traits(self.tcx)
Expand Down Expand Up @@ -2643,14 +2626,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& !actual.has_concrete_skeleton()
&& let SelfSource::MethodCall(expr) = source
{
let ty_str = self.tcx.short_string(actual, long_ty_path);
let mut err = struct_span_code_err!(
self.dcx(),
span,
E0689,
"can't call {} `{}` on ambiguous numeric type `{}`",
item_kind,
item_name,
ty_str
"can't call {item_kind} `{item_name}` on ambiguous numeric type `{ty_str}`"
);
*err.long_ty_path() = long_ty_path.take();
let concrete_type = if actual.is_integral() { "i32" } else { "f32" };
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3039,7 +3039,7 @@ impl<'tcx> ty::Binder<'tcx, ty::TraitRef<'tcx>> {
}
}

#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift, Hash)]
pub struct TraitPredPrintModifiersAndPath<'tcx>(ty::TraitPredicate<'tcx>);

impl<'tcx> fmt::Debug for TraitPredPrintModifiersAndPath<'tcx> {
Expand Down
Loading
Loading