]> git.lizzy.rs Git - rust.git/blobdiff - compiler/rustc_resolve/src/late.rs
Detect bare blocks with type ascription that were meant to be a `struct` literal
[rust.git] / compiler / rustc_resolve / src / late.rs
index 0b552aa07f5179062631d70ea8347ffda0a206dd..fed739d186c443538971883aa00522ef962d6da3 100644 (file)
@@ -383,6 +383,11 @@ struct DiagnosticMetadata<'ast> {
     /// Only used for better errors on `fn(): fn()`.
     current_type_ascription: Vec<Span>,
 
+    /// Only used for better errors on `let x = { foo: bar };`.
+    /// In the case of a parse error with `let x = { foo: bar, };`, this isn't needed, it's only
+    /// needed for cases where this parses as a correct type ascription.
+    current_block_could_be_bare_struct_literal: Option<Span>,
+
     /// Only used for better errors on `let <pat>: <expr, not type>;`.
     current_let_binding: Option<(Span, Option<Span>, Option<Span>)>,
 
@@ -454,7 +459,7 @@ fn visit_local(&mut self, local: &'ast Local) {
             _ => Some((
                 local.pat.span,
                 local.ty.as_ref().map(|ty| ty.span),
-                local.init.as_ref().map(|init| init.span),
+                local.kind.init().map(|init| init.span),
             )),
         };
         let original = replace(&mut self.diagnostic_metadata.current_let_binding, local_spans);
@@ -1426,7 +1431,14 @@ fn resolve_local(&mut self, local: &'ast Local) {
         walk_list!(self, visit_ty, &local.ty);
 
         // Resolve the initializer.
-        walk_list!(self, visit_expr, &local.init);
+        if let Some((init, els)) = local.kind.init_else_opt() {
+            self.visit_expr(init);
+
+            // Resolve the `else` block
+            if let Some(els) = els {
+                self.visit_block(els);
+            }
+        }
 
         // Resolve the pattern.
         self.resolve_pattern_top(&local.pat, PatternSource::Let);
@@ -1852,6 +1864,7 @@ fn smart_resolve_path_fragment(
                 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,
@@ -2235,6 +2248,15 @@ fn resolve_block(&mut self, block: &'ast Block) {
             self.ribs[ValueNS].push(Rib::new(NormalRibKind));
         }
 
+        let prev = self.diagnostic_metadata.current_block_could_be_bare_struct_literal.take();
+        if let (true, [Stmt { kind: StmtKind::Expr(expr), .. }]) =
+            (block.could_be_bare_literal, &block.stmts[..])
+        {
+            if let ExprKind::Type(..) = expr.kind {
+                self.diagnostic_metadata.current_block_could_be_bare_struct_literal =
+                    Some(block.span);
+            }
+        }
         // Descend into the block.
         for stmt in &block.stmts {
             if let StmtKind::Item(ref item) = stmt.kind {
@@ -2248,6 +2270,7 @@ fn resolve_block(&mut self, block: &'ast Block) {
 
             self.visit_stmt(stmt);
         }
+        self.diagnostic_metadata.current_block_could_be_bare_struct_literal = prev;
 
         // Move back up.
         self.parent_scope.module = orig_module;