about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2024-07-08 19:43:20 +0000
committerEsteban Küber <esteban@kuber.com.ar>2024-07-11 20:39:24 +0000
commitcbe75486f7eb6ae9fb00602f5347a09a62a7a9de (patch)
tree98bbb9812a87a5bdb586f7287fb491570de207ac
parentb56dc8ee90582d9c1322632d570b996bcb73ecda (diff)
downloadrust-cbe75486f7eb6ae9fb00602f5347a09a62a7a9de.tar.gz
rust-cbe75486f7eb6ae9fb00602f5347a09a62a7a9de.zip
Account for `let foo = expr`; to suggest `const foo: Ty = expr;`
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs8
-rw-r--r--compiler/rustc_resolve/src/errors.rs10
-rw-r--r--compiler/rustc_resolve/src/ident.rs44
-rw-r--r--compiler/rustc_resolve/src/lib.rs11
-rw-r--r--tests/ui/asm/parse-error.stderr20
-rw-r--r--tests/ui/asm/type-check-1.stderr12
-rw-r--r--tests/ui/asm/x86_64/x86_64_parse_error.stderr12
-rw-r--r--tests/ui/const-generics/legacy-const-generics-bad.stderr4
-rw-r--r--tests/ui/consts/non-const-value-in-const.stderr4
-rw-r--r--tests/ui/issues/issue-27433.fixed2
-rw-r--r--tests/ui/issues/issue-27433.rs2
-rw-r--r--tests/ui/repeat-expr/repeat_count.stderr4
-rw-r--r--tests/ui/typeof/issue-42060.stderr8
13 files changed, 85 insertions, 56 deletions
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index f879e548f27..09221041031 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -819,7 +819,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => {
                 self.dcx().create_err(errs::CannotCaptureDynamicEnvironmentInFnItem { span })
             }
-            ResolutionError::AttemptToUseNonConstantValueInConstant(ident, suggestion, current) => {
+            ResolutionError::AttemptToUseNonConstantValueInConstant {
+                ident,
+                suggestion,
+                current,
+                type_span,
+            } => {
                 // let foo =...
                 //     ^^^ given this Span
                 // ------- get this Span to have an applicable suggestion
@@ -844,6 +849,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                 span: sp,
                                 suggestion,
                                 current,
+                                type_span,
                             }), Some(errs::AttemptToUseNonConstantValueInConstantLabelWithSuggestion {span})),
                             None,
                         )
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index a4bdd62acbb..79c76e7a976 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -240,16 +240,18 @@ pub(crate) struct AttemptToUseNonConstantValueInConstant<'a> {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(
+#[multipart_suggestion(
     resolve_attempt_to_use_non_constant_value_in_constant_with_suggestion,
-    code = "{suggestion} ",
     style = "verbose",
-    applicability = "maybe-incorrect"
+    applicability = "has-placeholders"
 )]
 pub(crate) struct AttemptToUseNonConstantValueInConstantWithSuggestion<'a> {
-    #[primary_span]
+    // #[primary_span]
+    #[suggestion_part(code = "{suggestion} ")]
     pub(crate) span: Span,
     pub(crate) suggestion: &'a str,
