diff options
| author | Esteban Küber <esteban@kuber.com.ar> | 2020-10-21 19:43:15 -0700 |
|---|---|---|
| committer | Esteban Küber <esteban@kuber.com.ar> | 2020-10-23 08:06:13 -0700 |
| commit | 671d7c4afb36a7dcedf9ec8a6f3ef00c19bfc260 (patch) | |
| tree | 09e30ca245dd37c3a4c0977935e0441da485910c | |
| parent | a4ee3ca1e4f1177516139a4704456958c7d08c91 (diff) | |
| download | rust-671d7c4afb36a7dcedf9ec8a6f3ef00c19bfc260.tar.gz rust-671d7c4afb36a7dcedf9ec8a6f3ef00c19bfc260.zip | |
Account for possible boxable `impl Future` in semicolon removal suggestions
| -rw-r--r-- | compiler/rustc_infer/src/infer/error_reporting/mod.rs | 46 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/traits/mod.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/_match.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs | 57 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/fn_ctxt/checks.rs | 23 | ||||
| -rw-r--r-- | src/test/ui/suggestions/match-prev-arm-needing-semi.rs | 15 | ||||
| -rw-r--r-- | src/test/ui/suggestions/match-prev-arm-needing-semi.stderr | 37 |
7 files changed, 152 insertions, 32 deletions
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 3a0ec6327c1..f6aa3c3d5ba 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -688,13 +688,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }; let msg = "`match` arms have incompatible types"; err.span_label(outer_error_span, msg); - if let Some(sp) = semi_span { - err.span_suggestion_short( - sp, - "consider removing this semicolon", - String::new(), - Applicability::MachineApplicable, - ); + if let Some((sp, boxed)) = semi_span { + if boxed { + err.span_suggestion_verbose( + sp, + "consider removing this semicolon and boxing the expression", + String::new(), + Applicability::HasPlaceholders, + ); + } else { + err.span_suggestion_short( + sp, + "consider removing this semicolon", + String::new(), + Applicability::MachineApplicable, + ); + } } if let Some(ret_sp) = opt_suggest_box_span { // Get return type span and point to it. @@ -717,13 +726,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { if let Some(sp) = outer { err.span_label(sp, "`if` and `else` have incompatible types"); } - if let Some(sp) = semicolon { - err.span_suggestion_short( - sp, - "consider removing this semicolon", - String::new(), - Applicability::MachineApplicable, - ); + if let Some((sp, boxed)) = semicolon { + if boxed { + err.span_suggestion_verbose( + sp, + "consider removing this semicolon and boxing the expression", + String::new(), + Applicability::HasPlaceholders, + ); + } else { + err.span_suggestion_short( + sp, + "consider removing this semicolon", + String::new(), + Applicability::MachineApplicable, + ); + } } if let Some(ret_sp) = opt_suggest_box_span { self.suggest_boxing_for_return_impl_trait( diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index bbc46b8d608..daa3010abb5 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -344,7 +344,7 @@ static_assert_size!(ObligationCauseCode<'_>, 32); pub struct MatchExpressionArmCause<'tcx> { pub arm_span: Span, pub scrut_span: Span, - pub semi_span: Option<Span>, + pub semi_span: Option<(Span, bool)>, pub source: hir::MatchSource, pub prior_arms: Vec<Span>, pub last_ty: Ty<'tcx>, @@ -357,7 +357,7 @@ pub struct IfExpressionCause { pub then: Span, pub else_sp: Span, pub outer: Option<Span>, - pub semicolon: Option<Span>, + pub semicolon: Option<(Span, bool)>, pub opt_suggest_box_span: Option<Span>, } diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs index 94e886be54d..27c85317e82 100644 --- a/compiler/rustc_typeck/src/check/_match.rs +++ b/compiler/rustc_typeck/src/check/_match.rs @@ -521,7 +521,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, block: &'tcx hir::Block<'tcx>, expected_ty: Option<Ty<'tcx>>, - ) -> (Span, Option<Span>) { + ) -> (Span, Option<(Span, bool)>) { if let Some(expr) = &block.expr { (expr.span, None) } else if let Some(stmt) = block.stmts.last() { diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 017b0abd1d6..f26a168bcb2 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -1061,7 +1061,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, blk: &'tcx hir::Block<'tcx>, expected_ty: Ty<'tcx>, - ) -> Option<Span> { + ) -> Option<(Span, bool)> { // Be helpful when the user wrote `{... expr;}` and // taking the `;` off is enough to fix the error. let last_stmt = blk.stmts.last()?; @@ -1070,13 +1070,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => return None, }; let last_expr_ty = self.node_ty(last_expr.hir_id); - if matches!(last_expr_ty.kind(), ty::Error(_)) - || self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err() + let needs_box = match (last_expr_ty.kind(), expected_ty.kind()) { + (ty::Opaque(last_def_id, last_bounds), ty::Opaque(exp_def_id, exp_bounds)) => { + debug!( + "both opaque, likely future {:?} {:?} {:?} {:?}", + last_def_id, last_bounds, exp_def_id, exp_bounds + ); + let last_hir_id = self.tcx.hir().local_def_id_to_hir_id(last_def_id.expect_local()); + let exp_hir_id = self.tcx.hir().local_def_id_to_hir_id(exp_def_id.expect_local()); + if let ( + hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: last_bounds, .. }), + hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: exp_bounds, .. }), + ) = ( + &self.tcx.hir().expect_item(last_hir_id).kind, + &self.tcx.hir().expect_item(exp_hir_id).kind, + ) { + debug!("{:?} {:?}", last_bounds, exp_bounds); + last_bounds.iter().zip(exp_bounds.iter()).all(|(left, right)| { + match (left, right) { + ( + hir::GenericBound::Trait(tl, ml), + hir::GenericBound::Trait(tr, mr), + ) => { + tl.trait_ref.trait_def_id() == tr.trait_ref.trait_def_id() + && ml == mr + } + ( + hir::GenericBound::LangItemTrait(langl, _, _, argsl), + hir::GenericBound::LangItemTrait(langr, _, _, argsr), + ) => { + // FIXME: consider the bounds! + debug!("{:?} {:?}", argsl, argsr); + langl == langr + } + _ => false, + } + }) + } else { + false + } + } + _ => false, + }; + debug!( + "needs_box {:?} {:?} {:?}", + needs_box, + last_expr_ty.kind(), + self.can_sub(self.param_env, last_expr_ty, expected_ty) + ); + if (matches!(last_expr_ty.kind(), ty::Error(_)) + || self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err()) + && !needs_box { return None; } let original_span = original_sp(last_stmt.span, blk.span); - Some(original_span.with_lo(original_span.hi() - BytePos(1))) + Some((original_span.with_lo(original_span.hi() - BytePos(1)), needs_box)) } // Instantiates the given path, which must refer to an item with the given diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index fd2f5eb5018..a124ad16612 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -758,13 +758,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected_ty: Ty<'tcx>, err: &mut DiagnosticBuilder<'_>, ) { - if let Some(span_semi) = self.could_remove_semicolon(blk, expected_ty) { - err.span_suggestion( - span_semi, - "consider removing this semicolon", - String::new(), - Applicability::MachineApplicable, - ); + if let Some((span_semi, boxed)) = self.could_remove_semicolon(blk, expected_ty) { + if boxed { + err.span_suggestion_verbose( + span_semi, + "consider removing this semicolon and boxing the expression", + String::new(), + Applicability::HasPlaceholders, + ); + } else { + err.span_suggestion_short( + span_semi, + "consider removing this semicolon", + String::new(), + Applicability::MachineApplicable, + ); + } } } diff --git a/src/test/ui/suggestions/match-prev-arm-needing-semi.rs b/src/test/ui/suggestions/match-prev-arm-needing-semi.rs index d8d6de4bf55..9704242e105 100644 --- a/src/test/ui/suggestions/match-prev-arm-needing-semi.rs +++ b/src/test/ui/suggestions/match-prev-arm-needing-semi.rs @@ -14,6 +14,7 @@ fn extra_semicolon() { } async fn async_dummy() {} //~ NOTE the `Output` of this `async fn`'s found opaque type +async fn async_dummy2() {} //~ NOTE the `Output` of this `async fn`'s found opaque type async fn async_extra_semicolon_same() { let _ = match true { //~ NOTE `match` arms have incompatible types @@ -28,5 +29,17 @@ async fn async_extra_semicolon_same() { }; } -fn main() {} +async fn async_extra_semicolon_different() { + let _ = match true { //~ NOTE `match` arms have incompatible types + true => { + async_dummy(); //~ NOTE this is found to be + //~^ HELP consider removing this semicolon + } + false => async_dummy2(), //~ ERROR `match` arms have incompatible types + //~^ NOTE expected `()`, found opaque type + //~| NOTE expected type `()` + //~| HELP consider `await`ing on the `Future` + }; +} +fn main() {} diff --git a/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr b/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr index e242a018843..00b02fbc007 100644 --- a/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr +++ b/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr @@ -1,5 +1,5 @@ error[E0308]: `match` arms have incompatible types - --> $DIR/match-prev-arm-needing-semi.rs:24:18 + --> $DIR/match-prev-arm-needing-semi.rs:25:18 | LL | async fn async_dummy() {} | - the `Output` of this `async fn`'s found opaque type @@ -20,7 +20,7 @@ LL | | }; | = note: expected type `()` found opaque type `impl Future` -help: consider removing this semicolon +help: consider removing this semicolon and boxing the expression | LL | async_dummy() | -- @@ -30,6 +30,37 @@ LL | false => async_dummy().await, | ^^^^^^ error[E0308]: `match` arms have incompatible types + --> $DIR/match-prev-arm-needing-semi.rs:38:18 + | +LL | async fn async_dummy2() {} + | - the `Output` of this `async fn`'s found opaque type +... +LL | let _ = match true { + | _____________- +LL | | true => { +LL | | async_dummy(); + | | -------------- this is found to be of type `()` +LL | | +LL | | } +LL | | false => async_dummy2(), + | | ^^^^^^^^^^^^^^ expected `()`, found opaque type +... | +LL | | +LL | | }; + | |_____- `match` arms have incompatible types + | + = note: expected type `()` + found opaque type `impl Future` +help: consider removing this semicolon and boxing the expression + | +LL | async_dummy() + | -- +help: consider `await`ing on the `Future` + | +LL | false => async_dummy2().await, + | ^^^^^^ + +error[E0308]: `match` arms have incompatible types --> $DIR/match-prev-arm-needing-semi.rs:11:18 | LL | let _ = match true { @@ -48,6 +79,6 @@ LL | | LL | | }; | |_____- `match` arms have incompatible types -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0308`. |
