about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast_pretty/src/pp.rs46
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs4
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs4
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs39
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs8
-rw-r--r--compiler/rustc_typeck/src/check/demand.rs184
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs4
7 files changed, 161 insertions, 128 deletions
diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs
index ea298d28e72..20954a322a5 100644
--- a/compiler/rustc_ast_pretty/src/pp.rs
+++ b/compiler/rustc_ast_pretty/src/pp.rs
@@ -222,29 +222,6 @@ struct PrintStackElem {
 
 const SIZE_INFINITY: isize = 0xffff;
 
-pub fn mk_printer() -> Printer {
-    let linewidth = 78;
-    // Yes 55, it makes the ring buffers big enough to never fall behind.
-    let n: usize = 55 * linewidth;
-    debug!("mk_printer {}", linewidth);
-    Printer {
-        out: String::new(),
-        buf_max_len: n,
-        margin: linewidth as isize,
-        space: linewidth as isize,
-        left: 0,
-        right: 0,
-        // Initialize a single entry; advance_right() will extend it on demand
-        // up to `buf_max_len` elements.
-        buf: vec![BufEntry::default()],
-        left_total: 0,
-        right_total: 0,
-        scan_stack: VecDeque::new(),
-        print_stack: Vec::new(),
-        pending_indentation: 0,
-    }
-}
-
 pub struct Printer {
     out: String,
     buf_max_len: usize,
@@ -288,6 +265,29 @@ impl Default for BufEntry {
 }
 
 impl Printer {
+    pub fn new() -> Self {
+        let linewidth = 78;
+        // Yes 55, it makes the ring buffers big enough to never fall behind.
+        let n: usize = 55 * linewidth;
+        debug!("Printer::new {}", linewidth);
+        Printer {
+            out: String::new(),
+            buf_max_len: n,
+            margin: linewidth as isize,
+            space: linewidth as isize,
+            left: 0,
+            right: 0,
+            // Initialize a single entry; advance_right() will extend it on demand
+            // up to `buf_max_len` elements.
+            buf: vec![BufEntry::default()],
+            left_total: 0,
+            right_total: 0,
+            scan_stack: VecDeque::new(),
+            print_stack: Vec::new(),
+            pending_indentation: 0,
+        }
+    }
+
     pub fn last_token(&self) -> Token {
         self.buf[self.right].token.clone()
     }
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 32a4a0751d8..015cd431deb 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -103,7 +103,7 @@ pub fn print_crate<'a>(
     edition: Edition,
 ) -> String {
     let mut s =
-        State { s: pp::mk_printer(), comments: Some(Comments::new(sm, filename, input)), ann };
+        State { s: pp::Printer::new(), comments: Some(Comments::new(sm, filename, input)), ann };
 
     if is_expanded && !krate.attrs.iter().any(|attr| attr.has_name(sym::no_core)) {
         // We need to print `#![no_std]` (and its feature gate) so that
@@ -910,7 +910,7 @@ impl<'a> PrintState<'a> for State<'a> {
 
 impl<'a> State<'a> {
     pub fn new() -> State<'a> {
-        State { s: pp::mk_printer(), comments: None, ann: &NoAnn }
+        State { s: pp::Printer::new(), comments: None, ann: &NoAnn }
     }
 
     crate fn commasep_cmnt<T, F, G>(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G)
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 1fd226291d1..dabab073551 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -170,7 +170,7 @@ impl<'a> State<'a> {
         ann: &'a dyn PpAnn,
     ) -> State<'a> {
         State {
-            s: pp::mk_printer(),
+            s: pp::Printer::new(),
             comments: Some(Comments::new(sm, filename, input)),
             attrs,
             ann,
@@ -186,7 +186,7 @@ pub fn to_string<F>(ann: &dyn PpAnn, f: F) -> String
 where
     F: FnOnce(&mut State<'_>),
 {
-    let mut printer = State { s: pp::mk_printer(), comments: None, attrs: &|_| &[], ann };
+    let mut printer = State { s: pp::Printer::new(), comments: None, attrs: &|_| &[], ann };
     f(&mut printer);
     printer.s.eof()
 }
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 612d4508565..c41f2d3299b 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -27,7 +27,7 @@ use std::mem::take;
 use tracing::{debug, trace};
 
 const TURBOFISH_SUGGESTION_STR: &str =
-    "use `::<...>` instead of `<...>` to specify type or const arguments";
+    "use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments";
 
 /// Creates a placeholder argument.
 pub(super) fn dummy_arg(ident: Ident) -> Param {
@@ -731,21 +731,28 @@ impl<'a> Parser<'a> {
                     match x {
                         Ok((_, _, false)) => {
                             if self.eat(&token::Gt) {
-                                match self.parse_expr() {
-                                    Ok(_) => {
-                                        e.span_suggestion_verbose(
-                                            binop.span.shrink_to_lo(),
-                                            TURBOFISH_SUGGESTION_STR,
-                                            "::".to_string(),
-                                            Applicability::MaybeIncorrect,
-                                        );
-                                        e.emit();
-                                        *expr =
-                                            self.mk_expr_err(expr.span.to(self.prev_token.span));
-                                        return Ok(());
-                                    }
-                                    Err(mut err) => {
-                                        err.cancel();
+                                let turbo_err = e.span_suggestion_verbose(
+                                    binop.span.shrink_to_lo(),
+                                    TURBOFISH_SUGGESTION_STR,
+                                    "::".to_string(),
+                                    Applicability::MaybeIncorrect,
+                                );
+                                if self.check(&TokenKind::Semi) {
+                                    turbo_err.emit();
+                                    *expr = self.mk_expr_err(expr.span);
+                                    return Ok(());
+                                } else {
+                                    match self.parse_expr() {
+                                        Ok(_) => {
+                                            turbo_err.emit();
+                                            *expr = self
+                                                .mk_expr_err(expr.span.to(self.prev_token.span));
+                                            return Ok(());
+                                        }
+                                        Err(mut err) => {
+                                            turbo_err.cancel();
+                                            err.cancel();
+                                        }
                                     }
                                 }
                             }
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index cd3846d5a22..192e87b4c01 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1443,7 +1443,7 @@ impl<'a> Parser<'a> {
         &mut self,
         label: Label,
         attrs: AttrVec,
-        consume_colon: bool,
+        mut consume_colon: bool,
     ) -> PResult<'a, P<Expr>> {
         let lo = label.ident.span;
         let label = Some(label);
@@ -1456,6 +1456,12 @@ impl<'a> Parser<'a> {
             self.parse_loop_expr(label, lo, attrs)
         } else if self.check(&token::OpenDelim(token::Brace)) || self.token.is_whole_block() {
             self.parse_block_expr(label, lo, BlockCheckMode::Default, attrs)
+        } else if !ate_colon && (self.check(&TokenKind::Comma) || self.check(&TokenKind::Gt)) {
+            // We're probably inside of a `Path<'a>` that needs a turbofish, so suppress the
+            // "must be followed by a colon" error.
+            self.diagnostic().delay_span_bug(lo, "this label wasn't parsed correctly");
+            consume_colon = false;
+            Ok(self.mk_expr_err(lo))
         } else {
             let msg = "expected `while`, `for`, `loop` or `{` after a label";
             self.struct_span_err(self.token.span, msg).span_label(self.token.span, msg).emit();
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index c351a9f7040..241dcbc64a6 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -13,7 +13,7 @@ use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, AssocItem, Ty, TypeAndMut};
-use rustc_span::symbol::sym;
+use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{BytePos, Span};
 
 use super::method::probe;
@@ -24,7 +24,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn emit_coerce_suggestions(
         &self,
         err: &mut DiagnosticBuilder<'_>,
-        expr: &hir::Expr<'_>,
+        expr: &hir::Expr<'tcx>,
         expr_ty: Ty<'tcx>,
         expected: Ty<'tcx>,
         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
@@ -109,7 +109,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     pub fn demand_coerce(
         &self,
-        expr: &hir::Expr<'_>,
+        expr: &hir::Expr<'tcx>,
         checked_ty: Ty<'tcx>,
         expected: Ty<'tcx>,
         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
@@ -129,7 +129,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// will be permitted if the diverges flag is currently "always".
     pub fn demand_coerce_diag(
         &self,
-        expr: &hir::Expr<'_>,
+        expr: &hir::Expr<'tcx>,
         checked_ty: Ty<'tcx>,
         expected: Ty<'tcx>,
         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
@@ -338,31 +338,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 })
                 .collect();
 
-            if let [variant] = &compatible_variants[..] {
-                // Just a single matching variant.
-                err.multipart_suggestion(
-                    &format!("try wrapping the expression in `{}`", variant),
-                    vec![
-                        (expr.span.shrink_to_lo(), format!("{}(", variant)),
-                        (expr.span.shrink_to_hi(), ")".to_string()),
-                    ],
-                    Applicability::MaybeIncorrect,
-                );
-            } else if compatible_variants.len() > 1 {
-                // More than one matching variant.
-                err.multipart_suggestions(
-                    &format!(
-                        "try wrapping the expression in a variant of `{}`",
-                        self.tcx.def_path_str(expected_adt.did)
-                    ),
-                    compatible_variants.into_iter().map(|variant| {
+            let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
+                Some(ident) => format!("{}: ", ident),
+                None => format!(""),
+            };
+
+            match &compatible_variants[..] {
+                [] => { /* No variants to format */ }
+                [variant] => {
+                    // Just a single matching variant.
+                    err.multipart_suggestion_verbose(
+                        &format!("try wrapping the expression in `{}`", variant),
                         vec![
-                            (expr.span.shrink_to_lo(), format!("{}(", variant)),
+                            (expr.span.shrink_to_lo(), format!("{}{}(", prefix, variant)),
                             (expr.span.shrink_to_hi(), ")".to_string()),
-                        ]
-                    }),
-                    Applicability::MaybeIncorrect,
-                );
+                        ],
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+                _ => {
+                    // More than one matching variant.
+                    err.multipart_suggestions(
+                        &format!(
+                            "try wrapping the expression in a variant of `{}`",
+                            self.tcx.def_path_str(expected_adt.did)
+                        ),
+                        compatible_variants.into_iter().map(|variant| {
+                            vec![
+                                (expr.span.shrink_to_lo(), format!("{}{}(", prefix, variant)),
+                                (expr.span.shrink_to_hi(), ")".to_string()),
+                            ]
+                        }),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
             }
         }
     }
@@ -483,33 +492,45 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    crate fn is_hir_id_from_struct_pattern_shorthand_field(
+    crate fn maybe_get_struct_pattern_shorthand_field(
         &self,
-        hir_id: hir::HirId,
-        sp: Span,
-    ) -> bool {
-        let sm = self.sess().source_map();
-        let parent_id = self.tcx.hir().get_parent_node(hir_id);
-        if let Some(parent) = self.tcx.hir().find(parent_id) {
-            // Account for fields
-            if let Node::Expr(hir::Expr { kind: hir::ExprKind::Struct(_, fields, ..), .. }) = parent
-            {
-                if let Ok(src) = sm.span_to_snippet(sp) {
-                    for field in *fields {
-                        if field.ident.as_str() == src && field.is_shorthand {
-                            return true;
-                        }
+        expr: &hir::Expr<'_>,
+    ) -> Option<Symbol> {
+        let hir = self.tcx.hir();
+        let local = match expr {
+            hir::Expr {
+                kind:
+                    hir::ExprKind::Path(hir::QPath::Resolved(
+                        None,
+                        hir::Path {
+                            res: hir::def::Res::Local(_),
+                            segments: [hir::PathSegment { ident, .. }],
+                            ..
+                        },
+                    )),
+                ..
+            } => Some(ident),
+            _ => None,
+        }?;
+
+        match hir.find(hir.get_parent_node(expr.hir_id))? {
+            Node::Expr(hir::Expr { kind: hir::ExprKind::Struct(_, fields, ..), .. }) => {
+                for field in *fields {
+                    if field.ident.name == local.name && field.is_shorthand {
+                        return Some(local.name);
                     }
                 }
             }
+            _ => {}
         }
-        false
+
+        None
     }
 
     /// If the given `HirId` corresponds to a block with a trailing expression, return that expression
-    crate fn maybe_get_block_expr(&self, hir_id: hir::HirId) -> Option<&'tcx hir::Expr<'tcx>> {
-        match self.tcx.hir().find(hir_id)? {
-            Node::Expr(hir::Expr { kind: hir::ExprKind::Block(block, ..), .. }) => block.expr,
+    crate fn maybe_get_block_expr(&self, expr: &hir::Expr<'tcx>) -> Option<&'tcx hir::Expr<'tcx>> {
+        match expr {
+            hir::Expr { kind: hir::ExprKind::Block(block, ..), .. } => block.expr,
             _ => None,
         }
     }
@@ -547,7 +568,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// `&mut`!".
     pub fn check_ref(
         &self,
-        expr: &hir::Expr<'_>,
+        expr: &hir::Expr<'tcx>,
         checked_ty: Ty<'tcx>,
         expected: Ty<'tcx>,
     ) -> Option<(Span, &'static str, String, Applicability, bool /* verbose */)> {
@@ -565,9 +586,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             s.strip_prefix(old).map(|stripped| new.to_string() + stripped)
         };
 
-        let is_struct_pat_shorthand_field =
-            self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, sp);
-
         // `ExprKind::DropTemps` is semantically irrelevant for these suggestions.
         let expr = expr.peel_drop_temps();
 
@@ -661,11 +679,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 false,
                             ));
                         }
-                        let field_name = if is_struct_pat_shorthand_field {
-                            format!("{}: ", sugg_expr)
-                        } else {
-                            String::new()
+
+                        let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
+                            Some(ident) => format!("{}: ", ident),
+                            None => format!(""),
                         };
+
                         if let Some(hir::Node::Expr(hir::Expr {
                             kind: hir::ExprKind::Assign(left_expr, ..),
                             ..
@@ -695,14 +714,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             hir::Mutability::Mut => (
                                 sp,
                                 "consider mutably borrowing here",
-                                format!("{}&mut {}", field_name, sugg_expr),
+                                format!("{}&mut {}", prefix, sugg_expr),
                                 Applicability::MachineApplicable,
                                 false,
                             ),
                             hir::Mutability::Not => (
                                 sp,
                                 "consider borrowing here",
-                                format!("{}&{}", field_name, sugg_expr),
+                                format!("{}&{}", prefix, sugg_expr),
                                 Applicability::MachineApplicable,
                                 false,
                             ),
@@ -846,32 +865,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         if self.infcx.type_is_copy_modulo_regions(self.param_env, expected, sp)
                             || checked_ty.is_box()
                         {
-                            if let Ok(code) = sm.span_to_snippet(expr.span) {
-                                let message = if checked_ty.is_box() {
-                                    "consider unboxing the value"
-                                } else if checked_ty.is_region_ptr() {
-                                    "consider dereferencing the borrow"
-                                } else {
-                                    "consider dereferencing the type"
-                                };
-                                let (span, suggestion) = if is_struct_pat_shorthand_field {
-                                    (expr.span, format!("{}: *{}", code, code))
-                                } else if self.is_else_if_block(expr) {
-                                    // Don't suggest nonsense like `else *if`
-                                    return None;
-                                } else if let Some(expr) = self.maybe_get_block_expr(expr.hir_id) {
-                                    (expr.span.shrink_to_lo(), "*".to_string())
-                                } else {
-                                    (expr.span.shrink_to_lo(), "*".to_string())
-                                };
-                                return Some((
-                                    span,
-                                    message,
-                                    suggestion,
-                                    Applicability::MachineApplicable,
-                                    true,
-                                ));
-                            }
+                            let message = if checked_ty.is_box() {
+                                "consider unboxing the value"
+                            } else if checked_ty.is_region_ptr() {
+                                "consider dereferencing the borrow"
+                            } else {
+                                "consider dereferencing the type"
+                            };
+                            let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
+                                Some(ident) => format!("{}: ", ident),
+                                None => format!(""),
+                            };
+                            let (span, suggestion) = if self.is_else_if_block(expr) {
+                                // Don't suggest nonsense like `else *if`
+                                return None;
+                            } else if let Some(expr) = self.maybe_get_block_expr(expr) {
+                                // prefix should be empty here..
+                                (expr.span.shrink_to_lo(), "*".to_string())
+                            } else {
+                                (expr.span.shrink_to_lo(), format!("{}*", prefix))
+                            };
+                            return Some((
+                                span,
+                                message,
+                                suggestion,
+                                Applicability::MachineApplicable,
+                                true,
+                            ));
                         }
                     }
                 }
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
index e8a0cc946b5..473c848ad8f 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
@@ -208,7 +208,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn suggest_deref_ref_or_into(
         &self,
         err: &mut DiagnosticBuilder<'_>,
-        expr: &hir::Expr<'_>,
+        expr: &hir::Expr<'tcx>,
         expected: Ty<'tcx>,
         found: Ty<'tcx>,
         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
@@ -231,7 +231,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         } else if !self.check_for_cast(err, expr, found, expected, expected_ty_expr) {
             let is_struct_pat_shorthand_field =
-                self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, expr.span);
+                self.maybe_get_struct_pattern_shorthand_field(expr).is_some();
             let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
             if !methods.is_empty() {
                 if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) {