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.
This commit is contained in:
commit
aceb5d951b
@ -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`
|
||||
|
@ -51,7 +51,7 @@ pub fn emit_type_mismatch_suggestions(
|
||||
|| 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)
|
||||
|
@ -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,
|
||||
},
|
||||
}
|
||||
|
@ -1519,7 +1519,6 @@ pub(in super::super) fn check_block_with_expected(
|
||||
// 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 @@ pub(in super::super) fn check_block_with_expected(
|
||||
|
||||
// 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 @@ pub(in super::super) fn check_block_with_expected(
|
||||
&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 @@ pub(in super::super) fn check_block_with_expected(
|
||||
// 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 @@ pub(in super::super) fn check_block_with_expected(
|
||||
},
|
||||
],
|
||||
..
|
||||
})) = self.tcx.hir().find(blk.hir_id)
|
||||
} = blk
|
||||
{
|
||||
self.comes_from_while_condition(blk.hir_id, |_| {
|
||||
err.downgrade_to_delayed_bug();
|
||||
|
@ -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::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 @@ pub fn suggest_deref_ref_or_into(
|
||||
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.
|
||||
// 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;
|
||||
}
|
||||
if !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
|
||||
|
12
tests/ui/issues/auxiliary/issue-111011.rs
Normal file
12
tests/ui/issues/auxiliary/issue-111011.rs
Normal file
@ -0,0 +1,12 @@
|
||||
#![feature(async_closure)]
|
||||
|
||||
// edition:2021
|
||||
|
||||
fn foo<X>(x: impl FnOnce() -> Box<X>) {}
|
||||
// just to make sure async closures can still be suggested for boxing.
|
||||
fn bar<X>(x: Box<dyn FnOnce() -> X>) {}
|
||||
|
||||
fn main() {
|
||||
foo(async move || {}); //~ ERROR mismatched types
|
||||
bar(async move || {}); //~ ERROR mismatched types
|
||||
}
|
34
tests/ui/issues/auxiliary/issue-111011.stderr
Normal file
34
tests/ui/issues/auxiliary/issue-111011.stderr
Normal file
@ -0,0 +1,34 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-111011.rs:10:23
|
||||
|
|
||||
LL | foo(async move || {});
|
||||
| ^^ expected `Box<_>`, found `async` closure body
|
||||
|
|
||||
= note: expected struct `Box<_>`
|
||||
found `async` closure body `[async closure body@$DIR/issue-111011.rs:10:23: 10:25]`
|
||||
= 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
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-111011.rs:11:9
|
||||
|
|
||||
LL | bar(async move || {});
|
||||
| --- ^^^^^^^^^^^^^^^^ expected `Box<dyn FnOnce() -> _>`, found closure
|
||||
| |
|
||||
| arguments to this function are incorrect
|
||||
|
|
||||
= note: expected struct `Box<(dyn FnOnce() -> _ + 'static)>`
|
||||
found closure `[closure@$DIR/issue-111011.rs:11:9: 11:22]`
|
||||
= 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
|
||||
note: function defined here
|
||||
--> $DIR/issue-111011.rs:7:4
|
||||
|
|
||||
LL | fn bar<X>(x: Box<dyn FnOnce() -> X>) {}
|
||||
| ^^^ -------------------------
|
||||
help: store this in the heap by calling `Box::new`
|
||||
|
|
||||
LL | bar(Box::new(async move || {}));
|
||||
| +++++++++ +
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
12
tests/ui/suggestions/suggest-boxed-empty-block.fixed
Normal file
12
tests/ui/suggestions/suggest-boxed-empty-block.fixed
Normal file
@ -0,0 +1,12 @@
|
||||
#![feature(async_closure)]
|
||||
|
||||
// edition:2021
|
||||
// run-rustfix
|
||||
|
||||
fn foo<T>(_: Box<T>) {}
|
||||
fn bar<T>(_: impl Fn() -> Box<T>) {}
|
||||
|
||||
fn main() {
|
||||
foo(Box::new(())); //~ ERROR mismatched types
|
||||
bar(|| Box::new(())); //~ ERROR mismatched types
|
||||
}
|
12
tests/ui/suggestions/suggest-boxed-empty-block.rs
Normal file
12
tests/ui/suggestions/suggest-boxed-empty-block.rs
Normal file
@ -0,0 +1,12 @@
|
||||
#![feature(async_closure)]
|
||||
|
||||
// edition:2021
|
||||
// run-rustfix
|
||||
|
||||
fn foo<T>(_: Box<T>) {}
|
||||
fn bar<T>(_: impl Fn() -> Box<T>) {}
|
||||
|
||||
fn main() {
|
||||
foo({}); //~ ERROR mismatched types
|
||||
bar(|| {}); //~ ERROR mismatched types
|
||||
}
|
33
tests/ui/suggestions/suggest-boxed-empty-block.stderr
Normal file
33
tests/ui/suggestions/suggest-boxed-empty-block.stderr
Normal file
@ -0,0 +1,33 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/suggest-boxed-empty-block.rs:10:9
|
||||
|
|
||||
LL | foo({});
|
||||
| ^^ expected `Box<_>`, found `()`
|
||||
|
|
||||
= note: expected struct `Box<_>`
|
||||
found unit type `()`
|
||||
= 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
|
||||
help: store this in the heap by calling `Box::new`
|
||||
|
|
||||
LL - foo({});
|
||||
LL + foo(Box::new(()));
|
||||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/suggest-boxed-empty-block.rs:11:12
|
||||
|
|
||||
LL | bar(|| {});
|
||||
| ^^ expected `Box<_>`, found `()`
|
||||
|
|
||||
= note: expected struct `Box<_>`
|
||||
found unit type `()`
|
||||
= 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
|
||||
help: store this in the heap by calling `Box::new`
|
||||
|
|
||||
LL - bar(|| {});
|
||||
LL + bar(|| Box::new(()));
|
||||
|
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
Loading…
Reference in New Issue
Block a user