@@ -6,7 +6,7 @@ use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
6
6
use rustc_error_codes:: * ;
7
7
use rustc_errors:: { pluralize, Applicability , PResult } ;
8
8
use rustc_span:: source_map:: Span ;
9
- use rustc_span:: symbol:: kw ;
9
+ use rustc_span:: symbol:: { kw , sym } ;
10
10
use syntax:: ast:: {
11
11
self , BareFnTy , FunctionRetTy , GenericParam , Ident , Lifetime , MutTy , Ty , TyKind ,
12
12
} ;
@@ -18,6 +18,24 @@ use syntax::ptr::P;
18
18
use syntax:: struct_span_err;
19
19
use syntax:: token:: { self , Token } ;
20
20
21
+ /// Any `?` or `?const` modifiers that appear at the start of a bound.
22
+ struct BoundModifiers {
23
+ /// `?Trait`.
24
+ maybe : Option < Span > ,
25
+
26
+ /// `?const Trait`.
27
+ maybe_const : Option < Span > ,
28
+ }
29
+
30
+ impl BoundModifiers {
31
+ fn trait_bound_modifier ( & self ) -> TraitBoundModifier {
32
+ match self . maybe {
33
+ Some ( _) => TraitBoundModifier :: Maybe ,
34
+ None => TraitBoundModifier :: None ,
35
+ }
36
+ }
37
+ }
38
+
21
39
/// Returns `true` if `IDENT t` can start a type -- `IDENT::a::b`, `IDENT<u8, u8>`,
22
40
/// `IDENT<<u8 as Trait>::AssocTy>`.
23
41
///
@@ -196,7 +214,9 @@ impl<'a> Parser<'a> {
196
214
lo : Span ,
197
215
parse_plus : bool ,
198
216
) -> PResult < ' a , TyKind > {
199
- let poly_trait_ref = PolyTraitRef :: new ( generic_params, path, lo. to ( self . prev_span ) ) ;
217
+ assert_ne ! ( self . token, token:: Question ) ;
218
+
219
+ let poly_trait_ref = PolyTraitRef :: new ( generic_params, path, None , lo. to ( self . prev_span ) ) ;
200
220
let mut bounds = vec ! [ GenericBound :: Trait ( poly_trait_ref, TraitBoundModifier :: None ) ] ;
201
221
if parse_plus {
202
222
self . eat_plus ( ) ; // `+`, or `+=` gets split and `+` is discarded
@@ -422,12 +442,15 @@ impl<'a> Parser<'a> {
422
442
let has_parens = self . eat ( & token:: OpenDelim ( token:: Paren ) ) ;
423
443
let inner_lo = self . token . span ;
424
444
let is_negative = self . eat ( & token:: Not ) ;
425
- let question = self . eat ( & token:: Question ) . then_some ( self . prev_span ) ;
445
+
446
+ let modifiers = self . parse_ty_bound_modifiers ( ) ;
426
447
let bound = if self . token . is_lifetime ( ) {
427
- self . parse_generic_lt_bound ( lo, inner_lo, has_parens, question) ?
448
+ self . error_lt_bound_with_modifiers ( modifiers) ;
449
+ self . parse_generic_lt_bound ( lo, inner_lo, has_parens) ?
428
450
} else {
429
- self . parse_generic_ty_bound ( lo, has_parens, question ) ?
451
+ self . parse_generic_ty_bound ( lo, has_parens, modifiers ) ?
430
452
} ;
453
+
431
454
Ok ( if is_negative { Err ( anchor_lo. to ( self . prev_span ) ) } else { Ok ( bound) } )
432
455
}
433
456
@@ -440,9 +463,7 @@ impl<'a> Parser<'a> {
440
463
lo : Span ,
441
464
inner_lo : Span ,
442
465
has_parens : bool ,
443
- question : Option < Span > ,
444
466
) -> PResult < ' a , GenericBound > {
445
- self . error_opt_out_lifetime ( question) ;
446
467
let bound = GenericBound :: Outlives ( self . expect_lifetime ( ) ) ;
447
468
if has_parens {
448
469
// FIXME(Centril): Consider not erroring here and accepting `('lt)` instead,
@@ -452,8 +473,17 @@ impl<'a> Parser<'a> {
452
473
Ok ( bound)
453
474
}
454
475
455
- fn error_opt_out_lifetime ( & self , question : Option < Span > ) {
456
- if let Some ( span) = question {
476
+ /// Emits an error if any trait bound modifiers were present.
477
+ fn error_lt_bound_with_modifiers ( & self , modifiers : BoundModifiers ) {
478
+ if let Some ( span) = modifiers. maybe_const {
479
+ self . struct_span_err (
480
+ span,
481
+ "`?const` may only modify trait bounds, not lifetime bounds" ,
482
+ )
483
+ . emit ( ) ;
484
+ }
485
+
486
+ if let Some ( span) = modifiers. maybe {
457
487
self . struct_span_err ( span, "`?` may only modify trait bounds, not lifetime bounds" )
458
488
. emit ( ) ;
459
489
}
@@ -479,25 +509,58 @@ impl<'a> Parser<'a> {
479
509
Ok ( ( ) )
480
510
}
481
511
512
+ /// Parses the modifiers that may precede a trait in a bound, e.g. `?Trait` or `?const Trait`.
513
+ ///
514
+ /// If no modifiers are present, this does not consume any tokens.
515
+ ///
516
+ /// ```
517
+ /// TY_BOUND_MODIFIERS = "?" ["const" ["?"]]
518
+ /// ```
519
+ fn parse_ty_bound_modifiers ( & mut self ) -> BoundModifiers {
520
+ if !self . eat ( & token:: Question ) {
521
+ return BoundModifiers { maybe : None , maybe_const : None } ;
522
+ }
523
+
524
+ // `? ...`
525
+ let first_question = self . prev_span ;
526
+ if !self . eat_keyword ( kw:: Const ) {
527
+ return BoundModifiers { maybe : Some ( first_question) , maybe_const : None } ;
528
+ }
529
+
530
+ // `?const ...`
531
+ let maybe_const = first_question. to ( self . prev_span ) ;
532
+ self . sess . gated_spans . gate ( sym:: const_trait_bound_opt_out, maybe_const) ;
533
+ if !self . eat ( & token:: Question ) {
534
+ return BoundModifiers { maybe : None , maybe_const : Some ( maybe_const) } ;
535
+ }
536
+
537
+ // `?const ? ...`
538
+ let second_question = self . prev_span ;
539
+ BoundModifiers { maybe : Some ( second_question) , maybe_const : Some ( maybe_const) }
540
+ }
541
+
482
542
/// Parses a type bound according to:
483
543
/// ```
484
544
/// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN)
485
- /// TY_BOUND_NOPAREN = [? ] [for<LT_PARAM_DEFS>] SIMPLE_PATH (e.g., `?for<'a: 'b> m::Trait<'a>`)
545
+ /// TY_BOUND_NOPAREN = [TY_BOUND_MODIFIERS ] [for<LT_PARAM_DEFS>] SIMPLE_PATH
486
546
/// ```
547
+ ///
548
+ /// For example, this grammar accepts `?const ?for<'a: 'b> m::Trait<'a>`.
487
549
fn parse_generic_ty_bound (
488
550
& mut self ,
489
551
lo : Span ,
490
552
has_parens : bool ,
491
- question : Option < Span > ,
553
+ modifiers : BoundModifiers ,
492
554
) -> PResult < ' a , GenericBound > {
493
555
let lifetime_defs = self . parse_late_bound_lifetime_defs ( ) ?;
494
556
let path = self . parse_path ( PathStyle :: Type ) ?;
495
557
if has_parens {
496
558
self . expect ( & token:: CloseDelim ( token:: Paren ) ) ?;
497
559
}
498
- let poly_trait = PolyTraitRef :: new ( lifetime_defs, path, lo. to ( self . prev_span ) ) ;
499
- let modifier = question. map_or ( TraitBoundModifier :: None , |_| TraitBoundModifier :: Maybe ) ;
500
- Ok ( GenericBound :: Trait ( poly_trait, modifier) )
560
+
561
+ let constness = modifiers. maybe_const . map ( |_| ast:: Constness :: NotConst ) ;
562
+ let poly_trait = PolyTraitRef :: new ( lifetime_defs, path, constness, lo. to ( self . prev_span ) ) ;
563
+ Ok ( GenericBound :: Trait ( poly_trait, modifiers. trait_bound_modifier ( ) ) )
501
564
}
502
565
503
566
/// Optionally parses `for<$generic_params>`.
0 commit comments