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 ;
@@ -74,7 +74,6 @@ fn check_method_is_structurally_compatible<'tcx>(
74
74
compare_generic_param_kinds ( tcx, impl_m, trait_m, delay) ?;
75
75
compare_number_of_method_arguments ( tcx, impl_m, trait_m, delay) ?;
76
76
compare_synthetic_generics ( tcx, impl_m, trait_m, delay) ?;
77
- compare_asyncness ( tcx, impl_m, trait_m, delay) ?;
78
77
check_region_bounds_on_impl_item ( tcx, impl_m, trait_m, delay) ?;
79
78
Ok ( ( ) )
80
79
}
@@ -414,36 +413,6 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RemapLateBound<'_, 'tcx> {
414
413
}
415
414
}
416
415
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
-
447
416
/// Given a method def-id in an impl, compare the method signature of the impl
448
417
/// against the trait that it's implementing. In doing so, infer the hidden types
449
418
/// 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>(
695
664
// RPITs.
696
665
let errors = ocx. select_all_or_error ( ) ;
697
666
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) ;
700
674
}
701
675
702
676
// Finally, resolve all regions. This catches wily misuses of
@@ -2248,3 +2222,47 @@ fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str {
2248
2222
ty:: AssocKind :: Type => "type" ,
2249
2223
}
2250
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