1
1
use super :: potentially_plural_count;
2
- use crate :: errors:: LifetimesOrBoundsMismatchOnTrait ;
2
+ use crate :: errors:: { LifetimesOrBoundsMismatchOnTrait , MethodShouldReturnFuture } ;
3
3
use hir:: def_id:: { DefId , DefIdMap , LocalDefId } ;
4
4
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet , FxIndexSet } ;
5
5
use rustc_errors:: { codes:: * , pluralize, struct_span_code_err, Applicability , ErrorGuaranteed } ;
@@ -10,7 +10,7 @@ use rustc_hir::{GenericParamKind, ImplItemKind};
10
10
use rustc_infer:: infer:: outlives:: env:: OutlivesEnvironment ;
11
11
use rustc_infer:: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
12
12
use rustc_infer:: infer:: { self , InferCtxt , TyCtxtInferExt } ;
13
- use rustc_infer:: traits:: util;
13
+ use rustc_infer:: traits:: { util, FulfillmentError } ;
14
14
use rustc_middle:: ty:: error:: { ExpectedFound , TypeError } ;
15
15
use rustc_middle:: ty:: fold:: BottomUpFolder ;
16
16
use rustc_middle:: ty:: util:: ExplicitSelf ;
@@ -664,8 +664,13 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
664
664
// RPITs.
665
665
let errors = ocx. select_all_or_error ( ) ;
666
666
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) ;
669
674
}
670
675
671
676
// Finally, resolve all regions. This catches wily misuses of
@@ -2217,3 +2222,47 @@ fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str {
2217
2222
ty:: AssocKind :: Type => "type" ,
2218
2223
}
2219
2224
}
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