Detect :: -> : typo in type argument

When writing `Vec<A:B>`, suggest `Vec<A::B>`.
This commit is contained in:
Esteban Kuber 2022-01-11 21:56:10 +00:00
parent 2681f253bc
commit b26ad8d10f
4 changed files with 102 additions and 1 deletions

View file

@ -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> {
@ -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 => {
@ -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(
@ -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,

View file

@ -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;
@ -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));
@ -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],