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 ;
@@ -74,7 +74,6 @@ fn check_method_is_structurally_compatible<'tcx>(
7474 compare_generic_param_kinds ( tcx, impl_m, trait_m, delay) ?;
7575 compare_number_of_method_arguments ( tcx, impl_m, trait_m, delay) ?;
7676 compare_synthetic_generics ( tcx, impl_m, trait_m, delay) ?;
77- compare_asyncness ( tcx, impl_m, trait_m, delay) ?;
7877 check_region_bounds_on_impl_item ( tcx, impl_m, trait_m, delay) ?;
7978 Ok ( ( ) )
8079}
@@ -414,36 +413,6 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RemapLateBound<'_, 'tcx> {
414413 }
415414}
416415
417- fn compare_asyncness < ' tcx > (
418- tcx : TyCtxt < ' tcx > ,
419- impl_m : ty:: AssocItem ,
420- trait_m : ty:: AssocItem ,
421- delay : bool ,
422- ) -> Result < ( ) , ErrorGuaranteed > {
423- if tcx. asyncness ( trait_m. def_id ) . is_async ( ) {
424- match tcx. fn_sig ( impl_m. def_id ) . skip_binder ( ) . skip_binder ( ) . output ( ) . kind ( ) {
425- ty:: Alias ( ty:: Opaque , ..) => {
426- // allow both `async fn foo()` and `fn foo() -> impl Future`
427- }
428- ty:: Error ( _) => {
429- // We don't know if it's ok, but at least it's already an error.
430- }
431- _ => {
432- return Err ( tcx
433- . dcx ( )
434- . create_err ( crate :: errors:: AsyncTraitImplShouldBeAsync {
435- span : tcx. def_span ( impl_m. def_id ) ,
436- method_name : trait_m. name ,
437- trait_item_span : tcx. hir ( ) . span_if_local ( trait_m. def_id ) ,
438- } )
439- . emit_unless ( delay) ) ;
440- }
441- } ;
442- }
443-
444- Ok ( ( ) )
445- }
446-
447416/// Given a method def-id in an impl, compare the method signature of the impl
448417/// against the trait that it's implementing. In doing so, infer the hidden types
449418/// that this method's signature provides to satisfy each return-position `impl Trait`
@@ -695,8 +664,13 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
695664 // RPITs.
696665 let errors = ocx. select_all_or_error ( ) ;
697666 if !errors. is_empty ( ) {
698- let reported = infcx. err_ctxt ( ) . report_fulfillment_errors ( errors) ;
699- 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) ;
700674 }
701675
702676 // Finally, resolve all regions. This catches wily misuses of
@@ -2248,3 +2222,47 @@ fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str {
22482222 ty:: AssocKind :: Type => "type" ,
22492223 }
22502224}
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