Rollup merge of #78214 - estebank:match-semicolon, r=oli-obk
Tweak match arm semicolon removal suggestion to account for futures * Tweak and extend "use `.await`" suggestions * Suggest removal of semicolon on prior match arm * Account for `impl Future` when suggesting semicolon removal * Silence some errors when encountering `await foo()?` as can't be certain what the intent was *Thanks to https://twitter.com/a_hoverbear/status/1318960787105353728 for pointing this out!*
This commit is contained in:
commit
083a5cd9a2
24 changed files with 571 additions and 322 deletions
|
@ -50,10 +50,10 @@ use super::region_constraints::GenericKind;
|
||||||
use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs};
|
use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs};
|
||||||
|
|
||||||
use crate::infer;
|
use crate::infer;
|
||||||
use crate::infer::OriginalQueryValues;
|
|
||||||
use crate::traits::error_reporting::report_object_safety_error;
|
use crate::traits::error_reporting::report_object_safety_error;
|
||||||
use crate::traits::{
|
use crate::traits::{
|
||||||
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
|
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
|
||||||
|
StatementAsExpression,
|
||||||
};
|
};
|
||||||
|
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
|
@ -64,7 +64,6 @@ use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_hir::{Item, ItemKind, Node};
|
use rustc_hir::{Item, ItemKind, Node};
|
||||||
use rustc_middle::ty::error::TypeError;
|
use rustc_middle::ty::error::TypeError;
|
||||||
use rustc_middle::ty::ParamEnvAnd;
|
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self,
|
self,
|
||||||
subst::{Subst, SubstsRef},
|
subst::{Subst, SubstsRef},
|
||||||
|
@ -688,7 +687,29 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
};
|
};
|
||||||
let msg = "`match` arms have incompatible types";
|
let msg = "`match` arms have incompatible types";
|
||||||
err.span_label(outer_error_span, msg);
|
err.span_label(outer_error_span, msg);
|
||||||
if let Some(sp) = semi_span {
|
if let Some((sp, boxed)) = semi_span {
|
||||||
|
if let (StatementAsExpression::NeedsBoxing, [.., prior_arm]) =
|
||||||
|
(boxed, &prior_arms[..])
|
||||||
|
{
|
||||||
|
err.multipart_suggestion(
|
||||||
|
"consider removing this semicolon and boxing the expressions",
|
||||||
|
vec![
|
||||||
|
(prior_arm.shrink_to_lo(), "Box::new(".to_string()),
|
||||||
|
(prior_arm.shrink_to_hi(), ")".to_string()),
|
||||||
|
(arm_span.shrink_to_lo(), "Box::new(".to_string()),
|
||||||
|
(arm_span.shrink_to_hi(), ")".to_string()),
|
||||||
|
(sp, String::new()),
|
||||||
|
],
|
||||||
|
Applicability::HasPlaceholders,
|
||||||
|
);
|
||||||
|
} else if matches!(boxed, StatementAsExpression::NeedsBoxing) {
|
||||||
|
err.span_suggestion_short(
|
||||||
|
sp,
|
||||||
|
"consider removing this semicolon and boxing the expressions",
|
||||||
|
String::new(),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
err.span_suggestion_short(
|
err.span_suggestion_short(
|
||||||
sp,
|
sp,
|
||||||
"consider removing this semicolon",
|
"consider removing this semicolon",
|
||||||
|
@ -696,6 +717,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if let Some(ret_sp) = opt_suggest_box_span {
|
if let Some(ret_sp) = opt_suggest_box_span {
|
||||||
// Get return type span and point to it.
|
// Get return type span and point to it.
|
||||||
self.suggest_boxing_for_return_impl_trait(
|
self.suggest_boxing_for_return_impl_trait(
|
||||||
|
@ -717,7 +739,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
if let Some(sp) = outer {
|
if let Some(sp) = outer {
|
||||||
err.span_label(sp, "`if` and `else` have incompatible types");
|
err.span_label(sp, "`if` and `else` have incompatible types");
|
||||||
}
|
}
|
||||||
if let Some(sp) = semicolon {
|
if let Some((sp, boxed)) = semicolon {
|
||||||
|
if matches!(boxed, StatementAsExpression::NeedsBoxing) {
|
||||||
|
err.multipart_suggestion(
|
||||||
|
"consider removing this semicolon and boxing the expression",
|
||||||
|
vec![
|
||||||
|
(then.shrink_to_lo(), "Box::new(".to_string()),
|
||||||
|
(then.shrink_to_hi(), ")".to_string()),
|
||||||
|
(else_sp.shrink_to_lo(), "Box::new(".to_string()),
|
||||||
|
(else_sp.shrink_to_hi(), ")".to_string()),
|
||||||
|
(sp, String::new()),
|
||||||
|
],
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
err.span_suggestion_short(
|
err.span_suggestion_short(
|
||||||
sp,
|
sp,
|
||||||
"consider removing this semicolon",
|
"consider removing this semicolon",
|
||||||
|
@ -725,6 +760,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if let Some(ret_sp) = opt_suggest_box_span {
|
if let Some(ret_sp) = opt_suggest_box_span {
|
||||||
self.suggest_boxing_for_return_impl_trait(
|
self.suggest_boxing_for_return_impl_trait(
|
||||||
err,
|
err,
|
||||||
|
@ -1602,6 +1638,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
Mismatch::Variable(exp_found) => Some(exp_found),
|
Mismatch::Variable(exp_found) => Some(exp_found),
|
||||||
Mismatch::Fixed(_) => None,
|
Mismatch::Fixed(_) => None,
|
||||||
};
|
};
|
||||||
|
let exp_found = match terr {
|
||||||
|
// `terr` has more accurate type information than `exp_found` in match expressions.
|
||||||
|
ty::error::TypeError::Sorts(terr)
|
||||||
|
if exp_found.map_or(false, |ef| terr.found == ef.found) =>
|
||||||
|
{
|
||||||
|
Some(*terr)
|
||||||
|
}
|
||||||
|
_ => exp_found,
|
||||||
|
};
|
||||||
|
debug!("exp_found {:?} terr {:?}", exp_found, terr);
|
||||||
if let Some(exp_found) = exp_found {
|
if let Some(exp_found) = exp_found {
|
||||||
self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
|
self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
|
||||||
self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
|
self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
|
||||||
|
@ -1623,19 +1669,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
self.note_error_origin(diag, cause, exp_found);
|
self.note_error_origin(diag, cause, exp_found);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn suggest_await_on_expect_found(
|
fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
|
||||||
&self,
|
if let ty::Opaque(def_id, substs) = ty.kind() {
|
||||||
cause: &ObligationCause<'tcx>,
|
|
||||||
exp_span: Span,
|
|
||||||
exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
|
|
||||||
diag: &mut DiagnosticBuilder<'tcx>,
|
|
||||||
) {
|
|
||||||
debug!(
|
|
||||||
"suggest_await_on_expect_found: exp_span={:?}, expected_ty={:?}, found_ty={:?}",
|
|
||||||
exp_span, exp_found.expected, exp_found.found
|
|
||||||
);
|
|
||||||
|
|
||||||
if let ty::Opaque(def_id, _) = *exp_found.expected.kind() {
|
|
||||||
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
|
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
|
||||||
// Future::Output
|
// Future::Output
|
||||||
let item_def_id = self
|
let item_def_id = self
|
||||||
|
@ -1646,36 +1681,120 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.def_id;
|
.def_id;
|
||||||
|
|
||||||
let projection_ty = self.tcx.projection_ty_from_predicates((def_id, item_def_id));
|
let bounds = self.tcx.explicit_item_bounds(*def_id);
|
||||||
if let Some(projection_ty) = projection_ty {
|
|
||||||
let projection_query = self.canonicalize_query(
|
for (predicate, _) in bounds {
|
||||||
&ParamEnvAnd { param_env: self.tcx.param_env(def_id), value: projection_ty },
|
let predicate = predicate.subst(self.tcx, substs);
|
||||||
&mut OriginalQueryValues::default(),
|
if let ty::PredicateAtom::Projection(projection_predicate) =
|
||||||
);
|
predicate.skip_binders()
|
||||||
if let Ok(resp) = self.tcx.normalize_projection_ty(projection_query) {
|
|
||||||
let normalized_ty = resp.value.value.normalized_ty;
|
|
||||||
debug!("suggest_await_on_expect_found: normalized={:?}", normalized_ty);
|
|
||||||
if ty::TyS::same_type(normalized_ty, exp_found.found) {
|
|
||||||
let span = if let ObligationCauseCode::Pattern {
|
|
||||||
span,
|
|
||||||
origin_expr: _,
|
|
||||||
root_ty: _,
|
|
||||||
} = cause.code
|
|
||||||
{
|
{
|
||||||
// scrutinee's span
|
if projection_predicate.projection_ty.item_def_id == item_def_id {
|
||||||
span.unwrap_or(exp_span)
|
// We don't account for multiple `Future::Output = Ty` contraints.
|
||||||
|
return Some(projection_predicate.ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A possible error is to forget to add `.await` when using futures:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// async fn make_u32() -> u32 {
|
||||||
|
/// 22
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn take_u32(x: u32) {}
|
||||||
|
///
|
||||||
|
/// async fn foo() {
|
||||||
|
/// let x = make_u32();
|
||||||
|
/// take_u32(x);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// This routine checks if the found type `T` implements `Future<Output=U>` where `U` is the
|
||||||
|
/// expected type. If this is the case, and we are inside of an async body, it suggests adding
|
||||||
|
/// `.await` to the tail of the expression.
|
||||||
|
fn suggest_await_on_expect_found(
|
||||||
|
&self,
|
||||||
|
cause: &ObligationCause<'tcx>,
|
||||||
|
exp_span: Span,
|
||||||
|
exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
|
||||||
|
diag: &mut DiagnosticBuilder<'tcx>,
|
||||||
|
) {
|
||||||
|
debug!(
|
||||||
|
"suggest_await_on_expect_found: exp_span={:?}, expected_ty={:?}, found_ty={:?}",
|
||||||
|
exp_span, exp_found.expected, exp_found.found,
|
||||||
|
);
|
||||||
|
|
||||||
|
if let ObligationCauseCode::CompareImplMethodObligation { .. } = &cause.code {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match (
|
||||||
|
self.get_impl_future_output_ty(exp_found.expected),
|
||||||
|
self.get_impl_future_output_ty(exp_found.found),
|
||||||
|
) {
|
||||||
|
(Some(exp), Some(found)) if ty::TyS::same_type(exp, found) => match &cause.code {
|
||||||
|
ObligationCauseCode::IfExpression(box IfExpressionCause { then, .. }) => {
|
||||||
|
diag.multipart_suggestion(
|
||||||
|
"consider `await`ing on both `Future`s",
|
||||||
|
vec![
|
||||||
|
(then.shrink_to_hi(), ".await".to_string()),
|
||||||
|
(exp_span.shrink_to_hi(), ".await".to_string()),
|
||||||
|
],
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
|
||||||
|
prior_arms,
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
if let [.., arm_span] = &prior_arms[..] {
|
||||||
|
diag.multipart_suggestion(
|
||||||
|
"consider `await`ing on both `Future`s",
|
||||||
|
vec![
|
||||||
|
(arm_span.shrink_to_hi(), ".await".to_string()),
|
||||||
|
(exp_span.shrink_to_hi(), ".await".to_string()),
|
||||||
|
],
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
exp_span
|
diag.help("consider `await`ing on both `Future`s");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
diag.help("consider `await`ing on both `Future`s");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(_, Some(ty)) if ty::TyS::same_type(exp_found.expected, ty) => {
|
||||||
|
let span = match cause.code {
|
||||||
|
// scrutinee's span
|
||||||
|
ObligationCauseCode::Pattern { span: Some(span), .. } => span,
|
||||||
|
_ => exp_span,
|
||||||
};
|
};
|
||||||
diag.span_suggestion_verbose(
|
diag.span_suggestion_verbose(
|
||||||
span.shrink_to_hi(),
|
span.shrink_to_hi(),
|
||||||
"consider awaiting on the future",
|
"consider `await`ing on the `Future`",
|
||||||
".await".to_string(),
|
".await".to_string(),
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
(Some(ty), _) if ty::TyS::same_type(ty, exp_found.found) => {
|
||||||
|
let span = match cause.code {
|
||||||
|
// scrutinee's span
|
||||||
|
ObligationCauseCode::Pattern { span: Some(span), .. } => span,
|
||||||
|
_ => exp_span,
|
||||||
|
};
|
||||||
|
diag.span_suggestion_verbose(
|
||||||
|
span.shrink_to_hi(),
|
||||||
|
"consider `await`ing on the `Future`",
|
||||||
|
".await".to_string(),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -340,11 +340,24 @@ impl ObligationCauseCode<'_> {
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
static_assert_size!(ObligationCauseCode<'_>, 32);
|
static_assert_size!(ObligationCauseCode<'_>, 32);
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum StatementAsExpression {
|
||||||
|
CorrectType,
|
||||||
|
NeedsBoxing,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> ty::Lift<'tcx> for StatementAsExpression {
|
||||||
|
type Lifted = StatementAsExpression;
|
||||||
|
fn lift_to_tcx(self, _tcx: TyCtxt<'tcx>) -> Option<StatementAsExpression> {
|
||||||
|
Some(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
|
||||||
pub struct MatchExpressionArmCause<'tcx> {
|
pub struct MatchExpressionArmCause<'tcx> {
|
||||||
pub arm_span: Span,
|
pub arm_span: Span,
|
||||||
pub scrut_span: Span,
|
pub scrut_span: Span,
|
||||||
pub semi_span: Option<Span>,
|
pub semi_span: Option<(Span, StatementAsExpression)>,
|
||||||
pub source: hir::MatchSource,
|
pub source: hir::MatchSource,
|
||||||
pub prior_arms: Vec<Span>,
|
pub prior_arms: Vec<Span>,
|
||||||
pub last_ty: Ty<'tcx>,
|
pub last_ty: Ty<'tcx>,
|
||||||
|
@ -357,7 +370,7 @@ pub struct IfExpressionCause {
|
||||||
pub then: Span,
|
pub then: Span,
|
||||||
pub else_sp: Span,
|
pub else_sp: Span,
|
||||||
pub outer: Option<Span>,
|
pub outer: Option<Span>,
|
||||||
pub semicolon: Option<Span>,
|
pub semicolon: Option<(Span, StatementAsExpression)>,
|
||||||
pub opt_suggest_box_span: Option<Span>,
|
pub opt_suggest_box_span: Option<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -334,26 +334,15 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
debug!("note_and_explain_type_err err={:?} cause={:?}", err, cause);
|
debug!("note_and_explain_type_err err={:?} cause={:?}", err, cause);
|
||||||
match err {
|
match err {
|
||||||
Sorts(values) => {
|
Sorts(values) => {
|
||||||
let expected_str = values.expected.sort_string(self);
|
match (values.expected.kind(), values.found.kind()) {
|
||||||
let found_str = values.found.sort_string(self);
|
(ty::Closure(..), ty::Closure(..)) => {
|
||||||
if expected_str == found_str && expected_str == "closure" {
|
|
||||||
db.note("no two closures, even if identical, have the same type");
|
db.note("no two closures, even if identical, have the same type");
|
||||||
db.help("consider boxing your closure and/or using it as a trait object");
|
db.help("consider boxing your closure and/or using it as a trait object");
|
||||||
}
|
}
|
||||||
if expected_str == found_str && expected_str == "opaque type" {
|
(ty::Opaque(..), ty::Opaque(..)) => {
|
||||||
// Issue #63167
|
// Issue #63167
|
||||||
db.note("distinct uses of `impl Trait` result in different opaque types");
|
db.note("distinct uses of `impl Trait` result in different opaque types");
|
||||||
let e_str = values.expected.to_string();
|
|
||||||
let f_str = values.found.to_string();
|
|
||||||
if e_str == f_str && &e_str == "impl std::future::Future" {
|
|
||||||
// FIXME: use non-string based check.
|
|
||||||
db.help(
|
|
||||||
"if both `Future`s have the same `Output` type, consider \
|
|
||||||
`.await`ing on both of them",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
match (values.expected.kind(), values.found.kind()) {
|
|
||||||
(ty::Float(_), ty::Infer(ty::IntVar(_))) => {
|
(ty::Float(_), ty::Infer(ty::IntVar(_))) => {
|
||||||
if let Ok(
|
if let Ok(
|
||||||
// Issue #53280
|
// Issue #53280
|
||||||
|
|
|
@ -1207,7 +1207,13 @@ impl<'a> Parser<'a> {
|
||||||
self.recover_await_prefix(await_sp)?
|
self.recover_await_prefix(await_sp)?
|
||||||
};
|
};
|
||||||
let sp = self.error_on_incorrect_await(lo, hi, &expr, is_question);
|
let sp = self.error_on_incorrect_await(lo, hi, &expr, is_question);
|
||||||
let expr = self.mk_expr(lo.to(sp), ExprKind::Await(expr), attrs);
|
let kind = match expr.kind {
|
||||||
|
// Avoid knock-down errors as we don't know whether to interpret this as `foo().await?`
|
||||||
|
// or `foo()?.await` (the very reason we went with postfix syntax 😅).
|
||||||
|
ExprKind::Try(_) => ExprKind::Err,
|
||||||
|
_ => ExprKind::Await(expr),
|
||||||
|
};
|
||||||
|
let expr = self.mk_expr(lo.to(sp), kind, attrs);
|
||||||
self.maybe_recover_from_bad_qpath(expr, true)
|
self.maybe_recover_from_bad_qpath(expr, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ use rustc_middle::ty::{
|
||||||
};
|
};
|
||||||
use rustc_middle::ty::{TypeAndMut, TypeckResults};
|
use rustc_middle::ty::{TypeAndMut, TypeckResults};
|
||||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||||
use rustc_span::{MultiSpan, Span, DUMMY_SP};
|
use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
|
||||||
use rustc_target::spec::abi;
|
use rustc_target::spec::abi;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
@ -2114,10 +2114,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
if self.predicate_may_hold(&try_obligation) && impls_future {
|
if self.predicate_may_hold(&try_obligation) && impls_future {
|
||||||
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
|
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
|
||||||
if snippet.ends_with('?') {
|
if snippet.ends_with('?') {
|
||||||
err.span_suggestion(
|
err.span_suggestion_verbose(
|
||||||
span,
|
span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(),
|
||||||
"consider using `.await` here",
|
"consider `await`ing on the `Future`",
|
||||||
format!("{}.await?", snippet.trim_end_matches('?')),
|
".await".to_string(),
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ use rustc_trait_selection::opaque_types::InferCtxtExt as _;
|
||||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
||||||
use rustc_trait_selection::traits::{
|
use rustc_trait_selection::traits::{
|
||||||
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
|
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
|
||||||
|
StatementAsExpression,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
|
@ -188,11 +189,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let (arm_span, semi_span) = if let hir::ExprKind::Block(blk, _) = &arm.body.kind {
|
let (arm_span, semi_span) =
|
||||||
self.find_block_span(blk, prior_arm_ty)
|
self.get_appropriate_arm_semicolon_removal_span(&arms, i, prior_arm_ty, arm_ty);
|
||||||
} else {
|
|
||||||
(arm.body.span, None)
|
|
||||||
};
|
|
||||||
let (span, code) = match i {
|
let (span, code) = match i {
|
||||||
// The reason for the first arm to fail is not that the match arms diverge,
|
// The reason for the first arm to fail is not that the match arms diverge,
|
||||||
// but rather that there's a prior obligation that doesn't hold.
|
// but rather that there's a prior obligation that doesn't hold.
|
||||||
|
@ -242,6 +240,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
coercion.complete(self)
|
coercion.complete(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_appropriate_arm_semicolon_removal_span(
|
||||||
|
&self,
|
||||||
|
arms: &'tcx [hir::Arm<'tcx>],
|
||||||
|
i: usize,
|
||||||
|
prior_arm_ty: Option<Ty<'tcx>>,
|
||||||
|
arm_ty: Ty<'tcx>,
|
||||||
|
) -> (Span, Option<(Span, StatementAsExpression)>) {
|
||||||
|
let arm = &arms[i];
|
||||||
|
let (arm_span, mut semi_span) = if let hir::ExprKind::Block(blk, _) = &arm.body.kind {
|
||||||
|
self.find_block_span(blk, prior_arm_ty)
|
||||||
|
} else {
|
||||||
|
(arm.body.span, None)
|
||||||
|
};
|
||||||
|
if semi_span.is_none() && i > 0 {
|
||||||
|
if let hir::ExprKind::Block(blk, _) = &arms[i - 1].body.kind {
|
||||||
|
let (_, semi_span_prev) = self.find_block_span(blk, Some(arm_ty));
|
||||||
|
semi_span = semi_span_prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(arm_span, semi_span)
|
||||||
|
}
|
||||||
|
|
||||||
/// When the previously checked expression (the scrutinee) diverges,
|
/// When the previously checked expression (the scrutinee) diverges,
|
||||||
/// warn the user about the match arms being unreachable.
|
/// warn the user about the match arms being unreachable.
|
||||||
fn warn_arms_when_scrutinee_diverges(
|
fn warn_arms_when_scrutinee_diverges(
|
||||||
|
@ -514,7 +534,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
&self,
|
&self,
|
||||||
block: &'tcx hir::Block<'tcx>,
|
block: &'tcx hir::Block<'tcx>,
|
||||||
expected_ty: Option<Ty<'tcx>>,
|
expected_ty: Option<Ty<'tcx>>,
|
||||||
) -> (Span, Option<Span>) {
|
) -> (Span, Option<(Span, StatementAsExpression)>) {
|
||||||
if let Some(expr) = &block.expr {
|
if let Some(expr) = &block.expr {
|
||||||
(expr.span, None)
|
(expr.span, None)
|
||||||
} else if let Some(stmt) = block.stmts.last() {
|
} else if let Some(stmt) = block.stmts.last() {
|
||||||
|
|
|
@ -33,7 +33,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
|
self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
|
||||||
self.suggest_missing_await(err, expr, expected, expr_ty);
|
|
||||||
self.suggest_missing_parentheses(err, expr);
|
self.suggest_missing_parentheses(err, expr);
|
||||||
self.note_need_for_fn_pointer(err, expected, expr_ty);
|
self.note_need_for_fn_pointer(err, expected, expr_ty);
|
||||||
self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
|
self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
|
||||||
|
|
|
@ -33,7 +33,9 @@ use rustc_span::{self, BytePos, MultiSpan, Span};
|
||||||
use rustc_trait_selection::infer::InferCtxtExt as _;
|
use rustc_trait_selection::infer::InferCtxtExt as _;
|
||||||
use rustc_trait_selection::opaque_types::InferCtxtExt as _;
|
use rustc_trait_selection::opaque_types::InferCtxtExt as _;
|
||||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
||||||
use rustc_trait_selection::traits::{self, ObligationCauseCode, TraitEngine, TraitEngineExt};
|
use rustc_trait_selection::traits::{
|
||||||
|
self, ObligationCauseCode, StatementAsExpression, TraitEngine, TraitEngineExt,
|
||||||
|
};
|
||||||
|
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
@ -1061,7 +1063,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
&self,
|
&self,
|
||||||
blk: &'tcx hir::Block<'tcx>,
|
blk: &'tcx hir::Block<'tcx>,
|
||||||
expected_ty: Ty<'tcx>,
|
expected_ty: Ty<'tcx>,
|
||||||
) -> Option<Span> {
|
) -> Option<(Span, StatementAsExpression)> {
|
||||||
// Be helpful when the user wrote `{... expr;}` and
|
// Be helpful when the user wrote `{... expr;}` and
|
||||||
// taking the `;` off is enough to fix the error.
|
// taking the `;` off is enough to fix the error.
|
||||||
let last_stmt = blk.stmts.last()?;
|
let last_stmt = blk.stmts.last()?;
|
||||||
|
@ -1070,13 +1072,58 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
let last_expr_ty = self.node_ty(last_expr.hir_id);
|
let last_expr_ty = self.node_ty(last_expr.hir_id);
|
||||||
if matches!(last_expr_ty.kind(), ty::Error(_))
|
let needs_box = match (last_expr_ty.kind(), expected_ty.kind()) {
|
||||||
|| self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err()
|
(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());
|
||||||
|
match (
|
||||||
|
&self.tcx.hir().expect_item(last_hir_id).kind,
|
||||||
|
&self.tcx.hir().expect_item(exp_hir_id).kind,
|
||||||
|
) {
|
||||||
|
(
|
||||||
|
hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: last_bounds, .. }),
|
||||||
|
hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: exp_bounds, .. }),
|
||||||
|
) if last_bounds.iter().zip(exp_bounds.iter()).all(|(left, right)| {
|
||||||
|
match (left, right) {
|
||||||
|
(
|
||||||
|
hir::GenericBound::Trait(tl, ml),
|
||||||
|
hir::GenericBound::Trait(tr, mr),
|
||||||
|
) if tl.trait_ref.trait_def_id() == tr.trait_ref.trait_def_id()
|
||||||
|
&& ml == mr =>
|
||||||
|
{
|
||||||
|
true
|
||||||
|
}
|
||||||
|
(
|
||||||
|
hir::GenericBound::LangItemTrait(langl, _, _, argsl),
|
||||||
|
hir::GenericBound::LangItemTrait(langr, _, _, argsr),
|
||||||
|
) if langl == langr => {
|
||||||
|
// FIXME: consider the bounds!
|
||||||
|
debug!("{:?} {:?}", argsl, argsr);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}) =>
|
||||||
|
{
|
||||||
|
StatementAsExpression::NeedsBoxing
|
||||||
|
}
|
||||||
|
_ => StatementAsExpression::CorrectType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => StatementAsExpression::CorrectType,
|
||||||
|
};
|
||||||
|
if (matches!(last_expr_ty.kind(), ty::Error(_))
|
||||||
|
|| self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err())
|
||||||
|
&& matches!(needs_box, StatementAsExpression::CorrectType)
|
||||||
{
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let original_span = original_sp(last_stmt.span, blk.span);
|
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
|
// Instantiates the given path, which must refer to an item with the given
|
||||||
|
|
|
@ -20,7 +20,7 @@ use rustc_middle::ty::{self, Ty};
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::symbol::{sym, Ident};
|
use rustc_span::symbol::{sym, Ident};
|
||||||
use rustc_span::{self, MultiSpan, Span};
|
use rustc_span::{self, MultiSpan, Span};
|
||||||
use rustc_trait_selection::traits::{self, ObligationCauseCode};
|
use rustc_trait_selection::traits::{self, ObligationCauseCode, StatementAsExpression};
|
||||||
|
|
||||||
use std::mem::replace;
|
use std::mem::replace;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
@ -758,8 +758,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
expected_ty: Ty<'tcx>,
|
expected_ty: Ty<'tcx>,
|
||||||
err: &mut DiagnosticBuilder<'_>,
|
err: &mut DiagnosticBuilder<'_>,
|
||||||
) {
|
) {
|
||||||
if let Some(span_semi) = self.could_remove_semicolon(blk, expected_ty) {
|
if let Some((span_semi, boxed)) = self.could_remove_semicolon(blk, expected_ty) {
|
||||||
err.span_suggestion(
|
if let StatementAsExpression::NeedsBoxing = 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,
|
span_semi,
|
||||||
"consider removing this semicolon",
|
"consider removing this semicolon",
|
||||||
String::new(),
|
String::new(),
|
||||||
|
@ -767,6 +775,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn parent_item_span(&self, id: hir::HirId) -> Option<Span> {
|
fn parent_item_span(&self, id: hir::HirId) -> Option<Span> {
|
||||||
let node = self.tcx.hir().get(self.tcx.hir().get_parent_item(id));
|
let node = self.tcx.hir().get(self.tcx.hir().get_parent_item(id));
|
||||||
|
|
|
@ -3,7 +3,6 @@ use crate::astconv::AstConv;
|
||||||
|
|
||||||
use rustc_ast::util::parser::ExprPrecedence;
|
use rustc_ast::util::parser::ExprPrecedence;
|
||||||
use rustc_span::{self, Span};
|
use rustc_span::{self, Span};
|
||||||
use rustc_trait_selection::traits;
|
|
||||||
|
|
||||||
use rustc_errors::{Applicability, DiagnosticBuilder};
|
use rustc_errors::{Applicability, DiagnosticBuilder};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
@ -13,7 +12,6 @@ use rustc_hir::{ExprKind, ItemKind, Node};
|
||||||
use rustc_infer::infer;
|
use rustc_infer::infer;
|
||||||
use rustc_middle::ty::{self, Ty};
|
use rustc_middle::ty::{self, Ty};
|
||||||
use rustc_span::symbol::kw;
|
use rustc_span::symbol::kw;
|
||||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
|
|
||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
|
@ -433,87 +431,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A possible error is to forget to add `.await` when using futures:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// async fn make_u32() -> u32 {
|
|
||||||
/// 22
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn take_u32(x: u32) {}
|
|
||||||
///
|
|
||||||
/// async fn foo() {
|
|
||||||
/// let x = make_u32();
|
|
||||||
/// take_u32(x);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// This routine checks if the found type `T` implements `Future<Output=U>` where `U` is the
|
|
||||||
/// expected type. If this is the case, and we are inside of an async body, it suggests adding
|
|
||||||
/// `.await` to the tail of the expression.
|
|
||||||
pub(in super::super) fn suggest_missing_await(
|
|
||||||
&self,
|
|
||||||
err: &mut DiagnosticBuilder<'_>,
|
|
||||||
expr: &hir::Expr<'_>,
|
|
||||||
expected: Ty<'tcx>,
|
|
||||||
found: Ty<'tcx>,
|
|
||||||
) {
|
|
||||||
debug!("suggest_missing_await: expr={:?} expected={:?}, found={:?}", expr, expected, found);
|
|
||||||
// `.await` is not permitted outside of `async` bodies, so don't bother to suggest if the
|
|
||||||
// body isn't `async`.
|
|
||||||
let item_id = self.tcx().hir().get_parent_node(self.body_id);
|
|
||||||
if let Some(body_id) = self.tcx().hir().maybe_body_owned_by(item_id) {
|
|
||||||
let body = self.tcx().hir().body(body_id);
|
|
||||||
if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind {
|
|
||||||
let sp = expr.span;
|
|
||||||
// Check for `Future` implementations by constructing a predicate to
|
|
||||||
// prove: `<T as Future>::Output == U`
|
|
||||||
let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(sp));
|
|
||||||
let item_def_id = self
|
|
||||||
.tcx
|
|
||||||
.associated_items(future_trait)
|
|
||||||
.in_definition_order()
|
|
||||||
.next()
|
|
||||||
.unwrap()
|
|
||||||
.def_id;
|
|
||||||
// `<T as Future>::Output`
|
|
||||||
let projection_ty = ty::ProjectionTy {
|
|
||||||
// `T`
|
|
||||||
substs: self
|
|
||||||
.tcx
|
|
||||||
.mk_substs_trait(found, self.fresh_substs_for_item(sp, item_def_id)),
|
|
||||||
// `Future::Output`
|
|
||||||
item_def_id,
|
|
||||||
};
|
|
||||||
|
|
||||||
let predicate = ty::PredicateAtom::Projection(ty::ProjectionPredicate {
|
|
||||||
projection_ty,
|
|
||||||
ty: expected,
|
|
||||||
})
|
|
||||||
.potentially_quantified(self.tcx, ty::PredicateKind::ForAll);
|
|
||||||
let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate);
|
|
||||||
|
|
||||||
debug!("suggest_missing_await: trying obligation {:?}", obligation);
|
|
||||||
|
|
||||||
if self.infcx.predicate_may_hold(&obligation) {
|
|
||||||
debug!("suggest_missing_await: obligation held: {:?}", obligation);
|
|
||||||
if let Ok(code) = self.sess().source_map().span_to_snippet(sp) {
|
|
||||||
err.span_suggestion(
|
|
||||||
sp,
|
|
||||||
"consider using `.await` here",
|
|
||||||
format!("{}.await", code),
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
debug!("suggest_missing_await: no snippet for {:?}", sp);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
debug!("suggest_missing_await: obligation did not hold: {:?}", obligation)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(in super::super) fn suggest_missing_parentheses(
|
pub(in super::super) fn suggest_missing_parentheses(
|
||||||
&self,
|
&self,
|
||||||
err: &mut DiagnosticBuilder<'_>,
|
err: &mut DiagnosticBuilder<'_>,
|
||||||
|
|
|
@ -14,7 +14,6 @@ async fn foo2() -> Result<(), ()> {
|
||||||
}
|
}
|
||||||
async fn foo3() -> Result<(), ()> {
|
async fn foo3() -> Result<(), ()> {
|
||||||
let _ = await bar()?; //~ ERROR incorrect use of `await`
|
let _ = await bar()?; //~ ERROR incorrect use of `await`
|
||||||
//~^ ERROR the `?` operator can only be applied to values that implement `Try`
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
async fn foo21() -> Result<(), ()> {
|
async fn foo21() -> Result<(), ()> {
|
||||||
|
@ -60,9 +59,7 @@ fn foo10() -> Result<(), ()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn foo11() -> Result<(), ()> {
|
fn foo11() -> Result<(), ()> {
|
||||||
let _ = await bar()?; //~ ERROR `await` is only allowed inside `async` functions and blocks
|
let _ = await bar()?; //~ ERROR incorrect use of `await`
|
||||||
//~^ ERROR incorrect use of `await`
|
|
||||||
//~| ERROR the `?` operator can only be applied to values that implement `Try`
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn foo12() -> Result<(), ()> {
|
fn foo12() -> Result<(), ()> {
|
||||||
|
|
|
@ -17,103 +17,103 @@ LL | let _ = await bar()?;
|
||||||
| ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar()?.await`
|
| ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar()?.await`
|
||||||
|
|
||||||
error: incorrect use of `await`
|
error: incorrect use of `await`
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:21:13
|
--> $DIR/incorrect-syntax-suggestions.rs:20:13
|
||||||
|
|
|
|
||||||
LL | let _ = await { bar() };
|
LL | let _ = await { bar() };
|
||||||
| ^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ bar() }.await`
|
| ^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ bar() }.await`
|
||||||
|
|
||||||
error: incorrect use of `await`
|
error: incorrect use of `await`
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:25:13
|
--> $DIR/incorrect-syntax-suggestions.rs:24:13
|
||||||
|
|
|
|
||||||
LL | let _ = await(bar());
|
LL | let _ = await(bar());
|
||||||
| ^^^^^^^^^^^^ help: `await` is a postfix operation: `(bar()).await`
|
| ^^^^^^^^^^^^ help: `await` is a postfix operation: `(bar()).await`
|
||||||
|
|
||||||
error: incorrect use of `await`
|
error: incorrect use of `await`
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:29:13
|
--> $DIR/incorrect-syntax-suggestions.rs:28:13
|
||||||
|
|
|
|
||||||
LL | let _ = await { bar() }?;
|
LL | let _ = await { bar() }?;
|
||||||
| ^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ bar() }.await`
|
| ^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ bar() }.await`
|
||||||
|
|
||||||
error: incorrect use of `await`
|
error: incorrect use of `await`
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:33:14
|
--> $DIR/incorrect-syntax-suggestions.rs:32:14
|
||||||
|
|
|
|
||||||
LL | let _ = (await bar())?;
|
LL | let _ = (await bar())?;
|
||||||
| ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
|
| ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
|
||||||
|
|
||||||
error: incorrect use of `await`
|
error: incorrect use of `await`
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:37:24
|
--> $DIR/incorrect-syntax-suggestions.rs:36:24
|
||||||
|
|
|
|
||||||
LL | let _ = bar().await();
|
LL | let _ = bar().await();
|
||||||
| ^^ help: `await` is not a method call, remove the parentheses
|
| ^^ help: `await` is not a method call, remove the parentheses
|
||||||
|
|
||||||
error: incorrect use of `await`
|
error: incorrect use of `await`
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:41:24
|
--> $DIR/incorrect-syntax-suggestions.rs:40:24
|
||||||
|
|
|
|
||||||
LL | let _ = bar().await()?;
|
LL | let _ = bar().await()?;
|
||||||
| ^^ help: `await` is not a method call, remove the parentheses
|
| ^^ help: `await` is not a method call, remove the parentheses
|
||||||
|
|
||||||
error: incorrect use of `await`
|
error: incorrect use of `await`
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:53:13
|
--> $DIR/incorrect-syntax-suggestions.rs:52:13
|
||||||
|
|
|
|
||||||
LL | let _ = await bar();
|
LL | let _ = await bar();
|
||||||
| ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
|
| ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
|
||||||
|
|
||||||
error: incorrect use of `await`
|
error: incorrect use of `await`
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:58:13
|
--> $DIR/incorrect-syntax-suggestions.rs:57:13
|
||||||
|
|
|
|
||||||
LL | let _ = await? bar();
|
LL | let _ = await? bar();
|
||||||
| ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await?`
|
| ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await?`
|
||||||
|
|
||||||
error: incorrect use of `await`
|
error: incorrect use of `await`
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:63:13
|
--> $DIR/incorrect-syntax-suggestions.rs:62:13
|
||||||
|
|
|
|
||||||
LL | let _ = await bar()?;
|
LL | let _ = await bar()?;
|
||||||
| ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar()?.await`
|
| ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar()?.await`
|
||||||
|
|
||||||
error: incorrect use of `await`
|
error: incorrect use of `await`
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:69:14
|
--> $DIR/incorrect-syntax-suggestions.rs:66:14
|
||||||
|
|
|
|
||||||
LL | let _ = (await bar())?;
|
LL | let _ = (await bar())?;
|
||||||
| ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
|
| ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
|
||||||
|
|
||||||
error: incorrect use of `await`
|
error: incorrect use of `await`
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:74:24
|
--> $DIR/incorrect-syntax-suggestions.rs:71:24
|
||||||
|
|
|
|
||||||
LL | let _ = bar().await();
|
LL | let _ = bar().await();
|
||||||
| ^^ help: `await` is not a method call, remove the parentheses
|
| ^^ help: `await` is not a method call, remove the parentheses
|
||||||
|
|
||||||
error: incorrect use of `await`
|
error: incorrect use of `await`
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:79:24
|
--> $DIR/incorrect-syntax-suggestions.rs:76:24
|
||||||
|
|
|
|
||||||
LL | let _ = bar().await()?;
|
LL | let _ = bar().await()?;
|
||||||
| ^^ help: `await` is not a method call, remove the parentheses
|
| ^^ help: `await` is not a method call, remove the parentheses
|
||||||
|
|
||||||
error: incorrect use of `await`
|
error: incorrect use of `await`
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:107:13
|
--> $DIR/incorrect-syntax-suggestions.rs:104:13
|
||||||
|
|
|
|
||||||
LL | let _ = await!(bar());
|
LL | let _ = await!(bar());
|
||||||
| ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
|
| ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
|
||||||
|
|
||||||
error: incorrect use of `await`
|
error: incorrect use of `await`
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:111:13
|
--> $DIR/incorrect-syntax-suggestions.rs:108:13
|
||||||
|
|
|
|
||||||
LL | let _ = await!(bar())?;
|
LL | let _ = await!(bar())?;
|
||||||
| ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
|
| ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
|
||||||
|
|
||||||
error: incorrect use of `await`
|
error: incorrect use of `await`
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:116:17
|
--> $DIR/incorrect-syntax-suggestions.rs:113:17
|
||||||
|
|
|
|
||||||
LL | let _ = await!(bar())?;
|
LL | let _ = await!(bar())?;
|
||||||
| ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
|
| ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
|
||||||
|
|
||||||
error: incorrect use of `await`
|
error: incorrect use of `await`
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:124:17
|
--> $DIR/incorrect-syntax-suggestions.rs:121:17
|
||||||
|
|
|
|
||||||
LL | let _ = await!(bar())?;
|
LL | let _ = await!(bar())?;
|
||||||
| ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
|
| ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
|
||||||
|
|
||||||
error: expected expression, found `=>`
|
error: expected expression, found `=>`
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:132:25
|
--> $DIR/incorrect-syntax-suggestions.rs:129:25
|
||||||
|
|
|
|
||||||
LL | match await { await => () }
|
LL | match await { await => () }
|
||||||
| ----- ^^ expected expression
|
| ----- ^^ expected expression
|
||||||
|
@ -121,13 +121,13 @@ LL | match await { await => () }
|
||||||
| while parsing this incorrect await expression
|
| while parsing this incorrect await expression
|
||||||
|
|
||||||
error: incorrect use of `await`
|
error: incorrect use of `await`
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:132:11
|
--> $DIR/incorrect-syntax-suggestions.rs:129:11
|
||||||
|
|
|
|
||||||
LL | match await { await => () }
|
LL | match await { await => () }
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ await => () }.await`
|
| ^^^^^^^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ await => () }.await`
|
||||||
|
|
||||||
error: expected one of `.`, `?`, `{`, or an operator, found `}`
|
error: expected one of `.`, `?`, `{`, or an operator, found `}`
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:135:1
|
--> $DIR/incorrect-syntax-suggestions.rs:132:1
|
||||||
|
|
|
|
||||||
LL | match await { await => () }
|
LL | match await { await => () }
|
||||||
| ----- - expected one of `.`, `?`, `{`, or an operator
|
| ----- - expected one of `.`, `?`, `{`, or an operator
|
||||||
|
@ -138,7 +138,7 @@ LL | }
|
||||||
| ^ unexpected token
|
| ^ unexpected token
|
||||||
|
|
||||||
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:53:13
|
--> $DIR/incorrect-syntax-suggestions.rs:52:13
|
||||||
|
|
|
|
||||||
LL | fn foo9() -> Result<(), ()> {
|
LL | fn foo9() -> Result<(), ()> {
|
||||||
| ---- this is not `async`
|
| ---- this is not `async`
|
||||||
|
@ -146,7 +146,7 @@ LL | let _ = await bar();
|
||||||
| ^^^^^^^^^^^ only allowed inside `async` functions and blocks
|
| ^^^^^^^^^^^ only allowed inside `async` functions and blocks
|
||||||
|
|
||||||
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:58:13
|
--> $DIR/incorrect-syntax-suggestions.rs:57:13
|
||||||
|
|
|
|
||||||
LL | fn foo10() -> Result<(), ()> {
|
LL | fn foo10() -> Result<(), ()> {
|
||||||
| ----- this is not `async`
|
| ----- this is not `async`
|
||||||
|
@ -154,15 +154,7 @@ LL | let _ = await? bar();
|
||||||
| ^^^^^^^^^^^^ only allowed inside `async` functions and blocks
|
| ^^^^^^^^^^^^ only allowed inside `async` functions and blocks
|
||||||
|
|
||||||
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:63:13
|
--> $DIR/incorrect-syntax-suggestions.rs:66:14
|
||||||
|
|
|
||||||
LL | fn foo11() -> Result<(), ()> {
|
|
||||||
| ----- this is not `async`
|
|
||||||
LL | let _ = await bar()?;
|
|
||||||
| ^^^^^^^^^^^^ only allowed inside `async` functions and blocks
|
|
||||||
|
|
||||||
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:69:14
|
|
||||||
|
|
|
|
||||||
LL | fn foo12() -> Result<(), ()> {
|
LL | fn foo12() -> Result<(), ()> {
|
||||||
| ----- this is not `async`
|
| ----- this is not `async`
|
||||||
|
@ -170,7 +162,7 @@ LL | let _ = (await bar())?;
|
||||||
| ^^^^^^^^^^^ only allowed inside `async` functions and blocks
|
| ^^^^^^^^^^^ only allowed inside `async` functions and blocks
|
||||||
|
|
||||||
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:74:13
|
--> $DIR/incorrect-syntax-suggestions.rs:71:13
|
||||||
|
|
|
|
||||||
LL | fn foo13() -> Result<(), ()> {
|
LL | fn foo13() -> Result<(), ()> {
|
||||||
| ----- this is not `async`
|
| ----- this is not `async`
|
||||||
|
@ -178,7 +170,7 @@ LL | let _ = bar().await();
|
||||||
| ^^^^^^^^^^^ only allowed inside `async` functions and blocks
|
| ^^^^^^^^^^^ only allowed inside `async` functions and blocks
|
||||||
|
|
||||||
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:79:13
|
--> $DIR/incorrect-syntax-suggestions.rs:76:13
|
||||||
|
|
|
|
||||||
LL | fn foo14() -> Result<(), ()> {
|
LL | fn foo14() -> Result<(), ()> {
|
||||||
| ----- this is not `async`
|
| ----- this is not `async`
|
||||||
|
@ -186,7 +178,7 @@ LL | let _ = bar().await()?;
|
||||||
| ^^^^^^^^^^^ only allowed inside `async` functions and blocks
|
| ^^^^^^^^^^^ only allowed inside `async` functions and blocks
|
||||||
|
|
||||||
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:84:13
|
--> $DIR/incorrect-syntax-suggestions.rs:81:13
|
||||||
|
|
|
|
||||||
LL | fn foo15() -> Result<(), ()> {
|
LL | fn foo15() -> Result<(), ()> {
|
||||||
| ----- this is not `async`
|
| ----- this is not `async`
|
||||||
|
@ -194,7 +186,7 @@ LL | let _ = bar().await;
|
||||||
| ^^^^^^^^^^^ only allowed inside `async` functions and blocks
|
| ^^^^^^^^^^^ only allowed inside `async` functions and blocks
|
||||||
|
|
||||||
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:88:13
|
--> $DIR/incorrect-syntax-suggestions.rs:85:13
|
||||||
|
|
|
|
||||||
LL | fn foo16() -> Result<(), ()> {
|
LL | fn foo16() -> Result<(), ()> {
|
||||||
| ----- this is not `async`
|
| ----- this is not `async`
|
||||||
|
@ -202,7 +194,7 @@ LL | let _ = bar().await?;
|
||||||
| ^^^^^^^^^^^ only allowed inside `async` functions and blocks
|
| ^^^^^^^^^^^ only allowed inside `async` functions and blocks
|
||||||
|
|
||||||
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:93:17
|
--> $DIR/incorrect-syntax-suggestions.rs:90:17
|
||||||
|
|
|
|
||||||
LL | fn foo() -> Result<(), ()> {
|
LL | fn foo() -> Result<(), ()> {
|
||||||
| --- this is not `async`
|
| --- this is not `async`
|
||||||
|
@ -210,7 +202,7 @@ LL | let _ = bar().await?;
|
||||||
| ^^^^^^^^^^^ only allowed inside `async` functions and blocks
|
| ^^^^^^^^^^^ only allowed inside `async` functions and blocks
|
||||||
|
|
||||||
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:100:17
|
--> $DIR/incorrect-syntax-suggestions.rs:97:17
|
||||||
|
|
|
|
||||||
LL | let foo = || {
|
LL | let foo = || {
|
||||||
| -- this is not `async`
|
| -- this is not `async`
|
||||||
|
@ -218,7 +210,7 @@ LL | let _ = bar().await?;
|
||||||
| ^^^^^^^^^^^ only allowed inside `async` functions and blocks
|
| ^^^^^^^^^^^ only allowed inside `async` functions and blocks
|
||||||
|
|
||||||
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:116:17
|
--> $DIR/incorrect-syntax-suggestions.rs:113:17
|
||||||
|
|
|
|
||||||
LL | fn foo() -> Result<(), ()> {
|
LL | fn foo() -> Result<(), ()> {
|
||||||
| --- this is not `async`
|
| --- this is not `async`
|
||||||
|
@ -226,35 +218,13 @@ LL | let _ = await!(bar())?;
|
||||||
| ^^^^^^^^^^^^^ only allowed inside `async` functions and blocks
|
| ^^^^^^^^^^^^^ only allowed inside `async` functions and blocks
|
||||||
|
|
||||||
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
error[E0728]: `await` is only allowed inside `async` functions and blocks
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:124:17
|
--> $DIR/incorrect-syntax-suggestions.rs:121:17
|
||||||
|
|
|
|
||||||
LL | let foo = || {
|
LL | let foo = || {
|
||||||
| -- this is not `async`
|
| -- this is not `async`
|
||||||
LL | let _ = await!(bar())?;
|
LL | let _ = await!(bar())?;
|
||||||
| ^^^^^^^^^^^^^ only allowed inside `async` functions and blocks
|
| ^^^^^^^^^^^^^ only allowed inside `async` functions and blocks
|
||||||
|
|
||||||
error[E0277]: the `?` operator can only be applied to values that implement `Try`
|
error: aborting due to 33 previous errors
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:16:19
|
|
||||||
|
|
|
||||||
LL | let _ = await bar()?;
|
|
||||||
| ^^^^^^
|
|
||||||
| |
|
|
||||||
| the `?` operator cannot be applied to type `impl Future`
|
|
||||||
| help: consider using `.await` here: `bar().await?`
|
|
||||||
|
|
|
||||||
= help: the trait `Try` is not implemented for `impl Future`
|
|
||||||
= note: required by `into_result`
|
|
||||||
|
|
||||||
error[E0277]: the `?` operator can only be applied to values that implement `Try`
|
For more information about this error, try `rustc --explain E0728`.
|
||||||
--> $DIR/incorrect-syntax-suggestions.rs:63:19
|
|
||||||
|
|
|
||||||
LL | let _ = await bar()?;
|
|
||||||
| ^^^^^^ the `?` operator cannot be applied to type `impl Future`
|
|
||||||
|
|
|
||||||
= help: the trait `Try` is not implemented for `impl Future`
|
|
||||||
= note: required by `into_result`
|
|
||||||
|
|
||||||
error: aborting due to 36 previous errors
|
|
||||||
|
|
||||||
Some errors have detailed explanations: E0277, E0728.
|
|
||||||
For more information about an error, try `rustc --explain E0277`.
|
|
||||||
|
|
|
@ -9,6 +9,10 @@ LL | take_u32(x)
|
||||||
|
|
|
|
||||||
= note: expected type `u32`
|
= note: expected type `u32`
|
||||||
found opaque type `impl Future`
|
found opaque type `impl Future`
|
||||||
|
help: consider `await`ing on the `Future`
|
||||||
|
|
|
||||||
|
LL | take_u32(x.await)
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -2,25 +2,27 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try
|
||||||
--> $DIR/issue-61076.rs:42:5
|
--> $DIR/issue-61076.rs:42:5
|
||||||
|
|
|
|
||||||
LL | foo()?;
|
LL | foo()?;
|
||||||
| ^^^^^^
|
| ^^^^^^ the `?` operator cannot be applied to type `impl Future`
|
||||||
| |
|
|
||||||
| the `?` operator cannot be applied to type `impl Future`
|
|
||||||
| help: consider using `.await` here: `foo().await?`
|
|
||||||
|
|
|
|
||||||
= help: the trait `Try` is not implemented for `impl Future`
|
= help: the trait `Try` is not implemented for `impl Future`
|
||||||
= note: required by `into_result`
|
= note: required by `into_result`
|
||||||
|
help: consider `await`ing on the `Future`
|
||||||
|
|
|
||||||
|
LL | foo().await?;
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
error[E0277]: the `?` operator can only be applied to values that implement `Try`
|
error[E0277]: the `?` operator can only be applied to values that implement `Try`
|
||||||
--> $DIR/issue-61076.rs:56:5
|
--> $DIR/issue-61076.rs:56:5
|
||||||
|
|
|
|
||||||
LL | t?;
|
LL | t?;
|
||||||
| ^^
|
| ^^ the `?` operator cannot be applied to type `T`
|
||||||
| |
|
|
||||||
| the `?` operator cannot be applied to type `T`
|
|
||||||
| help: consider using `.await` here: `t.await?`
|
|
||||||
|
|
|
|
||||||
= help: the trait `Try` is not implemented for `T`
|
= help: the trait `Try` is not implemented for `T`
|
||||||
= note: required by `into_result`
|
= note: required by `into_result`
|
||||||
|
help: consider `await`ing on the `Future`
|
||||||
|
|
|
||||||
|
LL | t.await?;
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
error[E0609]: no field `0` on type `impl Future`
|
error[E0609]: no field `0` on type `impl Future`
|
||||||
--> $DIR/issue-61076.rs:58:26
|
--> $DIR/issue-61076.rs:58:26
|
||||||
|
@ -51,6 +53,10 @@ LL | Tuple(_) => {}
|
||||||
|
|
|
|
||||||
= note: expected opaque type `impl Future`
|
= note: expected opaque type `impl Future`
|
||||||
found struct `Tuple`
|
found struct `Tuple`
|
||||||
|
help: consider `await`ing on the `Future`
|
||||||
|
|
|
||||||
|
LL | match tuple().await {
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
error: aborting due to 6 previous errors
|
error: aborting due to 6 previous errors
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,8 @@ async fn suggest_await_in_async_closure() {
|
||||||
let x = make_u32();
|
let x = make_u32();
|
||||||
take_u32(x.await)
|
take_u32(x.await)
|
||||||
//~^ ERROR mismatched types [E0308]
|
//~^ ERROR mismatched types [E0308]
|
||||||
//~| HELP consider using `.await` here
|
//~| HELP consider `await`ing on the `Future`
|
||||||
//~| SUGGESTION x.await
|
//~| SUGGESTION .await
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,8 @@ async fn suggest_await_in_async_closure() {
|
||||||
let x = make_u32();
|
let x = make_u32();
|
||||||
take_u32(x)
|
take_u32(x)
|
||||||
//~^ ERROR mismatched types [E0308]
|
//~^ ERROR mismatched types [E0308]
|
||||||
//~| HELP consider using `.await` here
|
//~| HELP consider `await`ing on the `Future`
|
||||||
//~| SUGGESTION x.await
|
//~| SUGGESTION .await
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,14 @@ LL | async fn make_u32() -> u32 {
|
||||||
| --- the `Output` of this `async fn`'s found opaque type
|
| --- the `Output` of this `async fn`'s found opaque type
|
||||||
...
|
...
|
||||||
LL | take_u32(x)
|
LL | take_u32(x)
|
||||||
| ^
|
| ^ expected `u32`, found opaque type
|
||||||
| |
|
|
||||||
| expected `u32`, found opaque type
|
|
||||||
| help: consider using `.await` here: `x.await`
|
|
||||||
|
|
|
|
||||||
= note: expected type `u32`
|
= note: expected type `u32`
|
||||||
found opaque type `impl Future`
|
found opaque type `impl Future`
|
||||||
|
help: consider `await`ing on the `Future`
|
||||||
|
|
|
||||||
|
LL | take_u32(x.await)
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
// edition:2018
|
|
||||||
// run-rustfix
|
|
||||||
|
|
||||||
fn take_u32(_x: u32) {}
|
|
||||||
|
|
||||||
async fn make_u32() -> u32 {
|
|
||||||
22
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
async fn suggest_await_in_async_fn() {
|
|
||||||
let x = make_u32();
|
|
||||||
take_u32(x.await)
|
|
||||||
//~^ ERROR mismatched types [E0308]
|
|
||||||
//~| HELP consider using `.await` here
|
|
||||||
//~| SUGGESTION x.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn dummy() {}
|
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
async fn suggest_await_in_async_fn_return() {
|
|
||||||
dummy().await;
|
|
||||||
//~^ ERROR mismatched types [E0308]
|
|
||||||
//~| HELP try adding a semicolon
|
|
||||||
//~| HELP consider using `.await` here
|
|
||||||
//~| SUGGESTION dummy().await
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {}
|
|
|
@ -1,5 +1,4 @@
|
||||||
// edition:2018
|
// edition:2018
|
||||||
// run-rustfix
|
|
||||||
|
|
||||||
fn take_u32(_x: u32) {}
|
fn take_u32(_x: u32) {}
|
||||||
|
|
||||||
|
@ -12,8 +11,8 @@ async fn suggest_await_in_async_fn() {
|
||||||
let x = make_u32();
|
let x = make_u32();
|
||||||
take_u32(x)
|
take_u32(x)
|
||||||
//~^ ERROR mismatched types [E0308]
|
//~^ ERROR mismatched types [E0308]
|
||||||
//~| HELP consider using `.await` here
|
//~| HELP consider `await`ing on the `Future`
|
||||||
//~| SUGGESTION x.await
|
//~| SUGGESTION .await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn dummy() {}
|
async fn dummy() {}
|
||||||
|
@ -23,8 +22,8 @@ async fn suggest_await_in_async_fn_return() {
|
||||||
dummy()
|
dummy()
|
||||||
//~^ ERROR mismatched types [E0308]
|
//~^ ERROR mismatched types [E0308]
|
||||||
//~| HELP try adding a semicolon
|
//~| HELP try adding a semicolon
|
||||||
//~| HELP consider using `.await` here
|
//~| HELP consider `await`ing on the `Future`
|
||||||
//~| SUGGESTION dummy().await
|
//~| SUGGESTION .await
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,20 +1,21 @@
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/suggest-missing-await.rs:13:14
|
--> $DIR/suggest-missing-await.rs:12:14
|
||||||
|
|
|
|
||||||
LL | async fn make_u32() -> u32 {
|
LL | async fn make_u32() -> u32 {
|
||||||
| --- the `Output` of this `async fn`'s found opaque type
|
| --- the `Output` of this `async fn`'s found opaque type
|
||||||
...
|
...
|
||||||
LL | take_u32(x)
|
LL | take_u32(x)
|
||||||
| ^
|
| ^ expected `u32`, found opaque type
|
||||||
| |
|
|
||||||
| expected `u32`, found opaque type
|
|
||||||
| help: consider using `.await` here: `x.await`
|
|
||||||
|
|
|
|
||||||
= note: expected type `u32`
|
= note: expected type `u32`
|
||||||
found opaque type `impl Future`
|
found opaque type `impl Future`
|
||||||
|
help: consider `await`ing on the `Future`
|
||||||
|
|
|
||||||
|
LL | take_u32(x.await)
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/suggest-missing-await.rs:23:5
|
--> $DIR/suggest-missing-await.rs:22:5
|
||||||
|
|
|
|
||||||
LL | async fn dummy() {}
|
LL | async fn dummy() {}
|
||||||
| - the `Output` of this `async fn`'s found opaque type
|
| - the `Output` of this `async fn`'s found opaque type
|
||||||
|
@ -24,14 +25,14 @@ LL | dummy()
|
||||||
|
|
|
|
||||||
= note: expected unit type `()`
|
= note: expected unit type `()`
|
||||||
found opaque type `impl Future`
|
found opaque type `impl Future`
|
||||||
|
help: consider `await`ing on the `Future`
|
||||||
|
|
|
||||||
|
LL | dummy().await
|
||||||
|
| ^^^^^^
|
||||||
help: try adding a semicolon
|
help: try adding a semicolon
|
||||||
|
|
|
|
||||||
LL | dummy();
|
LL | dummy();
|
||||||
| ^
|
| ^
|
||||||
help: consider using `.await` here
|
|
||||||
|
|
|
||||||
LL | dummy().await
|
|
||||||
|
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
|
@ -2,13 +2,14 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try
|
||||||
--> $DIR/issue-72766.rs:14:5
|
--> $DIR/issue-72766.rs:14:5
|
||||||
|
|
|
|
||||||
LL | SadGirl {}.call()?;
|
LL | SadGirl {}.call()?;
|
||||||
| ^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^ the `?` operator cannot be applied to type `impl Future`
|
||||||
| |
|
|
||||||
| the `?` operator cannot be applied to type `impl Future`
|
|
||||||
| help: consider using `.await` here: `SadGirl {}.call().await?`
|
|
||||||
|
|
|
|
||||||
= help: the trait `Try` is not implemented for `impl Future`
|
= help: the trait `Try` is not implemented for `impl Future`
|
||||||
= note: required by `into_result`
|
= note: required by `into_result`
|
||||||
|
help: consider `await`ing on the `Future`
|
||||||
|
|
|
||||||
|
LL | SadGirl {}.call().await?;
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
57
src/test/ui/suggestions/match-prev-arm-needing-semi.rs
Normal file
57
src/test/ui/suggestions/match-prev-arm-needing-semi.rs
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
// edition:2018
|
||||||
|
|
||||||
|
fn dummy() -> i32 { 42 }
|
||||||
|
|
||||||
|
fn extra_semicolon() {
|
||||||
|
let _ = match true { //~ NOTE `match` arms have incompatible types
|
||||||
|
true => {
|
||||||
|
dummy(); //~ NOTE this is found to be
|
||||||
|
//~^ HELP consider removing this semicolon
|
||||||
|
}
|
||||||
|
false => dummy(), //~ ERROR `match` arms have incompatible types
|
||||||
|
//~^ NOTE expected `()`, found `i32`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
//~^ 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
|
||||||
|
true => {
|
||||||
|
async_dummy(); //~ NOTE this is found to be
|
||||||
|
//~^ HELP consider removing this semicolon
|
||||||
|
}
|
||||||
|
false => async_dummy(), //~ ERROR `match` arms have incompatible types
|
||||||
|
//~^ NOTE expected `()`, found opaque type
|
||||||
|
//~| NOTE expected type `()`
|
||||||
|
//~| HELP consider `await`ing on the `Future`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
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`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn async_different_futures() {
|
||||||
|
let _ = match true { //~ NOTE `match` arms have incompatible types
|
||||||
|
true => async_dummy(), //~ NOTE this is found to be
|
||||||
|
//~| HELP consider `await`ing on both `Future`s
|
||||||
|
false => async_dummy2(), //~ ERROR `match` arms have incompatible types
|
||||||
|
//~^ NOTE expected opaque type, found a different opaque type
|
||||||
|
//~| NOTE expected type `impl Future`
|
||||||
|
//~| NOTE distinct uses of `impl Trait` result in different opaque types
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
118
src/test/ui/suggestions/match-prev-arm-needing-semi.stderr
Normal file
118
src/test/ui/suggestions/match-prev-arm-needing-semi.stderr
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
error[E0308]: `match` arms have incompatible types
|
||||||
|
--> $DIR/match-prev-arm-needing-semi.rs:26:18
|
||||||
|
|
|
||||||
|
LL | async fn async_dummy() {}
|
||||||
|
| - 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_dummy(),
|
||||||
|
| | ^^^^^^^^^^^^^ expected `()`, found opaque type
|
||||||
|
... |
|
||||||
|
LL | |
|
||||||
|
LL | | };
|
||||||
|
| |_____- `match` arms have incompatible types
|
||||||
|
|
|
||||||
|
= note: expected type `()`
|
||||||
|
found opaque type `impl Future`
|
||||||
|
help: consider `await`ing on the `Future`
|
||||||
|
|
|
||||||
|
LL | false => async_dummy().await,
|
||||||
|
| ^^^^^^
|
||||||
|
help: consider removing this semicolon and boxing the expressions
|
||||||
|
|
|
||||||
|
LL | Box::new(async_dummy())
|
||||||
|
LL |
|
||||||
|
LL | }
|
||||||
|
LL | false => Box::new(async_dummy()),
|
||||||
|
|
|
||||||
|
|
||||||
|
error[E0308]: `match` arms have incompatible types
|
||||||
|
--> $DIR/match-prev-arm-needing-semi.rs:39: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 `await`ing on the `Future`
|
||||||
|
|
|
||||||
|
LL | false => async_dummy2().await,
|
||||||
|
| ^^^^^^
|
||||||
|
help: consider removing this semicolon and boxing the expressions
|
||||||
|
|
|
||||||
|
LL | Box::new(async_dummy())
|
||||||
|
LL |
|
||||||
|
LL | }
|
||||||
|
LL | false => Box::new(async_dummy2()),
|
||||||
|
|
|
||||||
|
|
||||||
|
error[E0308]: `match` arms have incompatible types
|
||||||
|
--> $DIR/match-prev-arm-needing-semi.rs:50:18
|
||||||
|
|
|
||||||
|
LL | async fn async_dummy2() {}
|
||||||
|
| - the `Output` of this `async fn`'s found opaque type
|
||||||
|
...
|
||||||
|
LL | let _ = match true {
|
||||||
|
| _____________-
|
||||||
|
LL | | true => async_dummy(),
|
||||||
|
| | ------------- this is found to be of type `impl Future`
|
||||||
|
LL | |
|
||||||
|
LL | | false => async_dummy2(),
|
||||||
|
| | ^^^^^^^^^^^^^^ expected opaque type, found a different opaque type
|
||||||
|
... |
|
||||||
|
LL | |
|
||||||
|
LL | | };
|
||||||
|
| |_____- `match` arms have incompatible types
|
||||||
|
|
|
||||||
|
= note: expected type `impl Future` (opaque type at <$DIR/match-prev-arm-needing-semi.rs:16:24>)
|
||||||
|
found opaque type `impl Future` (opaque type at <$DIR/match-prev-arm-needing-semi.rs:17:25>)
|
||||||
|
= note: distinct uses of `impl Trait` result in different opaque types
|
||||||
|
help: consider `await`ing on both `Future`s
|
||||||
|
|
|
||||||
|
LL | true => async_dummy().await,
|
||||||
|
LL |
|
||||||
|
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 {
|
||||||
|
| _____________-
|
||||||
|
LL | | true => {
|
||||||
|
LL | | dummy();
|
||||||
|
| | --------
|
||||||
|
| | | |
|
||||||
|
| | | help: consider removing this semicolon
|
||||||
|
| | this is found to be of type `()`
|
||||||
|
LL | |
|
||||||
|
LL | | }
|
||||||
|
LL | | false => dummy(),
|
||||||
|
| | ^^^^^^^ expected `()`, found `i32`
|
||||||
|
LL | |
|
||||||
|
LL | | };
|
||||||
|
| |_____- `match` arms have incompatible types
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
|
@ -16,6 +16,12 @@ LL | | }.await
|
||||||
= note: expected type `impl Future` (opaque type at <$DIR/opaque-type-error.rs:8:19>)
|
= note: expected type `impl Future` (opaque type at <$DIR/opaque-type-error.rs:8:19>)
|
||||||
found opaque type `impl Future` (opaque type at <$DIR/opaque-type-error.rs:12:19>)
|
found opaque type `impl Future` (opaque type at <$DIR/opaque-type-error.rs:12:19>)
|
||||||
= note: distinct uses of `impl Trait` result in different opaque types
|
= note: distinct uses of `impl Trait` result in different opaque types
|
||||||
|
help: consider `await`ing on both `Future`s
|
||||||
|
|
|
||||||
|
LL | thing_one().await
|
||||||
|
LL | } else {
|
||||||
|
LL | thing_two().await
|
||||||
|
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue