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