diff options
| author | Dylan DPC <99973273+Dylan-DPC@users.noreply.github.com> | 2023-05-08 11:39:21 +0530 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-05-08 11:39:21 +0530 |
| commit | aceb5d951b8776fc314b9565ea5c987546248e28 (patch) | |
| tree | 7897f0e555fb47ffbd31713042606eff79e21bf7 /compiler | |
| parent | c75543d648a1b49329ecd3b9bfcf748f4d708a6f (diff) | |
| parent | 35985091cc0bf18d40f9fdf9bcb81e3dd74f253b (diff) | |
| download | rust-aceb5d951b8776fc314b9565ea5c987546248e28.tar.gz rust-aceb5d951b8776fc314b9565ea5c987546248e28.zip | |
Rollup merge of #111056 - JohnBobbo96:fix_box_suggestions, r=compiler-errors
Fix some suggestions where a `Box<T>` is expected. This fixes #111011, and also adds a suggestion for boxing a unit type when a `Box<T>` was expected and an empty block was found.
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_hir_typeck/messages.ftl | 4 | ||||
| -rw-r--r-- | compiler/rustc_hir_typeck/src/demand.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_hir_typeck/src/errors.rs | 28 | ||||
| -rw-r--r-- | compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 20 | ||||
| -rw-r--r-- | compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs | 48 |
5 files changed, 71 insertions, 31 deletions
diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 603ea1440e9..aa664031a87 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -75,3 +75,7 @@ hir_typeck_union_pat_dotdot = `..` cannot be used in union patterns hir_typeck_arg_mismatch_indeterminate = argument type mismatch was detected, but rustc had trouble determining where .note = we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new + +hir_typeck_suggest_boxing_note = for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html + +hir_typeck_suggest_boxing_when_appropriate = store this in the heap by calling `Box::new` diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index ee81ea345a6..9d59cdcbc60 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -51,7 +51,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { || self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty) || self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) || self.suggest_no_capture_closure(err, expected, expr_ty) - || self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty) + || self.suggest_boxing_when_appropriate(err, expr.span, expr.hir_id, expected, expr_ty) || self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected) || self.suggest_copied_or_cloned(err, expr, expr_ty, expected) || self.suggest_clone_for_ref(err, expr, expr_ty, expected) diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 48c40d21603..ce30bbeca0b 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -267,3 +267,31 @@ pub struct ArgMismatchIndeterminate { #[primary_span] pub span: Span, } + +#[derive(Subdiagnostic)] +pub enum SuggestBoxing { + #[note(hir_typeck_suggest_boxing_note)] + #[multipart_suggestion( + hir_typeck_suggest_boxing_when_appropriate, + applicability = "machine-applicable" + )] + Unit { + #[suggestion_part(code = "Box::new(())")] + start: Span, + #[suggestion_part(code = "")] + end: Span, + }, + #[note(hir_typeck_suggest_boxing_note)] + AsyncBody, + #[note(hir_typeck_suggest_boxing_note)] + #[multipart_suggestion( + hir_typeck_suggest_boxing_when_appropriate, + applicability = "machine-applicable" + )] + Other { + #[suggestion_part(code = "Box::new(")] + start: Span, + #[suggestion_part(code = ")")] + end: Span, + }, +} diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 4b8fc7303a2..c7011b23a7d 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1519,7 +1519,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // case we can ignore the tail expression (e.g., `'a: { // break 'a 22; }` would not force the type of the block // to be `()`). - let tail_expr = blk.expr.as_ref(); let coerce_to_ty = expected.coercion_target_type(self, blk.span); let coerce = if blk.targeted_by_break { CoerceMany::new(coerce_to_ty) @@ -1537,13 +1536,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // check the tail expression **without** holding the // `enclosing_breakables` lock below. - let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected)); + let tail_expr_ty = + blk.expr.map(|expr| (expr, self.check_expr_with_expectation(expr, expected))); let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); let ctxt = enclosing_breakables.find_breakable(blk.hir_id); let coerce = ctxt.coerce.as_mut().unwrap(); - if let Some(tail_expr_ty) = tail_expr_ty { - let tail_expr = tail_expr.unwrap(); + if let Some((tail_expr, tail_expr_ty)) = tail_expr_ty { let span = self.get_expr_coercion_span(tail_expr); let cause = self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id)); let ty_for_diagnostic = coerce.merged_ty(); @@ -1596,6 +1595,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self.misc(sp), &mut |err| { if let Some(expected_ty) = expected.only_has_type(self) { + if blk.stmts.is_empty() && blk.expr.is_none() { + self.suggest_boxing_when_appropriate( + err, + blk.span, + blk.hir_id, + expected_ty, + self.tcx.mk_unit(), + ); + } if !self.consider_removing_semicolon(blk, expected_ty, err) { self.err_ctxt().consider_returning_binding( blk, @@ -1608,7 +1616,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // silence this redundant error, as we already emit E0070. // Our block must be a `assign desugar local; assignment` - if let Some(hir::Node::Block(hir::Block { + if let hir::Block { stmts: [ hir::Stmt { @@ -1630,7 +1638,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, ], .. - })) = self.tcx.hir().find(blk.hir_id) + } = blk { self.comes_from_while_condition(blk.hir_id, |_| { err.downgrade_to_delayed_bug(); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 8978139119c..2867fcc8ecd 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1,6 +1,6 @@ use super::FnCtxt; -use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel}; +use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel, SuggestBoxing}; use crate::fluent_generated as fluent; use crate::method::probe::{IsSuggestion, Mode, ProbeScope}; use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX}; @@ -9,7 +9,8 @@ use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; use rustc_hir::lang_items::LangItem; use rustc_hir::{ - Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate, + AsyncGeneratorKind, Expr, ExprKind, GeneratorKind, GenericBound, HirId, Node, Path, QPath, + Stmt, StmtKind, TyKind, WherePredicate, }; use rustc_hir_analysis::astconv::AstConv; use rustc_infer::traits::{self, StatementAsExpression}; @@ -438,33 +439,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn suggest_boxing_when_appropriate( &self, err: &mut Diagnostic, - expr: &hir::Expr<'_>, + span: Span, + hir_id: HirId, expected: Ty<'tcx>, found: Ty<'tcx>, ) -> bool { - if self.tcx.hir().is_inside_const_context(expr.hir_id) { - // Do not suggest `Box::new` in const context. - return false; - } - if !expected.is_box() || found.is_box() { + // Do not suggest `Box::new` in const context. + if self.tcx.hir().is_inside_const_context(hir_id) || !expected.is_box() || found.is_box() { return false; } - let boxed_found = self.tcx.mk_box(found); - if self.can_coerce(boxed_found, expected) { - err.multipart_suggestion( - "store this in the heap by calling `Box::new`", - vec![ - (expr.span.shrink_to_lo(), "Box::new(".to_string()), - (expr.span.shrink_to_hi(), ")".to_string()), - ], - Applicability::MachineApplicable, - ); - err.note( - "for more on the distinction between the stack and the heap, read \ - https://doc.rust-lang.org/book/ch15-01-box.html, \ - https://doc.rust-lang.org/rust-by-example/std/box.html, and \ - https://doc.rust-lang.org/std/boxed/index.html", - ); + if self.can_coerce(self.tcx.mk_box(found), expected) { + let suggest_boxing = match found.kind() { + ty::Tuple(tuple) if tuple.is_empty() => { + SuggestBoxing::Unit { start: span.shrink_to_lo(), end: span } + } + ty::Generator(def_id, ..) + if matches!( + self.tcx.generator_kind(def_id), + Some(GeneratorKind::Async(AsyncGeneratorKind::Closure)) + ) => + { + SuggestBoxing::AsyncBody + } + _ => SuggestBoxing::Other { start: span.shrink_to_lo(), end: span.shrink_to_hi() }, + }; + err.subdiagnostic(suggest_boxing); + true } else { false |
