11use super :: potentially_plural_count;
2- use crate :: errors:: LifetimesOrBoundsMismatchOnTrait ;
2+ use crate :: errors:: { LifetimesOrBoundsMismatchOnTrait , MethodShouldReturnFuture } ;
33use hir:: def_id:: { DefId , DefIdMap , LocalDefId } ;
44use rustc_data_structures:: fx:: { FxHashMap , FxHashSet , FxIndexSet } ;
55use rustc_errors:: { codes:: * , pluralize, struct_span_code_err, Applicability , ErrorGuaranteed } ;
@@ -10,7 +10,7 @@ use rustc_hir::{GenericParamKind, ImplItemKind};
1010use rustc_infer:: infer:: outlives:: env:: OutlivesEnvironment ;
1111use rustc_infer:: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
1212use rustc_infer:: infer:: { self , InferCtxt , TyCtxtInferExt } ;
13- use rustc_infer:: traits:: util;
13+ use rustc_infer:: traits:: { util, FulfillmentError } ;
1414use rustc_middle:: ty:: error:: { ExpectedFound , TypeError } ;
1515use rustc_middle:: ty:: fold:: BottomUpFolder ;
1616use rustc_middle:: ty:: util:: ExplicitSelf ;
@@ -664,8 +664,13 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
664664 // RPITs.
665665 let errors = ocx. select_all_or_error ( ) ;
666666 if !errors. is_empty ( ) {
667- let reported = infcx. err_ctxt ( ) . report_fulfillment_errors ( errors) ;
668- return Err ( reported) ;
667+ if let Err ( guar) = try_report_async_mismatch ( tcx, infcx, & errors, trait_m, impl_m, impl_sig)
668+ {
669+ return Err ( guar) ;
670+ }
671+
672+ let guar = infcx. err_ctxt ( ) . report_fulfillment_errors ( errors) ;
673+ return Err ( guar) ;
669674 }
670675
671676 // Finally, resolve all regions. This catches wily misuses of
@@ -2217,3 +2222,47 @@ fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str {
22172222 ty:: AssocKind :: Type => "type" ,
22182223 }
22192224}
2225+
2226+ /// Manually check here that `async fn foo()` wasn't matched against `fn foo()`,
2227+ /// and extract a better error if so.
2228+ fn try_report_async_mismatch < ' tcx > (
2229+ tcx : TyCtxt < ' tcx > ,
2230+ infcx : & InferCtxt < ' tcx > ,
2231+ errors : & [ FulfillmentError < ' tcx > ] ,
2232+ trait_m : ty:: AssocItem ,
2233+ impl_m : ty:: AssocItem ,
2234+ impl_sig : ty:: FnSig < ' tcx > ,
2235+ ) -> Result < ( ) , ErrorGuaranteed > {
2236+ if !tcx. asyncness ( trait_m. def_id ) . is_async ( ) {
2237+ return Ok ( ( ) ) ;
2238+ }
2239+
2240+ let ty:: Alias ( ty:: Projection , ty:: AliasTy { def_id : async_future_def_id, .. } ) =
2241+ * tcx. fn_sig ( trait_m. def_id ) . skip_binder ( ) . skip_binder ( ) . output ( ) . kind ( )
2242+ else {
2243+ bug ! ( "expected `async fn` to return an RPITIT" ) ;
2244+ } ;
2245+
2246+ for error in errors {
2247+ if let traits:: BindingObligation ( def_id, _) = * error. root_obligation . cause . code ( )
2248+ && def_id == async_future_def_id
2249+ && let Some ( proj) = error. root_obligation . predicate . to_opt_poly_projection_pred ( )
2250+ && let Some ( proj) = proj. no_bound_vars ( )
2251+ && infcx. can_eq (
2252+ error. root_obligation . param_env ,
2253+ proj. term . ty ( ) . unwrap ( ) ,
2254+ impl_sig. output ( ) ,
2255+ )
2256+ {
2257+ // FIXME: We should suggest making the fn `async`, but extracting
2258+ // the right span is a bit difficult.
2259+ return Err ( tcx. sess . dcx ( ) . emit_err ( MethodShouldReturnFuture {
2260+ span : tcx. def_span ( impl_m. def_id ) ,
2261+ method_name : trait_m. name ,
2262+ trait_item_span : tcx. hir ( ) . span_if_local ( trait_m. def_id ) ,
2263+ } ) ) ;
2264+ }
2265+ }
2266+
2267+ Ok ( ( ) )
2268+ }
0 commit comments