Skip to content

Commit adf5464

Browse files
committed
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 {} | ```
1 parent adb5eca commit adf5464

File tree

5 files changed

+128
-20
lines changed

5 files changed

+128
-20
lines changed

compiler/rustc_resolve/src/late.rs

+18-5
Original file line numberDiff line numberDiff line change
@@ -3125,6 +3125,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
31253125
PathSource::Trait(AliasPossibility::No),
31263126
Finalize::new(trait_ref.ref_id, trait_ref.path.span),
31273127
RecordPartialRes::Yes,
3128+
&None,
31283129
);
31293130
self.diag_metadata.currently_processing_impl_trait = None;
31303131
if let Some(def_id) = res.expect_full_res().opt_def_id() {
@@ -4051,6 +4052,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
40514052
source,
40524053
Finalize::new(id, path.span),
40534054
RecordPartialRes::Yes,
4055+
qself,
40544056
);
40554057
}
40564058

@@ -4062,14 +4064,21 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
40624064
source: PathSource<'ast>,
40634065
finalize: Finalize,
40644066
record_partial_res: RecordPartialRes,
4067+
parent_qself: &Option<P<QSelf>>,
40654068
) -> PartialRes {
40664069
let ns = source.namespace();
40674070

40684071
let Finalize { node_id, path_span, .. } = finalize;
40694072
let report_errors = |this: &mut Self, res: Option<Res>| {
40704073
if this.should_report_errs() {
4071-
let (err, candidates) =
4072-
this.smart_resolve_report_errors(path, None, path_span, source, res);
4074+
let (err, candidates) = this.smart_resolve_report_errors(
4075+
path,
4076+
None,
4077+
path_span,
4078+
source,
4079+
res,
4080+
parent_qself,
4081+
);
40734082

40744083
let def_id = this.parent_scope.module.nearest_parent_mod();
40754084
let instead = res.is_some();
@@ -4138,6 +4147,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
41384147
path_span,
41394148
PathSource::Type,
41404149
None,
4150+
parent_qself,
41414151
);
41424152

41434153
// There are two different error messages user might receive at
@@ -4386,17 +4396,17 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
43864396
/// Handles paths that may refer to associated items.
43874397
fn resolve_qpath(
43884398
&mut self,
4389-
qself: &Option<P<QSelf>>,
4399+
qself_: &Option<P<QSelf>>,
43904400
path: &[Segment],
43914401
ns: Namespace,
43924402
finalize: Finalize,
43934403
) -> Result<Option<PartialRes>, Spanned<ResolutionError<'ra>>> {
43944404
debug!(
43954405
"resolve_qpath(qself={:?}, path={:?}, ns={:?}, finalize={:?})",
4396-
qself, path, ns, finalize,
4406+
qself_, path, ns, finalize,
43974407
);
43984408

4399-
if let Some(qself) = qself {
4409+
if let Some(qself) = &qself_ {
44004410
if qself.position == 0 {
44014411
// This is a case like `<T>::B`, where there is no
44024412
// trait to resolve. In that case, we leave the `B`
@@ -4415,6 +4425,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
44154425
PathSource::Trait(AliasPossibility::No),
44164426
Finalize::new(finalize.node_id, qself.path_span),
44174427
RecordPartialRes::No,
4428+
qself_,
44184429
);
44194430

44204431
if trait_res.expect_full_res() == Res::Err {
@@ -4433,12 +4444,14 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
44334444
// `qself.position`). And then we recursively resolve that,
44344445
// but with `qself` set to `None`.
44354446
let ns = if qself.position + 1 == path.len() { ns } else { TypeNS };
4447+
tracing::info!(?qself, ?path, ?ns, "method");
44364448
let partial_res = self.smart_resolve_path_fragment(
44374449
&None,
44384450
&path[..=qself.position],
44394451
PathSource::TraitItem(ns),
44404452
Finalize::with_root_span(finalize.node_id, finalize.path_span, qself.path_span),
44414453
RecordPartialRes::No,
4454+
qself_,
44424455
);
44434456

44444457
// The remaining segments (the `C` in our example) will

compiler/rustc_resolve/src/late/diagnostics.rs

+37-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use super::NoConstantGenericsReason;
3535
use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};
3636
use crate::late::{
3737
AliasPossibility, LateResolutionVisitor, LifetimeBinderKind, LifetimeRes, LifetimeRibKind,
38-
LifetimeUseSet, RibKind,
38+
LifetimeUseSet, QSelf, RibKind,
3939
};
4040
use crate::ty::fast_reject::SimplifiedType;
4141
use crate::{
@@ -421,6 +421,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
421421
span: Span,
422422
source: PathSource<'_>,
423423
res: Option<Res>,
424+
qself: &Option<P<QSelf>>,
424425
) -> (Diag<'tcx>, Vec<ImportSuggestion>) {
425426
debug!(?res, ?source);
426427
let base_error = self.make_base_error(path, span, source, res);
@@ -453,6 +454,15 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
453454

454455
self.suggest_self_or_self_ref(&mut err, path, span);
455456
self.detect_assoc_type_constraint_meant_as_path(&mut err, &base_error);
457+
self.detect_rtn_with_fully_qualified_path(
458+
&mut err,
459+
path,
460+
following_seg,
461+
span,
462+
source,
463+
res,
464+
qself,
465+
);
456466
if self.suggest_self_ty(&mut err, source, path, span)
457467
|| self.suggest_self_value(&mut err, source, path, span)
458468
{
@@ -500,6 +510,32 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
500510

501511
(err, candidates)
502512
}
513+
fn detect_rtn_with_fully_qualified_path(
514+
&self,
515+
err: &mut Diag<'_>,
516+
path: &[Segment],
517+
following_seg: Option<&Segment>,
518+
span: Span,
519+
source: PathSource<'_>,
520+
res: Option<Res>,
521+
qself: &Option<P<QSelf>>,
522+
) {
523+
if let Some(Res::Def(DefKind::AssocFn, _)) = res
524+
&& let PathSource::TraitItem(TypeNS) = source
525+
&& let None = following_seg
526+
&& let Some(qself) = qself
527+
&& let TyKind::Path(None, ty_path) = &qself.ty.kind
528+
&& ty_path.segments.len() == 1
529+
&& self.diag_metadata.current_where_predicate.is_some()
530+
{
531+
err.span_suggestion_verbose(
532+
span,
533+
"you might have meant to use the return type notation syntax",
534+
format!("{}::{}(..)", ty_path.segments[0].ident, path[path.len() - 1].ident),
535+
Applicability::MaybeIncorrect,
536+
);
537+
}
538+
}
503539

504540
fn detect_assoc_type_constraint_meant_as_path(
505541
&self,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//@ edition: 2021
2+
//@ run-rustfix
3+
#![feature(return_type_notation)]
4+
#![allow(dead_code)]
5+
6+
trait Trait {
7+
async fn method() {}
8+
}
9+
10+
fn foo<T: Trait<method(..): Send>>() {}
11+
//~^ ERROR argument types not allowed with return type notation
12+
13+
fn bar<T: Trait<method(..): Send>>() {}
14+
//~^ ERROR return type not allowed with return type notation
15+
16+
fn baz<T: Trait<method(..): Send>>() {}
17+
//~^ ERROR return type notation arguments must be elided with `..`
18+
19+
fn foo_path<T: Trait>() where T::method(..): Send {}
20+
//~^ ERROR argument types not allowed with return type notation
21+
22+
fn bar_path<T: Trait>() where T::method(..): Send {}
23+
//~^ ERROR return type not allowed with return type notation
24+
25+
fn bay_path<T: Trait>() where T::method(..): Send {}
26+
//~^ ERROR return type not allowed with return type notation
27+
28+
fn baz_path<T: Trait>() where T::method(..): Send {}
29+
//~^ ERROR return type notation arguments must be elided with `..`
30+
31+
fn foo_qualified<T: Trait>() where T::method(..): Send {}
32+
//~^ ERROR expected associated type
33+
34+
fn bar_qualified<T: Trait>() where T::method(..): Send {}
35+
//~^ ERROR expected associated type
36+
37+
fn baz_qualified<TParam: Trait>() where TParam::method(..): Send {}
38+
//~^ ERROR expected associated type
39+
40+
fn main() {}

tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//@ edition: 2021
2-
2+
//@ run-rustfix
33
#![feature(return_type_notation)]
4+
#![allow(dead_code)]
45

56
trait Trait {
67
async fn method() {}
@@ -33,7 +34,7 @@ fn foo_qualified<T: Trait>() where <T as Trait>::method(i32): Send {}
3334
fn bar_qualified<T: Trait>() where <T as Trait>::method() -> (): Send {}
3435
//~^ ERROR expected associated type
3536

36-
fn baz_qualified<T: Trait>() where <T as Trait>::method(): Send {}
37+
fn baz_qualified<TParam: Trait>() where <TParam as Trait>::method(): Send {}
3738
//~^ ERROR expected associated type
3839

3940
fn main() {}

tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr

+30-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: return type not allowed with return type notation
2-
--> $DIR/bad-inputs-and-output.rs:24:45
2+
--> $DIR/bad-inputs-and-output.rs:25:45
33
|
44
LL | fn bay_path<T: Trait>() where T::method(..) -> (): Send {}
55
| ^^^^^
@@ -11,25 +11,43 @@ LL + fn bay_path<T: Trait>() where T::method(..): Send {}
1111
|
1212

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

1925
error[E0575]: expected associated type, found associated function `Trait::method`
20-
--> $DIR/bad-inputs-and-output.rs:33:36
26+
--> $DIR/bad-inputs-and-output.rs:34:36
2127
|
2228
LL | fn bar_qualified<T: Trait>() where <T as Trait>::method() -> (): Send {}
2329
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a associated type
30+
|
31+
help: you might have meant to use the return type notation syntax
32+
|
33+
LL - fn bar_qualified<T: Trait>() where <T as Trait>::method() -> (): Send {}
34+
LL + fn bar_qualified<T: Trait>() where T::method(..): Send {}
35+
|
2436

2537
error[E0575]: expected associated type, found associated function `Trait::method`
26-
--> $DIR/bad-inputs-and-output.rs:36:36
38+
--> $DIR/bad-inputs-and-output.rs:37:41
39+
|
40+
LL | fn baz_qualified<TParam: Trait>() where <TParam as Trait>::method(): Send {}
41+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a associated type
42+
|
43+
help: you might have meant to use the return type notation syntax
44+
|
45+
LL - fn baz_qualified<TParam: Trait>() where <TParam as Trait>::method(): Send {}
46+
LL + fn baz_qualified<TParam: Trait>() where TParam::method(..): Send {}
2747
|
28-
LL | fn baz_qualified<T: Trait>() where <T as Trait>::method(): Send {}
29-
| ^^^^^^^^^^^^^^^^^^^^^^ not a associated type
3048

3149
error: argument types not allowed with return type notation
32-
--> $DIR/bad-inputs-and-output.rs:9:23
50+
--> $DIR/bad-inputs-and-output.rs:10:23
3351
|
3452
LL | fn foo<T: Trait<method(i32): Send>>() {}
3553
| ^^^^^
@@ -41,7 +59,7 @@ LL + fn foo<T: Trait<method(..): Send>>() {}
4159
|
4260

4361
error: return type not allowed with return type notation
44-
--> $DIR/bad-inputs-and-output.rs:12:25
62+
--> $DIR/bad-inputs-and-output.rs:13:25
4563
|
4664
LL | fn bar<T: Trait<method() -> (): Send>>() {}
4765
| ^^^^^^
@@ -53,7 +71,7 @@ LL + fn bar<T: Trait<method(..): Send>>() {}
5371
|
5472

5573
error: return type notation arguments must be elided with `..`
56-
--> $DIR/bad-inputs-and-output.rs:15:23
74+
--> $DIR/bad-inputs-and-output.rs:16:23
5775
|
5876
LL | fn baz<T: Trait<method(): Send>>() {}
5977
| ^^
@@ -64,7 +82,7 @@ LL | fn baz<T: Trait<method(..): Send>>() {}
6482
| ++
6583

6684
error: argument types not allowed with return type notation
67-
--> $DIR/bad-inputs-and-output.rs:18:40
85+
--> $DIR/bad-inputs-and-output.rs:19:40
6886
|
6987
LL | fn foo_path<T: Trait>() where T::method(i32): Send {}
7088
| ^^^^^
@@ -76,7 +94,7 @@ LL + fn foo_path<T: Trait>() where T::method(..): Send {}
7694
|
7795

7896
error: return type not allowed with return type notation
79-
--> $DIR/bad-inputs-and-output.rs:21:42
97+
--> $DIR/bad-inputs-and-output.rs:22:42
8098
|
8199
LL | fn bar_path<T: Trait>() where T::method() -> (): Send {}
82100
| ^^^^^^
@@ -88,7 +106,7 @@ LL + fn bar_path<T: Trait>() where T::method(..): Send {}
88106
|
89107

90108
error: return type notation arguments must be elided with `..`
91-
--> $DIR/bad-inputs-and-output.rs:27:40
109+
--> $DIR/bad-inputs-and-output.rs:28:40
92110
|
93111
LL | fn baz_path<T: Trait>() where T::method(): Send {}
94112
| ^^

0 commit comments

Comments
 (0)