Detect ::
-> :
typo in type argument
When writing `Vec<A:B>`, suggest `Vec<A::B>`.
This commit is contained in:
parent
2681f253bc
commit
b26ad8d10f
4 changed files with 102 additions and 1 deletions
|
@ -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,
|
||||
|
|
|
@ -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 ¶ms.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],
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue