1
Fork 0

Rollup merge of #137825 - estebank:rtn-sugg-2, r=compiler-errors

Provide more context on resolve error caused from incorrect RTN

When encountering a resolve E0575 error for an associated method (when a type was expected), see if it could have been an intended return type notation bound.

```
error[E0575]: expected associated type, found associated function `Trait::method`
  --> $DIR/bad-inputs-and-output.rs:31:36
   |
LL | fn foo_qualified<T: Trait>() where <T as Trait>::method(i32): Send {}
   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^ not a associated type
   |
help: you might have meant to use the return type notation syntax
   |
LL - fn foo_qualified<T: Trait>() where <T as Trait>::method(i32): Send {}
LL + fn foo_qualified<T: Trait>() where T::method(..): Send {}
   |
```

Built on top of #137824, only second commit is relevant for review.

r? ````````@compiler-errors````````
This commit is contained in:
Michael Goulet 2025-03-06 12:22:21 -05:00 committed by GitHub
commit 484d8dd5b4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 123 additions and 17 deletions

View file

@ -624,7 +624,7 @@ pub(crate) struct UnnecessaryQualification<'ra> {
pub removal_span: Span,
}
#[derive(Default)]
#[derive(Default, Debug)]
struct DiagMetadata<'ast> {
/// The current trait's associated items' ident, used for diagnostic suggestions.
current_trait_assoc_items: Option<&'ast [P<AssocItem>]>,
@ -3147,6 +3147,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
PathSource::Trait(AliasPossibility::No),
Finalize::new(trait_ref.ref_id, trait_ref.path.span),
RecordPartialRes::Yes,
None,
);
self.diag_metadata.currently_processing_impl_trait = None;
if let Some(def_id) = res.expect_full_res().opt_def_id() {
@ -4073,6 +4074,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
source,
Finalize::new(id, path.span),
RecordPartialRes::Yes,
None,
);
}
@ -4084,14 +4086,21 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
source: PathSource<'ast>,
finalize: Finalize,
record_partial_res: RecordPartialRes,
parent_qself: Option<&QSelf>,
) -> PartialRes {
let ns = source.namespace();
let Finalize { node_id, path_span, .. } = finalize;
let report_errors = |this: &mut Self, res: Option<Res>| {
if this.should_report_errs() {
let (err, candidates) =
this.smart_resolve_report_errors(path, None, path_span, source, res);
let (err, candidates) = this.smart_resolve_report_errors(
path,
None,
path_span,
source,
res,
parent_qself,
);
let def_id = this.parent_scope.module.nearest_parent_mod();
let instead = res.is_some();
@ -4160,6 +4169,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
path_span,
PathSource::Type,
None,
parent_qself,
);
// There are two different error messages user might receive at
@ -4437,6 +4447,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
PathSource::Trait(AliasPossibility::No),
Finalize::new(finalize.node_id, qself.path_span),
RecordPartialRes::No,
Some(&qself),
);
if trait_res.expect_full_res() == Res::Err {
@ -4461,6 +4472,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
PathSource::TraitItem(ns),
Finalize::with_root_span(finalize.node_id, finalize.path_span, qself.path_span),
RecordPartialRes::No,
Some(&qself),
);
// The remaining segments (the `C` in our example) will

View file

@ -35,7 +35,7 @@ use super::NoConstantGenericsReason;
use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};
use crate::late::{
AliasPossibility, LateResolutionVisitor, LifetimeBinderKind, LifetimeRes, LifetimeRibKind,
LifetimeUseSet, RibKind,
LifetimeUseSet, QSelf, RibKind,
};
use crate::ty::fast_reject::SimplifiedType;
use crate::{
@ -421,6 +421,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
span: Span,
source: PathSource<'_>,
res: Option<Res>,
qself: Option<&QSelf>,
) -> (Diag<'tcx>, Vec<ImportSuggestion>) {
debug!(?res, ?source);
let base_error = self.make_base_error(path, span, source, res);
@ -461,6 +462,15 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
self.suggest_self_or_self_ref(&mut err, path, span);
self.detect_assoc_type_constraint_meant_as_path(&mut err, &base_error);
self.detect_rtn_with_fully_qualified_path(
&mut err,
path,
following_seg,
span,
source,
res,
qself,
);
if self.suggest_self_ty(&mut err, source, path, span)
|| self.suggest_self_value(&mut err, source, path, span)
{
@ -509,6 +519,33 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
(err, candidates)
}
fn detect_rtn_with_fully_qualified_path(
&self,
err: &mut Diag<'_>,
path: &[Segment],
following_seg: Option<&Segment>,
span: Span,
source: PathSource<'_>,
res: Option<Res>,
qself: Option<&QSelf>,
) {
if let Some(Res::Def(DefKind::AssocFn, _)) = res
&& let PathSource::TraitItem(TypeNS) = source
&& let None = following_seg
&& let Some(qself) = qself
&& let TyKind::Path(None, ty_path) = &qself.ty.kind
&& ty_path.segments.len() == 1
&& self.diag_metadata.current_where_predicate.is_some()
{
err.span_suggestion_verbose(
span,
"you might have meant to use the return type notation syntax",
format!("{}::{}(..)", ty_path.segments[0].ident, path[path.len() - 1].ident),
Applicability::MaybeIncorrect,
);
}
}
fn detect_assoc_type_constraint_meant_as_path(
&self,
err: &mut Diag<'_>,