Skip to content

Commit b26ad8d

Browse files
committed
Detect :: -> : typo in type argument
When writing `Vec<A:B>`, suggest `Vec<A::B>`.
1 parent 2681f25 commit b26ad8d

File tree

4 files changed

+102
-1
lines changed

4 files changed

+102
-1
lines changed

compiler/rustc_resolve/src/late.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,8 @@ struct DiagnosticMetadata<'ast> {
400400

401401
/// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`.
402402
current_where_predicate: Option<&'ast WherePredicate>,
403+
404+
current_type_path: Option<&'ast Ty>,
403405
}
404406

405407
struct LateResolutionVisitor<'a, 'b, 'ast> {
@@ -472,8 +474,10 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
472474
}
473475
fn visit_ty(&mut self, ty: &'ast Ty) {
474476
let prev = self.diagnostic_metadata.current_trait_object;
477+
let prev_ty = self.diagnostic_metadata.current_type_path;
475478
match ty.kind {
476479
TyKind::Path(ref qself, ref path) => {
480+
self.diagnostic_metadata.current_type_path = Some(ty);
477481
self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
478482
}
479483
TyKind::ImplicitSelf => {
@@ -490,6 +494,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
490494
}
491495
visit::walk_ty(self, ty);
492496
self.diagnostic_metadata.current_trait_object = prev;
497+
self.diagnostic_metadata.current_type_path = prev_ty;
493498
}
494499
fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) {
495500
self.smart_resolve_path(
@@ -1936,7 +1941,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
19361941
let instead = res.is_some();
19371942
let suggestion =
19381943
if res.is_none() { this.report_missing_type_error(path) } else { None };
1939-
// get_from_node_id
19401944

19411945
this.r.use_injections.push(UseError {
19421946
err,

compiler/rustc_resolve/src/late/diagnostics.rs

+37
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
2626
use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
2727

2828
use std::iter;
29+
use std::ops::Deref;
2930

3031
use tracing::debug;
3132

@@ -265,6 +266,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
265266
}
266267
}
267268

269+
self.detect_assoct_type_constraint_meant_as_path(base_span, &mut err);
270+
268271
// Emit special messages for unresolved `Self` and `self`.
269272
if is_self_type(path, ns) {
270273
err.code(rustc_errors::error_code!(E0411));
@@ -603,6 +606,40 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
603606
(err, candidates)
604607
}
605608

609+
fn detect_assoct_type_constraint_meant_as_path(
610+
&self,
611+
base_span: Span,
612+
err: &mut DiagnosticBuilder<'_>,
613+
) {
614+
let Some(ty) = self.diagnostic_metadata.current_type_path else { return; };
615+
let TyKind::Path(_, path) = &ty.kind else { return; };
616+
for segment in &path.segments {
617+
let Some(params) = &segment.args else { continue; };
618+
let ast::GenericArgs::AngleBracketed(ref params) = params.deref() else { continue; };
619+
for param in &params.args {
620+
let ast::AngleBracketedArg::Constraint(constraint) = param else { continue; };
621+
let ast::AssocConstraintKind::Bound { bounds } = &constraint.kind else {
622+
continue;
623+
};
624+
for bound in bounds {
625+
let ast::GenericBound::Trait(trait_ref, ast::TraitBoundModifier::None)
626+
= bound else
627+
{
628+
continue;
629+
};
630+
if base_span == trait_ref.span {
631+
err.span_suggestion_verbose(
632+
constraint.ident.span.between(trait_ref.span),
633+
"you might have meant to write a path instead of an associated type bound",
634+
"::".to_string(),
635+
Applicability::MachineApplicable,
636+
);
637+
}
638+
}
639+
}
640+
}
641+
}
642+
606643
fn get_single_associated_item(
607644
&mut self,
608645
path: &[Segment],
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
enum A {
2+
B,
3+
}
4+
5+
fn main() {
6+
let _: Vec<A:B> = A::B;
7+
//~^ ERROR cannot find trait `B` in this scope
8+
//~| HELP you might have meant to write a path instead of an associated type bound
9+
//~| ERROR associated type bounds are unstable
10+
//~| HELP add `#![feature(associated_type_bounds)]` to the crate attributes to enable
11+
//~| ERROR struct takes at least 1 generic argument but 0 generic arguments were supplied
12+
//~| HELP add missing generic argument
13+
//~| ERROR associated type bindings are not allowed here
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
error[E0405]: cannot find trait `B` in this scope
2+
--> $DIR/type-ascription-instead-of-path-in-type.rs:6:18
3+
|
4+
LL | let _: Vec<A:B> = A::B;
5+
| ^ not found in this scope
6+
|
7+
help: you might have meant to write a path instead of an associated type bound
8+
|
9+
LL | let _: Vec<A::B> = A::B;
10+
| ~~
11+
12+
error[E0658]: associated type bounds are unstable
13+
--> $DIR/type-ascription-instead-of-path-in-type.rs:6:16
14+
|
15+
LL | let _: Vec<A:B> = A::B;
16+
| ^^^
17+
|
18+
= note: see issue #52662 <https://github.com/rust-lang/rust/issues/52662> for more information
19+
= help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
20+
21+
error[E0107]: this struct takes at least 1 generic argument but 0 generic arguments were supplied
22+
--> $DIR/type-ascription-instead-of-path-in-type.rs:6:12
23+
|
24+
LL | let _: Vec<A:B> = A::B;
25+
| ^^^ expected at least 1 generic argument
26+
|
27+
note: struct defined here, with at least 1 generic parameter: `T`
28+
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
29+
|
30+
LL | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
31+
| ^^^ -
32+
help: add missing generic argument
33+
|
34+
LL | let _: Vec<T, A:B> = A::B;
35+
| ++
36+
37+
error[E0229]: associated type bindings are not allowed here
38+
--> $DIR/type-ascription-instead-of-path-in-type.rs:6:16
39+
|
40+
LL | let _: Vec<A:B> = A::B;
41+
| ^^^ associated type not allowed here
42+
43+
error: aborting due to 4 previous errors
44+
45+
Some errors have detailed explanations: E0107, E0229, E0405, E0658.
46+
For more information about an error, try `rustc --explain E0107`.

0 commit comments

Comments
 (0)