diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_ast_pretty/src/pp.rs | 46 | ||||
| -rw-r--r-- | compiler/rustc_ast_pretty/src/pprust/state.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_hir_pretty/src/lib.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/diagnostics.rs | 39 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/expr.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/demand.rs | 184 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs | 4 |
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) { |
