about summary refs log tree commit diff
path: root/compiler/rustc_resolve
diff options
context:
space:
mode:
authorLeón Orell Valerian Liehr <me@fmease.dev>2024-02-02 02:49:13 +0100
committerLeón Orell Valerian Liehr <me@fmease.dev>2024-02-02 03:25:04 +0100
commit5906237b32a83a1df215b87bbafcc926bf49cd66 (patch)
treed3355ec0af3ea3972d7b21dea577e380180f9515 /compiler/rustc_resolve
parent3f7b1a5f491a66365e9973babc1b3dde2c90ad55 (diff)
downloadrust-5906237b32a83a1df215b87bbafcc926bf49cd66.tar.gz
rust-5906237b32a83a1df215b87bbafcc926bf49cd66.zip
Suggest changing ty to const params if appropriate
Diffstat (limited to 'compiler/rustc_resolve')
-rw-r--r--compiler/rustc_resolve/messages.ftl3
-rw-r--r--compiler/rustc_resolve/src/errors.rs15
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs50
3 files changed, 67 insertions, 1 deletions
diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl
index c8ec10cad17..02847a0f5f9 100644
--- a/compiler/rustc_resolve/messages.ftl
+++ b/compiler/rustc_resolve/messages.ftl
@@ -289,6 +289,9 @@ resolve_underscore_lifetime_name_cannot_be_used_here =
     `'_` cannot be used here
     .note = `'_` is a reserved lifetime name
 
+resolve_unexpected_res_change_ty_to_const_param_sugg =
+    you might have meant to write a const parameter here
+
 resolve_unreachable_label =
     use of unreachable label `{$name}`
     .label = unreachable label `{$name}`
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index 50ff09feb4d..655fc9812d7 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -1,4 +1,4 @@
-use rustc_errors::codes::*;
+use rustc_errors::{codes::*, Applicability};
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_span::{
     symbol::{Ident, Symbol},
@@ -787,3 +787,16 @@ pub(crate) struct IsNotDirectlyImportable {
     pub(crate) span: Span,
     pub(crate) target: Ident,
 }
+
+#[derive(Subdiagnostic)]
+#[suggestion(
+    resolve_unexpected_res_change_ty_to_const_param_sugg,
+    code = "const ",
+    style = "verbose"
+)]
+pub(crate) struct UnexpectedResChangeTyToConstParamSugg {
+    #[primary_span]
+    pub span: Span,
+    #[applicability]
+    pub applicability: Applicability,
+}
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 64e2b6a4971..9f810741f49 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -444,6 +444,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
         }
 
         self.suggest_bare_struct_literal(&mut err);
+        self.suggest_changing_type_to_const_param(&mut err, res, source, span);
 
         if self.suggest_pattern_match_with_let(&mut err, source, span) {
             // Fallback label.
@@ -1138,6 +1139,55 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
         }
     }
 
+    fn suggest_changing_type_to_const_param(
+        &mut self,
+        err: &mut Diagnostic,
+        res: Option<Res>,
+        source: PathSource<'_>,
+        span: Span,
+    ) {
+        let PathSource::Trait(_) = source else { return };
+
+        // We don't include `DefKind::Str` and `DefKind::AssocTy` as they can't be reached here anyway.
+        let applicability = match res {
+            Some(Res::PrimTy(PrimTy::Int(_) | PrimTy::Uint(_) | PrimTy::Bool | PrimTy::Char)) => {
+                Applicability::MachineApplicable
+            }
+            // FIXME(const_generics): Add `DefKind::TyParam` and `SelfTyParam` once we support generic
+            // const generics. Of course, `Struct` and `Enum` may contain ty params, too, but the
+            // benefits of including them here outweighs the small number of false positives.
+            Some(Res::Def(DefKind::Struct | DefKind::Enum, _))
+                if self.r.tcx.features().adt_const_params =>
+            {
+                Applicability::MaybeIncorrect
+            }
+            _ => return,
+        };
+
+        let Some(item) = self.diagnostic_metadata.current_item else { return };
+        let Some(generics) = item.kind.generics() else { return };
+
+        let param = generics.params.iter().find_map(|param| {
+            // Only consider type params with exactly one trait bound.
+            if let [bound] = &*param.bounds
+                && let ast::GenericBound::Trait(tref, ast::TraitBoundModifiers::NONE) = bound
+                && tref.span == span
+                && param.ident.span.eq_ctxt(span)
+            {
+                Some(param.ident.span)
+            } else {
+                None
+            }
+        });
+
+        if let Some(param) = param {
+            err.subdiagnostic(errors::UnexpectedResChangeTyToConstParamSugg {
+                span: param.shrink_to_lo(),
+                applicability,
+            });
+        }
+    }
+
     fn suggest_pattern_match_with_let(
         &mut self,
         err: &mut Diagnostic,