Skip to content

Commit 671d7c4

Browse files
committed
Account for possible boxable impl Future in semicolon removal suggestions
1 parent a4ee3ca commit 671d7c4

File tree

7 files changed

+152
-32
lines changed

7 files changed

+152
-32
lines changed

Diff for: compiler/rustc_infer/src/infer/error_reporting/mod.rs

+32-14
Original file line numberDiff line numberDiff line change
@@ -688,13 +688,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
688688
};
689689
let msg = "`match` arms have incompatible types";
690690
err.span_label(outer_error_span, msg);
691-
if let Some(sp) = semi_span {
692-
err.span_suggestion_short(
693-
sp,
694-
"consider removing this semicolon",
695-
String::new(),
696-
Applicability::MachineApplicable,
697-
);
691+
if let Some((sp, boxed)) = semi_span {
692+
if boxed {
693+
err.span_suggestion_verbose(
694+
sp,
695+
"consider removing this semicolon and boxing the expression",
696+
String::new(),
697+
Applicability::HasPlaceholders,
698+
);
699+
} else {
700+
err.span_suggestion_short(
701+
sp,
702+
"consider removing this semicolon",
703+
String::new(),
704+
Applicability::MachineApplicable,
705+
);
706+
}
698707
}
699708
if let Some(ret_sp) = opt_suggest_box_span {
700709
// Get return type span and point to it.
@@ -717,13 +726,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
717726
if let Some(sp) = outer {
718727
err.span_label(sp, "`if` and `else` have incompatible types");
719728
}
720-
if let Some(sp) = semicolon {
721-
err.span_suggestion_short(
722-
sp,
723-
"consider removing this semicolon",
724-
String::new(),
725-
Applicability::MachineApplicable,
726-
);
729+
if let Some((sp, boxed)) = semicolon {
730+
if boxed {
731+
err.span_suggestion_verbose(
732+
sp,
733+
"consider removing this semicolon and boxing the expression",
734+
String::new(),
735+
Applicability::HasPlaceholders,
736+
);
737+
} else {
738+
err.span_suggestion_short(
739+
sp,
740+
"consider removing this semicolon",
741+
String::new(),
742+
Applicability::MachineApplicable,
743+
);
744+
}
727745
}
728746
if let Some(ret_sp) = opt_suggest_box_span {
729747
self.suggest_boxing_for_return_impl_trait(

Diff for: compiler/rustc_middle/src/traits/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ static_assert_size!(ObligationCauseCode<'_>, 32);
344344
pub struct MatchExpressionArmCause<'tcx> {
345345
pub arm_span: Span,
346346
pub scrut_span: Span,
347-
pub semi_span: Option<Span>,
347+
pub semi_span: Option<(Span, bool)>,
348348
pub source: hir::MatchSource,
349349
pub prior_arms: Vec<Span>,
350350
pub last_ty: Ty<'tcx>,
@@ -357,7 +357,7 @@ pub struct IfExpressionCause {
357357
pub then: Span,
358358
pub else_sp: Span,
359359
pub outer: Option<Span>,
360-
pub semicolon: Option<Span>,
360+
pub semicolon: Option<(Span, bool)>,
361361
pub opt_suggest_box_span: Option<Span>,
362362
}
363363

Diff for: compiler/rustc_typeck/src/check/_match.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
521521
&self,
522522
block: &'tcx hir::Block<'tcx>,
523523
expected_ty: Option<Ty<'tcx>>,
524-
) -> (Span, Option<Span>) {
524+
) -> (Span, Option<(Span, bool)>) {
525525
if let Some(expr) = &block.expr {
526526
(expr.span, None)
527527
} else if let Some(stmt) = block.stmts.last() {

Diff for: compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs

+53-4
Original file line numberDiff line numberDiff line change
@@ -1061,7 +1061,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10611061
&self,
10621062
blk: &'tcx hir::Block<'tcx>,
10631063
expected_ty: Ty<'tcx>,
1064-
) -> Option<Span> {
1064+
) -> Option<(Span, bool)> {
10651065
// Be helpful when the user wrote `{... expr;}` and
10661066
// taking the `;` off is enough to fix the error.
10671067
let last_stmt = blk.stmts.last()?;
@@ -1070,13 +1070,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10701070
_ => return None,
10711071
};
10721072
let last_expr_ty = self.node_ty(last_expr.hir_id);
1073-
if matches!(last_expr_ty.kind(), ty::Error(_))
1074-
|| self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err()
1073+
let needs_box = match (last_expr_ty.kind(), expected_ty.kind()) {
1074+
(ty::Opaque(last_def_id, last_bounds), ty::Opaque(exp_def_id, exp_bounds)) => {
1075+
debug!(
1076+
"both opaque, likely future {:?} {:?} {:?} {:?}",
1077+
last_def_id, last_bounds, exp_def_id, exp_bounds
1078+
);
1079+
let last_hir_id = self.tcx.hir().local_def_id_to_hir_id(last_def_id.expect_local());
1080+
let exp_hir_id = self.tcx.hir().local_def_id_to_hir_id(exp_def_id.expect_local());
1081+
if let (
1082+
hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: last_bounds, .. }),
1083+
hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: exp_bounds, .. }),
1084+
) = (
1085+
&self.tcx.hir().expect_item(last_hir_id).kind,
1086+
&self.tcx.hir().expect_item(exp_hir_id).kind,
1087+
) {
1088+
debug!("{:?} {:?}", last_bounds, exp_bounds);
1089+
last_bounds.iter().zip(exp_bounds.iter()).all(|(left, right)| {
1090+
match (left, right) {
1091+
(
1092+
hir::GenericBound::Trait(tl, ml),
1093+
hir::GenericBound::Trait(tr, mr),
1094+
) => {
1095+
tl.trait_ref.trait_def_id() == tr.trait_ref.trait_def_id()
1096+
&& ml == mr
1097+
}
1098+
(
1099+
hir::GenericBound::LangItemTrait(langl, _, _, argsl),
1100+
hir::GenericBound::LangItemTrait(langr, _, _, argsr),
1101+
) => {
1102+
// FIXME: consider the bounds!
1103+
debug!("{:?} {:?}", argsl, argsr);
1104+
langl == langr
1105+
}
1106+
_ => false,
1107+
}
1108+
})
1109+
} else {
1110+
false
1111+
}
1112+
}
1113+
_ => false,
1114+
};
1115+
debug!(
1116+
"needs_box {:?} {:?} {:?}",
1117+
needs_box,
1118+
last_expr_ty.kind(),
1119+
self.can_sub(self.param_env, last_expr_ty, expected_ty)
1120+
);
1121+
if (matches!(last_expr_ty.kind(), ty::Error(_))
1122+
|| self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err())
1123+
&& !needs_box
10751124
{
10761125
return None;
10771126
}
10781127
let original_span = original_sp(last_stmt.span, blk.span);
1079-
Some(original_span.with_lo(original_span.hi() - BytePos(1)))
1128+
Some((original_span.with_lo(original_span.hi() - BytePos(1)), needs_box))
10801129
}
10811130

10821131
// Instantiates the given path, which must refer to an item with the given

Diff for: compiler/rustc_typeck/src/check/fn_ctxt/checks.rs

+16-7
Original file line numberDiff line numberDiff line change
@@ -758,13 +758,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
758758
expected_ty: Ty<'tcx>,
759759
err: &mut DiagnosticBuilder<'_>,
760760
) {
761-
if let Some(span_semi) = self.could_remove_semicolon(blk, expected_ty) {
762-
err.span_suggestion(
763-
span_semi,
764-
"consider removing this semicolon",
765-
String::new(),
766-
Applicability::MachineApplicable,
767-
);
761+
if let Some((span_semi, boxed)) = self.could_remove_semicolon(blk, expected_ty) {
762+
if boxed {
763+
err.span_suggestion_verbose(
764+
span_semi,
765+
"consider removing this semicolon and boxing the expression",
766+
String::new(),
767+
Applicability::HasPlaceholders,
768+
);
769+
} else {
770+
err.span_suggestion_short(
771+
span_semi,
772+
"consider removing this semicolon",
773+
String::new(),
774+
Applicability::MachineApplicable,
775+
);
776+
}
768777
}
769778
}
770779

Diff for: src/test/ui/suggestions/match-prev-arm-needing-semi.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ fn extra_semicolon() {
1414
}
1515

1616
async fn async_dummy() {} //~ NOTE the `Output` of this `async fn`'s found opaque type
17+
async fn async_dummy2() {} //~ NOTE the `Output` of this `async fn`'s found opaque type
1718

1819
async fn async_extra_semicolon_same() {
1920
let _ = match true { //~ NOTE `match` arms have incompatible types
@@ -28,5 +29,17 @@ async fn async_extra_semicolon_same() {
2829
};
2930
}
3031

31-
fn main() {}
32+
async fn async_extra_semicolon_different() {
33+
let _ = match true { //~ NOTE `match` arms have incompatible types
34+
true => {
35+
async_dummy(); //~ NOTE this is found to be
36+
//~^ HELP consider removing this semicolon
37+
}
38+
false => async_dummy2(), //~ ERROR `match` arms have incompatible types
39+
//~^ NOTE expected `()`, found opaque type
40+
//~| NOTE expected type `()`
41+
//~| HELP consider `await`ing on the `Future`
42+
};
43+
}
3244

45+
fn main() {}

Diff for: src/test/ui/suggestions/match-prev-arm-needing-semi.stderr

+34-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0308]: `match` arms have incompatible types
2-
--> $DIR/match-prev-arm-needing-semi.rs:24:18
2+
--> $DIR/match-prev-arm-needing-semi.rs:25:18
33
|
44
LL | async fn async_dummy() {}
55
| - the `Output` of this `async fn`'s found opaque type
@@ -20,7 +20,7 @@ LL | | };
2020
|
2121
= note: expected type `()`
2222
found opaque type `impl Future`
23-
help: consider removing this semicolon
23+
help: consider removing this semicolon and boxing the expression
2424
|
2525
LL | async_dummy()
2626
| --
@@ -29,6 +29,37 @@ help: consider `await`ing on the `Future`
2929
LL | false => async_dummy().await,
3030
| ^^^^^^
3131

