about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2022-08-03 09:29:29 -0700
committerEsteban Küber <esteban@kuber.com.ar>2022-08-03 09:29:29 -0700
commit939c2b63137e4b4f8c35d7cdc2b2d8bbb491e2dd (patch)
tree2fed9e24903051eae60f8453b2cc0cb8a4ee1cef
parent7308c22c6a8d77e82187e290e1f7459870e48d12 (diff)
downloadrust-939c2b63137e4b4f8c35d7cdc2b2d8bbb491e2dd.tar.gz
rust-939c2b63137e4b4f8c35d7cdc2b2d8bbb491e2dd.zip
Provide suggestion on missing `let` in binding statement
Fix #78907.
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs30
-rw-r--r--src/test/ui/type/missing-let-in-binding.fixed5
-rw-r--r--src/test/ui/type/missing-let-in-binding.rs5
-rw-r--r--src/test/ui/type/missing-let-in-binding.stderr16
4 files changed, 53 insertions, 3 deletions
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index ad9ed798e55..6e33c261a03 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -2,7 +2,7 @@ use rustc_ast as ast;
 use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
 use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId};
 use rustc_ast::{PatKind, RangeEnd, VariantData};
-use rustc_errors::struct_span_err;
+use rustc_errors::{struct_span_err, Applicability};
 use rustc_feature::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
 use rustc_feature::{Features, GateIssue};
 use rustc_session::parse::{feature_err, feature_err_issue};
@@ -577,6 +577,32 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
         }
     }
 
+    fn visit_stmt(&mut self, stmt: &'a ast::Stmt) {
+        if let ast::StmtKind::Semi(expr) = &stmt.kind
+            && let ast::ExprKind::Assign(lhs, _, _) = &expr.kind
+            && let ast::ExprKind::Type(..) = lhs.kind
+            && self.sess.parse_sess.span_diagnostic.err_count() == 0
+            && !self.features.type_ascription
+            && !lhs.span.allows_unstable(sym::type_ascription)
+        {
+            // When we encounter a statement of the form `foo: Ty = val;`, this will emit a type
+            // ascription error, but the likely intention was to write a `let` statement. (#78907).
+            feature_err_issue(
+                &self.sess.parse_sess,
+                sym::type_ascription,
+                lhs.span,
+                GateIssue::Language,
+                "type ascription is experimental",
+            ).span_suggestion_verbose(
+                lhs.span.shrink_to_lo(),
+                "you might have meant to introduce a new binding",
+                "let ".to_string(),
+                Applicability::MachineApplicable,
+            ).emit();
+        }
+        visit::walk_stmt(self, stmt);
+    }
+
     fn visit_expr(&mut self, e: &'a ast::Expr) {
         match e.kind {
             ast::ExprKind::Box(_) => {
@@ -795,8 +821,6 @@ fn maybe_stage_features(sess: &Session, krate: &ast::Crate) {
     // checks if `#![feature]` has been used to enable any lang feature
     // does not check the same for lib features unless there's at least one
     // declared lang feature
-    use rustc_errors::Applicability;
-
     if !sess.opts.unstable_features.is_nightly_build() {
         let lang_features = &sess.features_untracked().declared_lang_features;
         if lang_features.len() == 0 {
diff --git a/src/test/ui/type/missing-let-in-binding.fixed b/src/test/ui/type/missing-let-in-binding.fixed
new file mode 100644
index 00000000000..d1787688950
--- /dev/null
+++ b/src/test/ui/type/missing-let-in-binding.fixed
@@ -0,0 +1,5 @@
+// run-rustfix
+fn main() {
+    let mut _foo: i32 = 1;
+    let _foo: i32 = 4; //~ ERROR type ascription is experimental
+}
diff --git a/src/test/ui/type/missing-let-in-binding.rs b/src/test/ui/type/missing-let-in-binding.rs
new file mode 100644
index 00000000000..ca42f2e6eac
--- /dev/null
+++ b/src/test/ui/type/missing-let-in-binding.rs
@@ -0,0 +1,5 @@
+// run-rustfix
+fn main() {
+    let mut _foo: i32 = 1;
+    _foo: i32 = 4; //~ ERROR type ascription is experimental
+}
diff --git a/src/test/ui/type/missing-let-in-binding.stderr b/src/test/ui/type/missing-let-in-binding.stderr
new file mode 100644
index 00000000000..12759c5096e
--- /dev/null
+++ b/src/test/ui/type/missing-let-in-binding.stderr
@@ -0,0 +1,16 @@
+error[E0658]: type ascription is experimental
+  --> $DIR/missing-let-in-binding.rs:4:5
+   |
+LL |     _foo: i32 = 4;
+   |     ^^^^^^^^^
+   |
+   = note: see issue #23416 <https://github.com/rust-lang/rust/issues/23416> for more information
+   = help: add `#![feature(type_ascription)]` to the crate attributes to enable
+help: you might have meant to introduce a new binding
+   |
+LL |     let _foo: i32 = 4;
+   |     +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.