@@ -6,12 +6,14 @@ use super::{GenericArgsCtor, LifetimeRes, ParenthesizedGenericArgs};
6
6
use super :: { ImplTraitContext , LoweringContext , ParamMode } ;
7
7
8
8
use rustc_ast:: { self as ast, * } ;
9
+ use rustc_data_structures:: sync:: Lrc ;
9
10
use rustc_hir as hir;
10
11
use rustc_hir:: def:: { DefKind , PartialRes , Res } ;
12
+ use rustc_hir:: def_id:: DefId ;
11
13
use rustc_hir:: GenericArg ;
12
14
use rustc_middle:: span_bug;
13
15
use rustc_span:: symbol:: { kw, sym, Ident } ;
14
- use rustc_span:: { BytePos , Span , DUMMY_SP } ;
16
+ use rustc_span:: { BytePos , DesugaringKind , Span , Symbol , DUMMY_SP } ;
15
17
16
18
use smallvec:: { smallvec, SmallVec } ;
17
19
@@ -24,8 +26,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
24
26
p : & Path ,
25
27
param_mode : ParamMode ,
26
28
itctx : & ImplTraitContext ,
27
- // constness of the impl/bound if this is a trait path
28
- constness : Option < ast:: BoundConstness > ,
29
+ // modifiers of the impl/bound if this is a trait path
30
+ modifiers : Option < ast:: TraitBoundModifiers > ,
29
31
) -> hir:: QPath < ' hir > {
30
32
let qself_position = qself. as_ref ( ) . map ( |q| q. position ) ;
31
33
let qself = qself. as_ref ( ) . map ( |q| self . lower_ty ( & q. ty , itctx) ) ;
@@ -35,10 +37,27 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
35
37
let base_res = partial_res. base_res ( ) ;
36
38
let unresolved_segments = partial_res. unresolved_segments ( ) ;
37
39
40
+ let mut res = self . lower_res ( base_res) ;
41
+
42
+ // When we have an `async` kw on a bound, map the trait it resolves to.
43
+ let mut bound_modifier_allowed_features = None ;
44
+ if let Some ( TraitBoundModifiers { asyncness : BoundAsyncness :: Async ( _) , .. } ) = modifiers {
45
+ if let Res :: Def ( DefKind :: Trait , def_id) = res {
46
+ if let Some ( ( async_def_id, features) ) = self . map_trait_to_async_trait ( def_id) {
47
+ res = Res :: Def ( DefKind :: Trait , async_def_id) ;
48
+ bound_modifier_allowed_features = Some ( features) ;
49
+ } else {
50
+ panic ! ( ) ;
51
+ }
52
+ } else {
53
+ panic ! ( ) ;
54
+ }
55
+ }
56
+
38
57
let path_span_lo = p. span . shrink_to_lo ( ) ;
39
58
let proj_start = p. segments . len ( ) - unresolved_segments;
40
59
let path = self . arena . alloc ( hir:: Path {
41
- res : self . lower_res ( base_res ) ,
60
+ res,
42
61
segments : self . arena . alloc_from_iter ( p. segments [ ..proj_start] . iter ( ) . enumerate ( ) . map (
43
62
|( i, segment) | {
44
63
let param_mode = match ( qself_position, param_mode) {
@@ -77,7 +96,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
77
96
parenthesized_generic_args,
78
97
itctx,
79
98
// if this is the last segment, add constness to the trait path
80
- if i == proj_start - 1 { constness } else { None } ,
99
+ if i == proj_start - 1 { modifiers. map ( |m| m. constness ) } else { None } ,
100
+ bound_modifier_allowed_features. clone ( ) ,
81
101
)
82
102
} ,
83
103
) ) ,
@@ -88,6 +108,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
88
108
) ,
89
109
} ) ;
90
110
111
+ if let Some ( bound_modifier_allowed_features) = bound_modifier_allowed_features {
112
+ path. span = self . mark_span_with_reason (
113
+ DesugaringKind :: BoundModifier ,
114
+ path. span ,
115
+ Some ( bound_modifier_allowed_features) ,
116
+ ) ;
117
+ }
118
+
91
119
// Simple case, either no projections, or only fully-qualified.
92
120
// E.g., `std::mem::size_of` or `<I as Iterator>::Item`.
93
121
if unresolved_segments == 0 {
@@ -125,6 +153,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
125
153
ParenthesizedGenericArgs :: Err ,
126
154
itctx,
127
155
None ,
156
+ None ,
128
157
) ) ;
129
158
let qpath = hir:: QPath :: TypeRelative ( ty, hir_segment) ;
130
159
@@ -166,6 +195,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
166
195
ParenthesizedGenericArgs :: Err ,
167
196
& ImplTraitContext :: Disallowed ( ImplTraitPosition :: Path ) ,
168
197
None ,
198
+ None ,
169
199
)
170
200
} ) ) ,
171
201
span : self . lower_span ( p. span ) ,
@@ -180,6 +210,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
180
210
parenthesized_generic_args : ParenthesizedGenericArgs ,
181
211
itctx : & ImplTraitContext ,
182
212
constness : Option < ast:: BoundConstness > ,
213
+ // Additional features ungated with a bound modifier like `async`.
214
+ // This is passed down to the implicit associated type binding in
215
+ // parenthesized bounds.
216
+ bound_modifier_allowed_features : Option < Lrc < [ Symbol ] > > ,
183
217
) -> hir:: PathSegment < ' hir > {
184
218
debug ! ( "path_span: {:?}, lower_path_segment(segment: {:?})" , path_span, segment) ;
185
219
let ( mut generic_args, infer_args) = if let Some ( generic_args) = segment. args . as_deref ( ) {
@@ -188,9 +222,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
188
222
self . lower_angle_bracketed_parameter_data ( data, param_mode, itctx)
189
223
}
190
224
GenericArgs :: Parenthesized ( data) => match parenthesized_generic_args {
191
- ParenthesizedGenericArgs :: ParenSugar => {
192
- self . lower_parenthesized_parameter_data ( data, itctx)
193
- }
225
+ ParenthesizedGenericArgs :: ParenSugar => self
226
+ . lower_parenthesized_parameter_data (
227
+ data,
228
+ itctx,
229
+ bound_modifier_allowed_features,
230
+ ) ,
194
231
ParenthesizedGenericArgs :: Err => {
195
232
// Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait<params...>`
196
233
let sub = if !data. inputs . is_empty ( ) {
@@ -357,6 +394,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
357
394
& mut self ,
358
395
data : & ParenthesizedArgs ,
359
396
itctx : & ImplTraitContext ,
397
+ bound_modifier_allowed_features : Option < Lrc < [ Symbol ] > > ,
360
398
) -> ( GenericArgsCtor < ' hir > , bool ) {
361
399
// Switch to `PassThrough` mode for anonymous lifetimes; this
362
400
// means that we permit things like `&Ref<T>`, where `Ref` has
@@ -392,7 +430,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
392
430
FnRetTy :: Default ( _) => self . arena . alloc ( self . ty_tup ( * span, & [ ] ) ) ,
393
431
} ;
394
432
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) ;
433
+
434
+ // If we have a bound like `async Fn() -> T`, make sure that we mark the
435
+ // `Output = T` associated type bound with the right feature gates.
436
+ let mut output_span = output_ty. span ;
437
+ if let Some ( bound_modifier_allowed_features) = bound_modifier_allowed_features {
438
+ output_span = self . mark_span_with_reason (
439
+ DesugaringKind :: BoundModifier ,
440
+ output_span,
441
+ Some ( bound_modifier_allowed_features) ,
442
+ ) ;
443
+ }
444
+ let binding = self . assoc_ty_binding ( sym:: Output , output_span, output_ty) ;
445
+
396
446
(
397
447
GenericArgsCtor {
398
448
args,
@@ -429,4 +479,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
429
479
kind,
430
480
}
431
481
}
482
+
483
+ /// When a bound is annotated with `async`, it signals to lowering that the trait
484
+ /// that the bound refers to should be mapped to the "async" flavor of the trait.
485
+ ///
486
+ /// This only needs to be done until we unify `AsyncFn` and `Fn` traits into one
487
+ /// that is generic over `async`ness, if that's ever possible, or modify the
488
+ /// lowering of `async Fn()` bounds to desugar to another trait like `LendingFn`.
489
+ fn map_trait_to_async_trait ( & self , def_id : DefId ) -> Option < ( DefId , Lrc < [ Symbol ] > ) > {
490
+ let lang_items = self . tcx . lang_items ( ) ;
491
+ if Some ( def_id) == lang_items. fn_trait ( ) {
492
+ Some ( ( lang_items. async_fn_trait ( ) ?, self . allow_async_fn_traits . clone ( ) ) )
493
+ } else if Some ( def_id) == lang_items. fn_mut_trait ( ) {
494
+ Some ( ( lang_items. async_fn_mut_trait ( ) ?, self . allow_async_fn_traits . clone ( ) ) )
495
+ } else if Some ( def_id) == lang_items. fn_once_trait ( ) {
496
+ Some ( ( lang_items. async_fn_once_trait ( ) ?, self . allow_async_fn_traits . clone ( ) ) )
497
+ } else {
498
+ None
499
+ }
500
+ }
432
501
}
0 commit comments