Skip to content

Commit

Permalink
Detect :: -> : typo in type argument
Browse files Browse the repository at this point in the history
When writing `Vec<A:B>`, suggest `Vec<A::B>`.
  • Loading branch information
estebank committed Feb 2, 2022
1 parent 2681f25 commit b26ad8d
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 1 deletion.
6 changes: 5 additions & 1 deletion compiler/rustc_resolve/src/late.rs
Expand Up @@ -400,6 +400,8 @@ struct DiagnosticMetadata<'ast> {

/// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`.
current_where_predicate: Option<&'ast WherePredicate>,

current_type_path: Option<&'ast Ty>,
}

struct LateResolutionVisitor<'a, 'b, 'ast> {
Expand Down Expand Up @@ -472,8 +474,10 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
}
fn visit_ty(&mut self, ty: &'ast Ty) {
let prev = self.diagnostic_metadata.current_trait_object;
let prev_ty = self.diagnostic_metadata.current_type_path;
match ty.kind {
TyKind::Path(ref qself, ref path) => {
self.diagnostic_metadata.current_type_path = Some(ty);
self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
}
TyKind::ImplicitSelf => {
Expand All @@ -490,6 +494,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
}
visit::walk_ty(self, ty);
self.diagnostic_metadata.current_trait_object = prev;
self.diagnostic_metadata.current_type_path = prev_ty;
}
fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) {
self.smart_resolve_path(
Expand Down Expand Up @@ -1936,7 +1941,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
let instead = res.is_some();
let suggestion =
if res.is_none() { this.report_missing_type_error(path) } else { None };
// get_from_node_id

this.r.use_injections.push(UseError {
err,
Expand Down
37 changes: 37 additions & 0 deletions compiler/rustc_resolve/src/late/diagnostics.rs
Expand Up @@ -26,6 +26,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};

use std::iter;
use std::ops::Deref;

use tracing::debug;

Expand Down Expand Up @@ -265,6 +266,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
}
}

self.detect_assoct_type_constraint_meant_as_path(base_span, &mut err);

// Emit special messages for unresolved `Self` and `self`.
if is_self_type(path, ns) {
err.code(rustc_errors::error_code!(E0411));
Expand Down Expand Up @@ -603,6 +606,40 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
(err, candidates)
}

fn detect_assoct_type_constraint_meant_as_path(
&self,
base_span: Span,
err: &mut DiagnosticBuilder<'_>,
) {
let Some(ty) = self.diagnostic_metadata.current_type_path else { return; };
let TyKind::Path(_, path) = &ty.kind else { return; };
for segment in &path.segments {
let Some(params) = &segment.args else { continue; };
let ast::GenericArgs::AngleBracketed(ref params) = params.deref() else { continue; };
for param in &params.args {
let ast::AngleBracketedArg::Constraint(constraint) = param else { continue; };
let ast::AssocConstraintKind::Bound { bounds } = &constraint.kind else {
continue;
};
for bound in bounds {
let ast::GenericBound::Trait(trait_ref, ast::TraitBoundModifier::None)
= bound else
{
continue;
};
if base_span == trait_ref.span {
err.span_suggestion_verbose(
constraint.ident.span.between(trait_ref.span),
"you might have meant to write a path instead of an associated type bound",
"::".to_string(),
Applicability::MachineApplicable,
);
}
}
}
}
}

fn get_single_associated_item(
&mut self,
path: &[Segment],
Expand Down
14 changes: 14 additions & 0 deletions src/test/ui/suggestions/type-ascription-instead-of-path-in-type.rs
@@ -0,0 +1,14 @@
enum A {
B,
}

fn main() {
let _: Vec<A:B> = A::B;
//~^ ERROR cannot find trait `B` in this scope
//~| HELP you might have meant to write a path instead of an associated type bound
//~| ERROR associated type bounds are unstable
//~| HELP add `#![feature(associated_type_bounds)]` to the crate attributes to enable
//~| ERROR struct takes at least 1 generic argument but 0 generic arguments were supplied
//~| HELP add missing generic argument
//~| ERROR associated type bindings are not allowed here
}
@@ -0,0 +1,46 @@
error[E0405]: cannot find trait `B` in this scope
--> $DIR/type-ascription-instead-of-path-in-type.rs:6:18
|
LL | let _: Vec<A:B> = A::B;
| ^ not found in this scope
|
help: you might have meant to write a path instead of an associated type bound
|
LL | let _: Vec<A::B> = A::B;
| ~~

error[E0658]: associated type bounds are unstable
--> $DIR/type-ascription-instead-of-path-in-type.rs:6:16
|
LL | let _: Vec<A:B> = A::B;
| ^^^
|
= note: see issue #52662 <https://github.com/rust-lang/rust/issues/52662> for more information
= help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable

error[E0107]: this struct takes at least 1 generic argument but 0 generic arguments were supplied
--> $DIR/type-ascription-instead-of-path-in-type.rs:6:12
|
LL | let _: Vec<A:B> = A::B;
| ^^^ expected at least 1 generic argument
|
note: struct defined here, with at least 1 generic parameter: `T`
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
LL | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
| ^^^ -
help: add missing generic argument
|
LL | let _: Vec<T, A:B> = A::B;
| ++

error[E0229]: associated type bindings are not allowed here
--> $DIR/type-ascription-instead-of-path-in-type.rs:6:16
|
LL | let _: Vec<A:B> = A::B;
| ^^^ associated type not allowed here

error: aborting due to 4 previous errors

Some errors have detailed explanations: E0107, E0229, E0405, E0658.
For more information about an error, try `rustc --explain E0107`.

0 comments on commit b26ad8d

Please sign in to comment.