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
@@ -2252,3 +2226,47 @@ fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str {
2252
2226
ty:: AssocKind :: Type => "type" ,
2253
2227
}
2254
2228
}
2229
+
2230
+ /// Manually check here that `async fn foo()` wasn't matched against `fn foo()`,
2231
+ /// and extract a better error if so.
2232
+ fn try_report_async_mismatch < ' tcx > (
2233
+ tcx : TyCtxt < ' tcx > ,
2234
+ infcx : & InferCtxt < ' tcx > ,
2235
+ errors : & [ FulfillmentError < ' tcx > ] ,
2236
+ trait_m : ty:: AssocItem ,
2237
+ impl_m : ty:: AssocItem ,
2238
+ impl_sig : ty:: FnSig < ' tcx > ,
2239
+ ) -> Result < ( ) , ErrorGuaranteed > {
2240
+ if !tcx. asyncness ( trait_m. def_id ) . is_async ( ) {
2241
+ return Ok ( ( ) ) ;
2242
+ }
2243
+
2244
+ let ty:: Alias ( ty:: Projection , ty:: AliasTy { def_id : async_future_def_id, .. } ) =
2245
+ * tcx. fn_sig ( trait_m. def_id ) . skip_binder ( ) . skip_binder ( ) . output ( ) . kind ( )
2246
+ else {
2247
+ bug ! ( "expected `async fn` to return an RPITIT" ) ;
2248
+ } ;
2249
+
2250
+ for error in errors {
2251
+ if let traits:: BindingObligation ( def_id, _) = * error. root_obligation . cause . code ( )
2252
+ && def_id == async_future_def_id
2253
+ && let Some ( proj) = error. root_obligation . predicate . to_opt_poly_projection_pred ( )
2254
+ && let Some ( proj) = proj. no_bound_vars ( )
2255
+ && infcx. can_eq (
2256
+ error. root_obligation . param_env ,
2257
+ proj. term . ty ( ) . unwrap ( ) ,
2258
+ impl_sig. output ( ) ,
2259
+ )
2260
+ {
2261
+ // FIXME: We should suggest making the fn `async`, but extracting
2262
+ // the right span is a bit difficult.
2263
+ return Err ( tcx. sess . dcx ( ) . emit_err ( MethodShouldReturnFuture {
2264
+ span : tcx. def_span ( impl_m. def_id ) ,
2265
+ method_name : trait_m. name ,
2266
+ trait_item_span : tcx. hir ( ) . span_if_local ( trait_m. def_id ) ,
2267
+ } ) ) ;
2268
+ }
2269
+ }
2270
+
2271
+ Ok ( ( ) )
2272
+ }
0 commit comments