32+
error[E0308]: `match` arms have incompatible types
33+
--> $DIR/match-prev-arm-needing-semi.rs:38:18
34+
|
35+
LL | async fn async_dummy2() {}
36+
| - the `Output` of this `async fn`'s found opaque type
37+
...
38+
LL | let _ = match true {
39+
| _____________-
40+
LL | | true => {
41+
LL | | async_dummy();
42+
| | -------------- this is found to be of type `()`
43+
LL | |
44+
LL | | }
45+
LL | | false => async_dummy2(),
46+
| | ^^^^^^^^^^^^^^ expected `()`, found opaque type
47+
... |
48+
LL | |
49+
LL | | };
50+
| |_____- `match` arms have incompatible types
51+
|
52+
= note: expected type `()`
53+
found opaque type `impl Future`
54+
help: consider removing this semicolon and boxing the expression
55+
|
56+
LL | async_dummy()
57+
| --
58+
help: consider `await`ing on the `Future`
59+
|
60+
LL | false => async_dummy2().await,
61+
| ^^^^^^
62+
3263
error[E0308]: `match` arms have incompatible types
3364
--> $DIR/match-prev-arm-needing-semi.rs:11:18
3465
|
@@ -48,6 +79,6 @@ LL | |
4879
LL | | };
4980
| |_____- `match` arms have incompatible types
5081

51-
error: aborting due to 2 previous errors
82+
error: aborting due to 3 previous errors
5283

5384
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)