+    #[suggestion_part(code = ": /* Type */")]
+    pub(crate) type_span: Option<Span>,
     pub(crate) current: &'a str,
 }
 
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 7d531385e21..f1934ff184b 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -1178,21 +1178,41 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                             if let Some(span) = finalize {
                                 let (span, resolution_error) = match item {
                                     None if rib_ident.as_str() == "self" => (span, LowercaseSelf),
-                                    None => (
-                                        rib_ident.span,
-                                        AttemptToUseNonConstantValueInConstant(
-                                            original_rib_ident_def,
-                                            "const",
-                                            "let",
-                                        ),
-                                    ),
+                                    None => {
+                                        // If we have a `let name = expr;`, we have the span for
+                                        // `name` and use that to see if it is followed by a type
+                                        // specifier. If not, then we know we need to suggest
+                                        // `const name: Ty = expr;`. This is a heuristic, it will
+                                        // break down in the presence of macros.
+                                        let sm = self.tcx.sess.source_map();
+                                        let type_span = match sm.span_look_ahead(
+                                            original_rib_ident_def.span,
+                                            ":",
+                                            None,
+                                        ) {
+                                            None => {
+                                                Some(original_rib_ident_def.span.shrink_to_hi())
+                                            }
+                                            Some(_) => None,
+                                        };
+                                        (
+                                            rib_ident.span,
+                                            AttemptToUseNonConstantValueInConstant {
+                                                ident: original_rib_ident_def,
+                                                suggestion: "const",
+                                                current: "let",
+                                                type_span,
+                                            },
+                                        )
+                                    }
                                     Some((ident, kind)) => (
                                         span,
-                                        AttemptToUseNonConstantValueInConstant(
+                                        AttemptToUseNonConstantValueInConstant {
                                             ident,
-                                            "let",
-                                            kind.as_str(),
-                                        ),
+                                            suggestion: "let",
+                                            current: kind.as_str(),
+                                            type_span: None,
+                                        },
                                     ),
                                 };
                                 self.report_error(span, resolution_error);
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 7cb5a3fb2fd..3dcb83d65b0 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -236,11 +236,12 @@ enum ResolutionError<'a> {
     /// Error E0434: can't capture dynamic environment in a fn item.
     CannotCaptureDynamicEnvironmentInFnItem,
     /// Error E0435: attempt to use a non-constant value in a constant.
-    AttemptToUseNonConstantValueInConstant(
-        Ident,
-        /* suggestion */ &'static str,
-        /* current */ &'static str,
-    ),
+    AttemptToUseNonConstantValueInConstant {
+        ident: Ident,
+        suggestion: &'static str,
+        current: &'static str,
+        type_span: Option<Span>,
+    },
     /// Error E0530: `X` bindings cannot shadow `Y`s.
     BindingShadowsSomethingUnacceptable {
         shadowing_binding: PatternSource,
diff --git a/tests/ui/asm/parse-error.stderr b/tests/ui/asm/parse-error.stderr
index 8030face1d2..1999cd09aa3 100644
--- a/tests/ui/asm/parse-error.stderr
+++ b/tests/ui/asm/parse-error.stderr
@@ -376,8 +376,8 @@ LL |         asm!("{}", options(), const foo);
    |
 help: consider using `const` instead of `let`
    |
-LL |     const foo = 0;
-   |     ~~~~~
+LL |     const foo: /* Type */ = 0;
+   |     ~~~~~    ++++++++++++
 
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:71:44
@@ -387,8 +387,8 @@ LL |         asm!("{}", clobber_abi("C"), const foo);
    |
 help: consider using `const` instead of `let`
    |
-LL |     const foo = 0;
-   |     ~~~~~
+LL |     const foo: /* Type */ = 0;
+   |     ~~~~~    ++++++++++++
 
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:74:55
@@ -398,8 +398,8 @@ LL |         asm!("{}", options(), clobber_abi("C"), const foo);
    |
 help: consider using `const` instead of `let`
    |
-LL |     const foo = 0;
-   |     ~~~~~
+LL |     const foo: /* Type */ = 0;
+   |     ~~~~~    ++++++++++++
 
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:76:31
@@ -409,8 +409,8 @@ LL |         asm!("{a}", a = const foo, a = const bar);
    |
 help: consider using `const` instead of `let`
    |
-LL |     const foo = 0;
-   |     ~~~~~
+LL |     const foo: /* Type */ = 0;
+   |     ~~~~~    ++++++++++++
 
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:76:46
@@ -420,8 +420,8 @@ LL |         asm!("{a}", a = const foo, a = const bar);
    |
 help: consider using `const` instead of `let`
    |
-LL |     const bar = 0;
-   |     ~~~~~
+LL |     const bar: /* Type */ = 0;
+   |     ~~~~~    ++++++++++++
 
 error: aborting due to 64 previous errors
 
diff --git a/tests/ui/asm/type-check-1.stderr b/tests/ui/asm/type-check-1.stderr
index deba9e0fc54..18526232118 100644
--- a/tests/ui/asm/type-check-1.stderr
+++ b/tests/ui/asm/type-check-1.stderr
@@ -6,8 +6,8 @@ LL |         asm!("{}", const x);
    |
 help: consider using `const` instead of `let`
    |
-LL |         const x = 0;
-   |         ~~~~~
+LL |         const x: /* Type */ = 0;
+   |         ~~~~~  ++++++++++++
 
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/type-check-1.rs:44:36
@@ -17,8 +17,8 @@ LL |         asm!("{}", const const_foo(x));
    |
 help: consider using `const` instead of `let`
    |
-LL |         const x = 0;
-   |         ~~~~~
+LL |         const x: /* Type */ = 0;
+   |         ~~~~~  ++++++++++++
 
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/type-check-1.rs:47:36
@@ -28,8 +28,8 @@ LL |         asm!("{}", const const_bar(x));
    |
 help: consider using `const` instead of `let`
    |
-LL |         const x = 0;
-   |         ~~~~~
+LL |         const x: /* Type */ = 0;
+   |         ~~~~~  ++++++++++++
 
 error: invalid `sym` operand
   --> $DIR/type-check-1.rs:49:24
diff --git a/tests/ui/asm/x86_64/x86_64_parse_error.stderr b/tests/ui/asm/x86_64/x86_64_parse_error.stderr
index 95b86d533fa..9751f7b09d0 100644
--- a/tests/ui/asm/x86_64/x86_64_parse_error.stderr
+++ b/tests/ui/asm/x86_64/x86_64_parse_error.stderr
@@ -20,8 +20,8 @@ LL |         asm!("{a}", in("eax") foo, a = const bar);
    |
 help: consider using `const` instead of `let`
    |
-LL |     const bar = 0;
-   |     ~~~~~
+LL |     const bar: /* Type */ = 0;
+   |     ~~~~~    ++++++++++++
 
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/x86_64_parse_error.rs:15:46
@@ -31,8 +31,8 @@ LL |         asm!("{a}", in("eax") foo, a = const bar);
    |
 help: consider using `const` instead of `let`
    |
-LL |     const bar = 0;
-   |     ~~~~~
+LL |     const bar: /* Type */ = 0;
+   |     ~~~~~    ++++++++++++
 
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/x86_64_parse_error.rs:17:42
@@ -42,8 +42,8 @@ LL |         asm!("{1}", in("eax") foo, const bar);
    |
 help: consider using `const` instead of `let`
    |
-LL |     const bar = 0;
-   |     ~~~~~
+LL |     const bar: /* Type */ = 0;
+   |     ~~~~~    ++++++++++++
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/const-generics/legacy-const-generics-bad.stderr b/tests/ui/const-generics/legacy-const-generics-bad.stderr
index 6285d478071..e9ea22e472c 100644
--- a/tests/ui/const-generics/legacy-const-generics-bad.stderr
+++ b/tests/ui/const-generics/legacy-const-generics-bad.stderr
@@ -6,8 +6,8 @@ LL |     legacy_const_generics::foo(0, a, 2);
    |
 help: consider using `const` instead of `let`
    |
-LL |     const a = 1;
-   |     ~~~~~
+LL |     const a: /* Type */ = 1;
+   |     ~~~~~  ++++++++++++
 
 error: generic parameters may not be used in const operations
   --> $DIR/legacy-const-generics-bad.rs:12:35
diff --git a/tests/ui/consts/non-const-value-in-const.stderr b/tests/ui/consts/non-const-value-in-const.stderr
index ee9ac16fe42..654b573544c 100644
--- a/tests/ui/consts/non-const-value-in-const.stderr
+++ b/tests/ui/consts/non-const-value-in-const.stderr
@@ -17,8 +17,8 @@ LL |     let _ = [0; x];
    |
 help: consider using `const` instead of `let`
    |
-LL |     const x = 5;
-   |     ~~~~~
+LL |     const x: /* Type */ = 5;
+   |     ~~~~~  ++++++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/issues/issue-27433.fixed b/tests/ui/issues/issue-27433.fixed
index ff6704e393b..f847b698976 100644
--- a/tests/ui/issues/issue-27433.fixed
+++ b/tests/ui/issues/issue-27433.fixed
@@ -3,5 +3,5 @@ fn main() {
     let foo = 42u32;
     #[allow(unused_variables, non_snake_case)]
     let FOO : u32 = foo;
-                   //~^ ERROR attempt to use a non-constant value in a constant
+    //~^ ERROR attempt to use a non-constant value in a constant
 }
diff --git a/tests/ui/issues/issue-27433.rs b/tests/ui/issues/issue-27433.rs
index 2a34b43f58d..9bbc5bcbb45 100644
--- a/tests/ui/issues/issue-27433.rs
+++ b/tests/ui/issues/issue-27433.rs
@@ -3,5 +3,5 @@ fn main() {
     let foo = 42u32;
     #[allow(unused_variables, non_snake_case)]
     const FOO : u32 = foo;
-                   //~^ ERROR attempt to use a non-constant value in a constant
+    //~^ ERROR attempt to use a non-constant value in a constant
 }
diff --git a/tests/ui/repeat-expr/repeat_count.stderr b/tests/ui/repeat-expr/repeat_count.stderr
index 9b5afc55735..350ac287507 100644
--- a/tests/ui/repeat-expr/repeat_count.stderr
+++ b/tests/ui/repeat-expr/repeat_count.stderr
@@ -6,8 +6,8 @@ LL |     let a = [0; n];
    |
 help: consider using `const` instead of `let`
    |
-LL |     const n = 1;
-   |     ~~~~~
+LL |     const n: /* Type */ = 1;
+   |     ~~~~~  ++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/repeat_count.rs:7:17
diff --git a/tests/ui/typeof/issue-42060.stderr b/tests/ui/typeof/issue-42060.stderr
index 7af65633f71..86ba9432384 100644
--- a/tests/ui/typeof/issue-42060.stderr
+++ b/tests/ui/typeof/issue-42060.stderr
@@ -6,8 +6,8 @@ LL |     let other: typeof(thing) = thing;
    |
 help: consider using `const` instead of `let`
    |
-LL |     const thing = ();
-   |     ~~~~~
+LL |     const thing: /* Type */ = ();
+   |     ~~~~~      ++++++++++++
 
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/issue-42060.rs:9:13
@@ -17,8 +17,8 @@ LL |     <typeof(q)>::N
    |
 help: consider using `const` instead of `let`
    |
-LL |     const q = 1;
-   |     ~~~~~
+LL |     const q: /* Type */ = 1;
+   |     ~~~~~  ++++++++++++
 
 error[E0516]: `typeof` is a reserved keyword but unimplemented
   --> $DIR/issue-42060.rs:3:16