Make the error message better
This commit is contained in:
parent
16cbdd0321
commit
e65abc0ea5
5 changed files with 72 additions and 13 deletions
|
@ -206,6 +206,9 @@ hir_analysis_manual_implementation =
|
||||||
.label = manual implementations of `{$trait_name}` are experimental
|
.label = manual implementations of `{$trait_name}` are experimental
|
||||||
.help = add `#![feature(unboxed_closures)]` to the crate attributes to enable
|
.help = add `#![feature(unboxed_closures)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
hir_analysis_method_should_return_future = method should be `async` or return a future, but it is synchronous
|
||||||
|
.note = this method is `async` so it expects a future to be returned
|
||||||
|
|
||||||
hir_analysis_missing_one_of_trait_item = not all trait items implemented, missing one of: `{$missing_items_msg}`
|
hir_analysis_missing_one_of_trait_item = not all trait items implemented, missing one of: `{$missing_items_msg}`
|
||||||
.label = missing one of `{$missing_items_msg}` in implementation
|
.label = missing one of `{$missing_items_msg}` in implementation
|
||||||
.note = required because of this annotation
|
.note = required because of this annotation
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use super::potentially_plural_count;
|
use super::potentially_plural_count;
|
||||||
use crate::errors::LifetimesOrBoundsMismatchOnTrait;
|
use crate::errors::{LifetimesOrBoundsMismatchOnTrait, MethodShouldReturnFuture};
|
||||||
use hir::def_id::{DefId, DefIdMap, LocalDefId};
|
use hir::def_id::{DefId, DefIdMap, LocalDefId};
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
|
||||||
use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, ErrorGuaranteed};
|
use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, ErrorGuaranteed};
|
||||||
|
@ -10,7 +10,7 @@ use rustc_hir::{GenericParamKind, ImplItemKind};
|
||||||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
|
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
|
||||||
use rustc_infer::traits::util;
|
use rustc_infer::traits::{util, FulfillmentError};
|
||||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||||
use rustc_middle::ty::fold::BottomUpFolder;
|
use rustc_middle::ty::fold::BottomUpFolder;
|
||||||
use rustc_middle::ty::util::ExplicitSelf;
|
use rustc_middle::ty::util::ExplicitSelf;
|
||||||
|
@ -664,8 +664,13 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
|
||||||
// RPITs.
|
// RPITs.
|
||||||
let errors = ocx.select_all_or_error();
|
let errors = ocx.select_all_or_error();
|
||||||
if !errors.is_empty() {
|
if !errors.is_empty() {
|
||||||
let reported = infcx.err_ctxt().report_fulfillment_errors(errors);
|
if let Err(guar) = try_report_async_mismatch(tcx, infcx, &errors, trait_m, impl_m, impl_sig)
|
||||||
return Err(reported);
|
{
|
||||||
|
return Err(guar);
|
||||||
|
}
|
||||||
|
|
||||||
|
let guar = infcx.err_ctxt().report_fulfillment_errors(errors);
|
||||||
|
return Err(guar);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, resolve all regions. This catches wily misuses of
|
// Finally, resolve all regions. This catches wily misuses of
|
||||||
|
@ -2217,3 +2222,47 @@ fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str {
|
||||||
ty::AssocKind::Type => "type",
|
ty::AssocKind::Type => "type",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Manually check here that `async fn foo()` wasn't matched against `fn foo()`,
|
||||||
|
/// and extract a better error if so.
|
||||||
|
fn try_report_async_mismatch<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
infcx: &InferCtxt<'tcx>,
|
||||||
|
errors: &[FulfillmentError<'tcx>],
|
||||||
|
trait_m: ty::AssocItem,
|
||||||
|
impl_m: ty::AssocItem,
|
||||||
|
impl_sig: ty::FnSig<'tcx>,
|
||||||
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
|
if !tcx.asyncness(trait_m.def_id).is_async() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let ty::Alias(ty::Projection, ty::AliasTy { def_id: async_future_def_id, .. }) =
|
||||||
|
*tcx.fn_sig(trait_m.def_id).skip_binder().skip_binder().output().kind()
|
||||||
|
else {
|
||||||
|
bug!("expected `async fn` to return an RPITIT");
|
||||||
|
};
|
||||||
|
|
||||||
|
for error in errors {
|
||||||
|
if let traits::BindingObligation(def_id, _) = *error.root_obligation.cause.code()
|
||||||
|
&& def_id == async_future_def_id
|
||||||
|
&& let Some(proj) = error.root_obligation.predicate.to_opt_poly_projection_pred()
|
||||||
|
&& let Some(proj) = proj.no_bound_vars()
|
||||||
|
&& infcx.can_eq(
|
||||||
|
error.root_obligation.param_env,
|
||||||
|
proj.term.ty().unwrap(),
|
||||||
|
impl_sig.output(),
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// FIXME: We should suggest making the fn `async`, but extracting
|
||||||
|
// the right span is a bit difficult.
|
||||||
|
return Err(tcx.sess.dcx().emit_err(MethodShouldReturnFuture {
|
||||||
|
span: tcx.def_span(impl_m.def_id),
|
||||||
|
method_name: trait_m.name,
|
||||||
|
trait_item_span: tcx.hir().span_if_local(trait_m.def_id),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
@ -1501,6 +1501,16 @@ pub struct NotSupportedDelegation<'a> {
|
||||||
pub callee_span: Span,
|
pub callee_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(hir_analysis_method_should_return_future)]
|
||||||
|
pub struct MethodShouldReturnFuture {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
pub method_name: Symbol,
|
||||||
|
#[note]
|
||||||
|
pub trait_item_span: Option<Span>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(hir_analysis_unused_generic_parameter)]
|
#[diag(hir_analysis_unused_generic_parameter)]
|
||||||
pub(crate) struct UnusedGenericParameter {
|
pub(crate) struct UnusedGenericParameter {
|
||||||
|
|
|
@ -8,7 +8,7 @@ trait MyTrait {
|
||||||
|
|
||||||
impl MyTrait for i32 {
|
impl MyTrait for i32 {
|
||||||
fn foo(&self) -> i32 {
|
fn foo(&self) -> i32 {
|
||||||
//~^ ERROR: `i32` is not a future
|
//~^ ERROR: method should be `async` or return a future, but it is synchronous
|
||||||
*self
|
*self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,14 @@
|
||||||
error[E0277]: `i32` is not a future
|
error: method should be `async` or return a future, but it is synchronous
|
||||||
--> $DIR/fn-not-async-err.rs:10:22
|
--> $DIR/fn-not-async-err.rs:10:5
|
||||||
|
|
|
|
||||||
LL | fn foo(&self) -> i32 {
|
LL | fn foo(&self) -> i32 {
|
||||||
| ^^^ `i32` is not a future
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: the trait `Future` is not implemented for `i32`
|
note: this method is `async` so it expects a future to be returned
|
||||||
= note: i32 must be a future or must implement `IntoFuture` to be awaited
|
|
||||||
note: required by a bound in `MyTrait::{opaque#0}`
|
|
||||||
--> $DIR/fn-not-async-err.rs:6:5
|
--> $DIR/fn-not-async-err.rs:6:5
|
||||||
|
|
|
|
||||||
LL | async fn foo(&self) -> i32;
|
LL | async fn foo(&self) -> i32;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `MyTrait::{opaque#0}`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0277`.
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue