diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 2c678e71ae1..6aed3223480 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -400,6 +400,8 @@ struct DiagnosticMetadata<'ast> { /// Given `where ::Baz: String`, suggest `where T: Bar`. 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, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 7e1e5c78805..d05f139e3bf 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -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], diff --git a/src/test/ui/suggestions/type-ascription-instead-of-path-in-type.rs b/src/test/ui/suggestions/type-ascription-instead-of-path-in-type.rs new file mode 100644 index 00000000000..48d19f6dd4e --- /dev/null +++ b/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; + //~^ 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 +} diff --git a/src/test/ui/suggestions/type-ascription-instead-of-path-in-type.stderr b/src/test/ui/suggestions/type-ascription-instead-of-path-in-type.stderr new file mode 100644 index 00000000000..951ff23d635 --- /dev/null +++ b/src/test/ui/suggestions/type-ascription-instead-of-path-in-type.stderr @@ -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; + | ^ 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; + | ~~ + +error[E0658]: associated type bounds are unstable + --> $DIR/type-ascription-instead-of-path-in-type.rs:6:16 + | +LL | let _: Vec = A::B; + | ^^^ + | + = note: see issue #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; + | ^^^ 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 { + | ^^^ - +help: add missing generic argument + | +LL | let _: Vec = 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; + | ^^^ 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`.