1
1
use crate :: ImplTraitPosition ;
2
2
3
- use super :: errors:: { GenericTypeWithParentheses , UseAngleBrackets } ;
3
+ use super :: errors:: {
4
+ AsyncBoundNotOnTrait , AsyncBoundOnlyForFnTraits , GenericTypeWithParentheses , UseAngleBrackets ,
5
+ } ;
4
6
use super :: ResolverAstLoweringExt ;
5
7
use super :: { GenericArgsCtor , LifetimeRes , ParenthesizedGenericArgs } ;
6
8
use super :: { ImplTraitContext , LoweringContext , ParamMode } ;
7
9
8
10
use rustc_ast:: { self as ast, * } ;
11
+ use rustc_data_structures:: sync:: Lrc ;
9
12
use rustc_hir as hir;
10
13
use rustc_hir:: def:: { DefKind , PartialRes , Res } ;
14
+ use rustc_hir:: def_id:: DefId ;
11
15
use rustc_hir:: GenericArg ;
12
16
use rustc_middle:: span_bug;
13
17
use rustc_span:: symbol:: { kw, sym, Ident } ;
14
- use rustc_span:: { BytePos , Span , DUMMY_SP } ;
18
+ use rustc_span:: { BytePos , DesugaringKind , Span , Symbol , DUMMY_SP } ;
15
19
16
20
use smallvec:: { smallvec, SmallVec } ;
17
21
@@ -24,8 +28,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
24
28
p : & Path ,
25
29
param_mode : ParamMode ,
26
30
itctx : & ImplTraitContext ,
27
- // constness of the impl/bound if this is a trait path
28
- constness : Option < ast:: BoundConstness > ,
31
+ // modifiers of the impl/bound if this is a trait path
32
+ modifiers : Option < ast:: TraitBoundModifiers > ,
29
33
) -> hir:: QPath < ' hir > {
30
34
let qself_position = qself. as_ref ( ) . map ( |q| q. position ) ;
31
35
let qself = qself. as_ref ( ) . map ( |q| self . lower_ty ( & q. ty , itctx) ) ;
@@ -35,10 +39,36 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
35
39
let base_res = partial_res. base_res ( ) ;
36
40
let unresolved_segments = partial_res. unresolved_segments ( ) ;
37
41
42
+ let mut res = self . lower_res ( base_res) ;
43
+
44
+ // When we have an `async` kw on a bound, map the trait it resolves to.
45
+ let mut bound_modifier_allowed_features = None ;
46
+ if let Some ( TraitBoundModifiers { asyncness : BoundAsyncness :: Async ( _) , .. } ) = modifiers {
47
+ match res {
48
+ Res :: Def ( DefKind :: Trait , def_id) => {
49
+ if let Some ( ( async_def_id, features) ) = self . map_trait_to_async_trait ( def_id) {
50
+ res = Res :: Def ( DefKind :: Trait , async_def_id) ;
51
+ bound_modifier_allowed_features = Some ( features) ;
52
+ } else {
53
+ self . dcx ( ) . emit_err ( AsyncBoundOnlyForFnTraits { span : p. span } ) ;
54
+ }
55
+ }
56
+ Res :: Err => {
57
+ // No additional error.
58
+ }
59
+ _ => {
60
+ // This error isn't actually emitted AFAICT, but it's best to keep
61
+ // it around in case the resolver doesn't always check the defkind
62
+ // of an item or something.
63
+ self . dcx ( ) . emit_err ( AsyncBoundNotOnTrait { span : p. span , descr : res. descr ( ) } ) ;
64
+ }
65
+ }
66
+ }
67
+
38
68
let path_span_lo = p. span . shrink_to_lo ( ) ;
39
69
let proj_start = p. segments . len ( ) - unresolved_segments;
40
70
let path = self . arena . alloc ( hir:: Path {
41
- res : self . lower_res ( base_res ) ,
71
+ res,
42
72
segments : self . arena . alloc_from_iter ( p. segments [ ..proj_start] . iter ( ) . enumerate ( ) . map (
43
73
|( i, segment) | {
44
74
let param_mode = match ( qself_position, param_mode) {
@@ -77,7 +107,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
77
107
parenthesized_generic_args,
78
108
itctx,
79
109
// if this is the last segment, add constness to the trait path
80
- if i == proj_start - 1 { constness } else { None } ,
110
+ if i == proj_start - 1 { modifiers. map ( |m| m. constness ) } else { None } ,
111
+ bound_modifier_allowed_features. clone ( ) ,
81
112
)
82
113
} ,
83
114
) ) ,
@@ -88,6 +119,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
88
119
) ,
89
120
} ) ;
90
121
122
+ if let Some ( bound_modifier_allowed_features) = bound_modifier_allowed_features {
123
+ path. span = self . mark_span_with_reason (
124
+ DesugaringKind :: BoundModifier ,
125
+ path. span ,
126
+ Some ( bound_modifier_allowed_features) ,
127
+ ) ;
128
+ }
129
+
91
130
// Simple case, either no projections, or only fully-qualified.
92
131
// E.g., `std::mem::size_of` or `<I as Iterator>::Item`.
93
132
if unresolved_segments == 0 {
@@ -125,6 +164,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
125
164
ParenthesizedGenericArgs :: Err ,
126
165
itctx,
127
166
None ,
167
+ None ,
128
168
) ) ;
129
169
let qpath = hir:: QPath :: TypeRelative ( ty, hir_segment) ;
130
170
@@ -166,6 +206,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
166
206
ParenthesizedGenericArgs :: Err ,
167
207
& ImplTraitContext :: Disallowed ( ImplTraitPosition :: Path ) ,
168
208
None ,
209
+ None ,
169
210
)
170
211
} ) ) ,
171
212
span : self . lower_span ( p. span ) ,
@@ -180,6 +221,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
180
221
parenthesized_generic_args : ParenthesizedGenericArgs ,
181
222
itctx : & ImplTraitContext ,
182
223
constness : Option < ast:: BoundConstness > ,
224
+ // Additional features ungated with a bound modifier like `async`.
225
+ // This is passed down to the implicit associated type binding in
226
+ // parenthesized bounds.
227
+ bound_modifier_allowed_features : Option < Lrc < [ Symbol ] > > ,
183
228
) -> hir:: PathSegment < ' hir > {
184
229
debug ! ( "path_span: {:?}, lower_path_segment(segment: {:?})" , path_span, segment) ;
185
230
let ( mut generic_args, infer_args) = if let Some ( generic_args) = segment. args . as_deref ( ) {
@@ -188,9 +233,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
188
233
self . lower_angle_bracketed_parameter_data ( data, param_mode, itctx)
189
234
}
190
235
GenericArgs :: Parenthesized ( data) => match parenthesized_generic_args {
191
- ParenthesizedGenericArgs :: ParenSugar => {
192
- self . lower_parenthesized_parameter_data ( data, itctx)
193
- }
236
+ ParenthesizedGenericArgs :: ParenSugar => self
237
+ . lower_parenthesized_parameter_data (
238
+ data,
239
+ itctx,
240
+ bound_modifier_allowed_features,
241
+ ) ,
194
242
ParenthesizedGenericArgs :: Err => {
195
243
// Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait<params...>`
196
244
let sub = if !data. inputs . is_empty ( ) {
@@ -357,6 +405,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
357
405
& mut self ,
358
406
data : & ParenthesizedArgs ,
359
407
itctx : & ImplTraitContext ,
408
+ bound_modifier_allowed_features : Option < Lrc < [ Symbol ] > > ,
360
409
) -> ( GenericArgsCtor < ' hir > , bool ) {
361
410
// Switch to `PassThrough` mode for anonymous lifetimes; this
362
411
// means that we permit things like `&Ref<T>`, where `Ref` has
@@ -392,7 +441,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
392
441
FnRetTy :: Default ( _) => self . arena . alloc ( self . ty_tup ( * span, & [ ] ) ) ,
393
442
} ;
394
443
let args = smallvec ! [ GenericArg :: Type ( self . arena. alloc( self . ty_tup( * inputs_span, inputs) ) ) ] ;
395
- let binding = self . assoc_ty_binding ( sym:: Output , output_ty. span , output_ty) ;
444
+
445
+ // If we have a bound like `async Fn() -> T`, make sure that we mark the
446
+ // `Output = T` associated type bound with the right feature gates.
447
+ let mut output_span = output_ty. span ;
448
+ if let Some ( bound_modifier_allowed_features) = bound_modifier_allowed_features {
449
+ output_span = self . mark_span_with_reason (
450
+ DesugaringKind :: BoundModifier ,
451
+ output_span,
452
+ Some ( bound_modifier_allowed_features) ,
453
+ ) ;
454
+ }
455
+ let binding = self . assoc_ty_binding ( sym:: Output , output_span, output_ty) ;
456
+
396
457
(
397
458
GenericArgsCtor {
398
459
args,
@@ -429,4 +490,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
429
490
kind,
430
491
}
431
492
}
493
+
494
+ /// When a bound is annotated with `async`, it signals to lowering that the trait
495
+ /// that the bound refers to should be mapped to the "async" flavor of the trait.
496
+ ///
497
+ /// This only needs to be done until we unify `AsyncFn` and `Fn` traits into one
498
+ /// that is generic over `async`ness, if that's ever possible, or modify the
499
+ /// lowering of `async Fn()` bounds to desugar to another trait like `LendingFn`.
500
+ fn map_trait_to_async_trait ( & self , def_id : DefId ) -> Option < ( DefId , Lrc < [ Symbol ] > ) > {
501
+ let lang_items = self . tcx . lang_items ( ) ;
502
+ if Some ( def_id) == lang_items. fn_trait ( ) {
503
+ Some ( ( lang_items. async_fn_trait ( ) ?, self . allow_async_fn_traits . clone ( ) ) )
504
+ } else if Some ( def_id) == lang_items. fn_mut_trait ( ) {
505
+ Some ( ( lang_items. async_fn_mut_trait ( ) ?, self . allow_async_fn_traits . clone ( ) ) )
506
+ } else if Some ( def_id) == lang_items. fn_once_trait ( ) {
507
+ Some ( ( lang_items. async_fn_once_trait ( ) ?, self . allow_async_fn_traits . clone ( ) ) )
508
+ } else {
509
+ None
510
+ }
511
+ }
432
512
}
0 commit comments