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:
commit
484d8dd5b4
7 changed files with 123 additions and 17 deletions
|
@ -928,7 +928,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
if let Some(first_char) = constraint.ident.as_str().chars().next()
|
if let Some(first_char) = constraint.ident.as_str().chars().next()
|
||||||
&& first_char.is_ascii_lowercase()
|
&& first_char.is_ascii_lowercase()
|
||||||
{
|
{
|
||||||
tracing::info!(?data, ?data.inputs);
|
|
||||||
let err = match (&data.inputs[..], &data.output) {
|
let err = match (&data.inputs[..], &data.output) {
|
||||||
([_, ..], FnRetTy::Default(_)) => {
|
([_, ..], FnRetTy::Default(_)) => {
|
||||||
errors::BadReturnTypeNotation::Inputs { span: data.inputs_span }
|
errors::BadReturnTypeNotation::Inputs { span: data.inputs_span }
|
||||||
|
|
|
@ -268,7 +268,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
}
|
}
|
||||||
GenericArgs::Parenthesized(data) => match generic_args_mode {
|
GenericArgs::Parenthesized(data) => match generic_args_mode {
|
||||||
GenericArgsMode::ReturnTypeNotation => {
|
GenericArgsMode::ReturnTypeNotation => {
|
||||||
tracing::info!(?data, ?data.inputs);
|
|
||||||
let err = match (&data.inputs[..], &data.output) {
|
let err = match (&data.inputs[..], &data.output) {
|
||||||
([_, ..], FnRetTy::Default(_)) => {
|
([_, ..], FnRetTy::Default(_)) => {
|
||||||
BadReturnTypeNotation::Inputs { span: data.inputs_span }
|
BadReturnTypeNotation::Inputs { span: data.inputs_span }
|
||||||
|
|
|
@ -624,7 +624,7 @@ pub(crate) struct UnnecessaryQualification<'ra> {
|
||||||
pub removal_span: Span,
|
pub removal_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default, Debug)]
|
||||||
struct DiagMetadata<'ast> {
|
struct DiagMetadata<'ast> {
|
||||||
/// The current trait's associated items' ident, used for diagnostic suggestions.
|
/// The current trait's associated items' ident, used for diagnostic suggestions.
|
||||||
current_trait_assoc_items: Option<&'ast [P<AssocItem>]>,
|
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),
|
PathSource::Trait(AliasPossibility::No),
|
||||||
Finalize::new(trait_ref.ref_id, trait_ref.path.span),
|
Finalize::new(trait_ref.ref_id, trait_ref.path.span),
|
||||||
RecordPartialRes::Yes,
|
RecordPartialRes::Yes,
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
self.diag_metadata.currently_processing_impl_trait = None;
|
self.diag_metadata.currently_processing_impl_trait = None;
|
||||||
if let Some(def_id) = res.expect_full_res().opt_def_id() {
|
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,
|
source,
|
||||||
Finalize::new(id, path.span),
|
Finalize::new(id, path.span),
|
||||||
RecordPartialRes::Yes,
|
RecordPartialRes::Yes,
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4084,14 +4086,21 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
||||||
source: PathSource<'ast>,
|
source: PathSource<'ast>,
|
||||||
finalize: Finalize,
|
finalize: Finalize,
|
||||||
record_partial_res: RecordPartialRes,
|
record_partial_res: RecordPartialRes,
|
||||||
|
parent_qself: Option<&QSelf>,
|
||||||
) -> PartialRes {
|
) -> PartialRes {
|
||||||
let ns = source.namespace();
|
let ns = source.namespace();
|
||||||
|
|
||||||
let Finalize { node_id, path_span, .. } = finalize;
|
let Finalize { node_id, path_span, .. } = finalize;
|
||||||
let report_errors = |this: &mut Self, res: Option<Res>| {
|
let report_errors = |this: &mut Self, res: Option<Res>| {
|
||||||
if this.should_report_errs() {
|
if this.should_report_errs() {
|
||||||
let (err, candidates) =
|
let (err, candidates) = this.smart_resolve_report_errors(
|
||||||
this.smart_resolve_report_errors(path, None, path_span, source, res);
|
path,
|
||||||
|
None,
|
||||||
|
path_span,
|
||||||
|
source,
|
||||||
|
res,
|
||||||
|
parent_qself,
|
||||||
|
);
|
||||||
|
|
||||||
let def_id = this.parent_scope.module.nearest_parent_mod();
|
let def_id = this.parent_scope.module.nearest_parent_mod();
|
||||||
let instead = res.is_some();
|
let instead = res.is_some();
|
||||||
|
@ -4160,6 +4169,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
||||||
path_span,
|
path_span,
|
||||||
PathSource::Type,
|
PathSource::Type,
|
||||||
None,
|
None,
|
||||||
|
parent_qself,
|
||||||
);
|
);
|
||||||
|
|
||||||
// There are two different error messages user might receive at
|
// 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),
|
PathSource::Trait(AliasPossibility::No),
|
||||||
Finalize::new(finalize.node_id, qself.path_span),
|
Finalize::new(finalize.node_id, qself.path_span),
|
||||||
RecordPartialRes::No,
|
RecordPartialRes::No,
|
||||||
|
Some(&qself),
|
||||||
);
|
);
|
||||||
|
|
||||||
if trait_res.expect_full_res() == Res::Err {
|
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),
|
PathSource::TraitItem(ns),
|
||||||
Finalize::with_root_span(finalize.node_id, finalize.path_span, qself.path_span),
|
Finalize::with_root_span(finalize.node_id, finalize.path_span, qself.path_span),
|
||||||
RecordPartialRes::No,
|
RecordPartialRes::No,
|
||||||
|
Some(&qself),
|
||||||
);
|
);
|
||||||
|
|
||||||
// The remaining segments (the `C` in our example) will
|
// The remaining segments (the `C` in our example) will
|
||||||
|
|
|
@ -35,7 +35,7 @@ use super::NoConstantGenericsReason;
|
||||||
use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};
|
use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};
|
||||||
use crate::late::{
|
use crate::late::{
|
||||||
AliasPossibility, LateResolutionVisitor, LifetimeBinderKind, LifetimeRes, LifetimeRibKind,
|
AliasPossibility, LateResolutionVisitor, LifetimeBinderKind, LifetimeRes, LifetimeRibKind,
|
||||||
LifetimeUseSet, RibKind,
|
LifetimeUseSet, QSelf, RibKind,
|
||||||
};
|
};
|
||||||
use crate::ty::fast_reject::SimplifiedType;
|
use crate::ty::fast_reject::SimplifiedType;
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -421,6 +421,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
span: Span,
|
span: Span,
|
||||||
source: PathSource<'_>,
|
source: PathSource<'_>,
|
||||||
res: Option<Res>,
|
res: Option<Res>,
|
||||||
|
qself: Option<&QSelf>,
|
||||||
) -> (Diag<'tcx>, Vec<ImportSuggestion>) {
|
) -> (Diag<'tcx>, Vec<ImportSuggestion>) {
|
||||||
debug!(?res, ?source);
|
debug!(?res, ?source);
|
||||||
let base_error = self.make_base_error(path, span, source, res);
|
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.suggest_self_or_self_ref(&mut err, path, span);
|
||||||
self.detect_assoc_type_constraint_meant_as_path(&mut err, &base_error);
|
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)
|
if self.suggest_self_ty(&mut err, source, path, span)
|
||||||
|| self.suggest_self_value(&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)
|
(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(
|
fn detect_assoc_type_constraint_meant_as_path(
|
||||||
&self,
|
&self,
|
||||||
err: &mut Diag<'_>,
|
err: &mut Diag<'_>,
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
//@ edition: 2021
|
||||||
|
//@ run-rustfix
|
||||||
|
#![feature(return_type_notation)]
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
async fn method() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo<T: Trait<method(..): Send>>() {}
|
||||||
|
//~^ ERROR argument types not allowed with return type notation
|
||||||
|
|
||||||
|
fn bar<T: Trait<method(..): Send>>() {}
|
||||||
|
//~^ ERROR return type not allowed with return type notation
|
||||||
|
|
||||||
|
fn baz<T: Trait<method(..): Send>>() {}
|
||||||
|
//~^ ERROR return type notation arguments must be elided with `..`
|
||||||
|
|
||||||
|
fn foo_path<T: Trait>() where T::method(..): Send {}
|
||||||
|
//~^ ERROR argument types not allowed with return type notation
|
||||||
|
|
||||||
|
fn bar_path<T: Trait>() where T::method(..): Send {}
|
||||||
|
//~^ ERROR return type not allowed with return type notation
|
||||||
|
|
||||||
|
fn bay_path<T: Trait>() where T::method(..): Send {}
|
||||||
|
//~^ ERROR return type not allowed with return type notation
|
||||||
|
|
||||||
|
fn baz_path<T: Trait>() where T::method(..): Send {}
|
||||||
|
//~^ ERROR return type notation arguments must be elided with `..`
|
||||||
|
|
||||||
|
fn foo_qualified<T: Trait>() where T::method(..): Send {}
|
||||||
|
//~^ ERROR expected associated type
|
||||||
|
|
||||||
|
fn bar_qualified<T: Trait>() where T::method(..): Send {}
|
||||||
|
//~^ ERROR expected associated type
|
||||||
|
|
||||||
|
fn baz_qualified<T: Trait>() where T::method(..): Send {}
|
||||||
|
//~^ ERROR expected associated type
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -1,6 +1,7 @@
|
||||||
//@ edition: 2021
|
//@ edition: 2021
|
||||||
|
//@ run-rustfix
|
||||||
#![feature(return_type_notation)]
|
#![feature(return_type_notation)]
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
trait Trait {
|
trait Trait {
|
||||||
async fn method() {}
|
async fn method() {}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: return type not allowed with return type notation
|
error: return type not allowed with return type notation
|
||||||
--> $DIR/bad-inputs-and-output.rs:24:45
|
--> $DIR/bad-inputs-and-output.rs:25:45
|
||||||
|
|
|
|
||||||
LL | fn bay_path<T: Trait>() where T::method(..) -> (): Send {}
|
LL | fn bay_path<T: Trait>() where T::method(..) -> (): Send {}
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
@ -11,25 +11,43 @@ LL + fn bay_path<T: Trait>() where T::method(..): Send {}
|
||||||
|
|
|
|
||||||
|
|
||||||
error[E0575]: expected associated type, found associated function `Trait::method`
|
error[E0575]: expected associated type, found associated function `Trait::method`
|
||||||
--> $DIR/bad-inputs-and-output.rs:30:36
|
--> $DIR/bad-inputs-and-output.rs:31:36
|
||||||
|
|
|
|
||||||
LL | fn foo_qualified<T: Trait>() where <T as Trait>::method(i32): Send {}
|
LL | fn foo_qualified<T: Trait>() where <T as Trait>::method(i32): Send {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ not a associated type
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^ 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 {}
|
||||||
|
|
|
||||||
|
|
||||||
error[E0575]: expected associated type, found associated function `Trait::method`
|
error[E0575]: expected associated type, found associated function `Trait::method`
|
||||||
--> $DIR/bad-inputs-and-output.rs:33:36
|
--> $DIR/bad-inputs-and-output.rs:34:36
|
||||||
|
|
|
|
||||||
LL | fn bar_qualified<T: Trait>() where <T as Trait>::method() -> (): Send {}
|
LL | fn bar_qualified<T: Trait>() where <T as Trait>::method() -> (): Send {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a associated type
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a associated type
|
||||||
|
|
|
||||||
|
help: you might have meant to use the return type notation syntax
|
||||||
|
|
|
||||||
|
LL - fn bar_qualified<T: Trait>() where <T as Trait>::method() -> (): Send {}
|
||||||
|
LL + fn bar_qualified<T: Trait>() where T::method(..): Send {}
|
||||||
|
|
|
||||||
|
|
||||||
error[E0575]: expected associated type, found associated function `Trait::method`
|
error[E0575]: expected associated type, found associated function `Trait::method`
|
||||||
--> $DIR/bad-inputs-and-output.rs:36:36
|
--> $DIR/bad-inputs-and-output.rs:37:36
|
||||||
|
|
|
|
||||||
LL | fn baz_qualified<T: Trait>() where <T as Trait>::method(): Send {}
|
LL | fn baz_qualified<T: Trait>() where <T as Trait>::method(): Send {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^ not a associated type
|
| ^^^^^^^^^^^^^^^^^^^^^^ not a associated type
|
||||||
|
|
|
||||||
|
help: you might have meant to use the return type notation syntax
|
||||||
|
|
|
||||||
|
LL - fn baz_qualified<T: Trait>() where <T as Trait>::method(): Send {}
|
||||||
|
LL + fn baz_qualified<T: Trait>() where T::method(..): Send {}
|
||||||
|
|
|
||||||
|
|
||||||
error: argument types not allowed with return type notation
|
error: argument types not allowed with return type notation
|
||||||
--> $DIR/bad-inputs-and-output.rs:9:23
|
--> $DIR/bad-inputs-and-output.rs:10:23
|
||||||
|
|
|
|
||||||
LL | fn foo<T: Trait<method(i32): Send>>() {}
|
LL | fn foo<T: Trait<method(i32): Send>>() {}
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
@ -41,7 +59,7 @@ LL + fn foo<T: Trait<method(..): Send>>() {}
|
||||||
|
|
|
|
||||||
|
|
||||||
error: return type not allowed with return type notation
|
error: return type not allowed with return type notation
|
||||||
--> $DIR/bad-inputs-and-output.rs:12:25
|
--> $DIR/bad-inputs-and-output.rs:13:25
|
||||||
|
|
|
|
||||||
LL | fn bar<T: Trait<method() -> (): Send>>() {}
|
LL | fn bar<T: Trait<method() -> (): Send>>() {}
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -53,7 +71,7 @@ LL + fn bar<T: Trait<method(..): Send>>() {}
|
||||||
|
|
|
|
||||||
|
|
||||||
error: return type notation arguments must be elided with `..`
|
error: return type notation arguments must be elided with `..`
|
||||||
--> $DIR/bad-inputs-and-output.rs:15:23
|
--> $DIR/bad-inputs-and-output.rs:16:23
|
||||||
|
|
|
|
||||||
LL | fn baz<T: Trait<method(): Send>>() {}
|
LL | fn baz<T: Trait<method(): Send>>() {}
|
||||||
| ^^
|
| ^^
|
||||||
|
@ -64,7 +82,7 @@ LL | fn baz<T: Trait<method(..): Send>>() {}
|
||||||
| ++
|
| ++
|
||||||
|
|
||||||
error: argument types not allowed with return type notation
|
error: argument types not allowed with return type notation
|
||||||
--> $DIR/bad-inputs-and-output.rs:18:40
|
--> $DIR/bad-inputs-and-output.rs:19:40
|
||||||
|
|
|
|
||||||
LL | fn foo_path<T: Trait>() where T::method(i32): Send {}
|
LL | fn foo_path<T: Trait>() where T::method(i32): Send {}
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
@ -76,7 +94,7 @@ LL + fn foo_path<T: Trait>() where T::method(..): Send {}
|
||||||
|
|
|
|
||||||
|
|
||||||
error: return type not allowed with return type notation
|
error: return type not allowed with return type notation
|
||||||
--> $DIR/bad-inputs-and-output.rs:21:42
|
--> $DIR/bad-inputs-and-output.rs:22:42
|
||||||
|
|
|
|
||||||
LL | fn bar_path<T: Trait>() where T::method() -> (): Send {}
|
LL | fn bar_path<T: Trait>() where T::method() -> (): Send {}
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
@ -88,7 +106,7 @@ LL + fn bar_path<T: Trait>() where T::method(..): Send {}
|
||||||
|
|
|
|
||||||
|
|
||||||
error: return type notation arguments must be elided with `..`
|
error: return type notation arguments must be elided with `..`
|
||||||
--> $DIR/bad-inputs-and-output.rs:27:40
|
--> $DIR/bad-inputs-and-output.rs:28:40
|
||||||
|
|
|
|
||||||
LL | fn baz_path<T: Trait>() where T::method(): Send {}
|
LL | fn baz_path<T: Trait>() where T::method(): Send {}
|
||||||
| ^^
|
| ^^
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue