9
9
use std:: mem;
10
10
use rustc:: lint;
11
11
use rustc:: session:: Session ;
12
+ use rustc_data_structures:: fx:: FxHashMap ;
12
13
use syntax:: ast:: * ;
13
14
use syntax:: attr;
14
15
use syntax:: source_map:: Spanned ;
@@ -271,7 +272,74 @@ impl<'a> AstValidator<'a> {
271
272
_ => None ,
272
273
}
273
274
}
275
+ }
274
276
277
+ enum GenericPosition {
278
+ Param ,
279
+ Arg ,
280
+ }
281
+
282
+ fn validate_generics_order < ' a > (
283
+ handler : & errors:: Handler ,
284
+ generics : impl Iterator < Item = ( ParamKindOrd , Span , Option < Ident > ) > ,
285
+ pos : GenericPosition ,
286
+ span : Span ,
287
+ ) {
288
+ let mut max_param: Option < ParamKindOrd > = None ;
289
+ let mut out_of_order = FxHashMap :: default ( ) ;
290
+ let mut param_idents = vec ! [ ] ;
291
+
292
+ for ( kind, span, ident) in generics {
293
+ if let Some ( ident) = ident {
294
+ param_idents. push ( ( kind, param_idents. len ( ) , ident) ) ;
295
+ }
296
+ let max_param = & mut max_param;
297
+ match max_param {
298
+ Some ( max_param) if * max_param > kind => {
299
+ let entry = out_of_order. entry ( kind) . or_insert ( ( * max_param, vec ! [ ] ) ) ;
300
+ entry. 1 . push ( span) ;
301
+ }
302
+ Some ( _) | None => * max_param = Some ( kind) ,
303
+ } ;
304
+ }
305
+
306
+ let mut ordered_params = "<" . to_string ( ) ;
307
+ if !out_of_order. is_empty ( ) {
308
+ param_idents. sort_by_key ( |& ( po, i, _) | ( po, i) ) ;
309
+ let mut first = true ;
310
+ for ( _, _, ident) in param_idents {
311
+ if !first {
312
+ ordered_params += ", " ;
313
+ }
314
+ ordered_params += & ident. as_str ( ) ;
315
+ first = false ;
316
+ }
317
+ }
318
+ ordered_params += ">" ;
319
+
320
+ let pos_str = match pos {
321
+ GenericPosition :: Param => "parameter" ,
322
+ GenericPosition :: Arg => "argument" ,
323
+ } ;
324
+
325
+ for ( param_ord, ( max_param, spans) ) in out_of_order {
326
+ let mut err = handler. struct_span_err ( spans,
327
+ & format ! (
328
+ "{} {pos}s must be declared prior to {} {pos}s" ,
329
+ param_ord,
330
+ max_param,
331
+ pos = pos_str,
332
+ ) ) ;
333
+ if let GenericPosition :: Param = pos {
334
+ err. span_suggestion (
335
+ span,
336
+ & format ! ( "reorder the {}s: lifetimes, then types, then consts" , pos_str) ,
337
+ ordered_params. clone ( ) ,
338
+ Applicability :: MachineApplicable ,
339
+ ) ;
340
+ }
341
+ err. emit ( ) ;
342
+ }
275
343
}
276
344
277
345
impl < ' a > Visitor < ' a > for AstValidator < ' a > {
@@ -412,6 +480,26 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
412
480
. note ( "only trait implementations may be annotated with default" ) . emit ( ) ;
413
481
}
414
482
}
483
+ ItemKind :: Fn ( _, header, ref generics, _) => {
484
+ // We currently do not permit const generics in `const fn`, as
485
+ // this is tantamount to allowing compile-time dependent typing.
486
+ if header. constness . node == Constness :: Const {
487
+ // Look for const generics and error if we find any.
488
+ for param in & generics. params {
489
+ match param. kind {
490
+ GenericParamKind :: Const { .. } => {
491
+ self . err_handler ( )
492
+ . struct_span_err (
493
+ item. span ,
494
+ "const parameters are not permitted in `const fn`" ,
495
+ )
496
+ . emit ( ) ;
497
+ }
498
+ _ => { }
499
+ }
500
+ }
501
+ }
502
+ }
415
503
ItemKind :: ForeignMod ( ..) => {
416
504
self . invalid_visibility (
417
505
& item. vis ,
@@ -508,6 +596,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
508
596
match * generic_args {
509
597
GenericArgs :: AngleBracketed ( ref data) => {
510
598
walk_list ! ( self , visit_generic_arg, & data. args) ;
599
+ validate_generics_order ( self . err_handler ( ) , data. args . iter ( ) . map ( |arg| {
600
+ ( match arg {
601
+ GenericArg :: Lifetime ( ..) => ParamKindOrd :: Lifetime ,
602
+ GenericArg :: Type ( ..) => ParamKindOrd :: Type ,
603
+ GenericArg :: Const ( ..) => ParamKindOrd :: Const ,
604
+ } , arg. span ( ) , None )
605
+ } ) , GenericPosition :: Arg , generic_args. span ( ) ) ;
511
606
// Type bindings such as `Item=impl Debug` in `Iterator<Item=Debug>`
512
607
// are allowed to contain nested `impl Trait`.
513
608
self . with_impl_trait ( None , |this| {
@@ -526,34 +621,35 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
526
621
}
527
622
528
623
fn visit_generics ( & mut self , generics : & ' a Generics ) {
529
- let mut seen_non_lifetime_param = false ;
530
- let mut seen_default = None ;
624
+ let mut prev_ty_default = None ;
531
625
for param in & generics. params {
532
- match ( & param. kind , seen_non_lifetime_param) {
533
- ( GenericParamKind :: Lifetime { .. } , true ) => {
626
+ if let GenericParamKind :: Type { ref default, .. } = param. kind {
627
+ if default. is_some ( ) {
628
+ prev_ty_default = Some ( param. ident . span ) ;
629
+ } else if let Some ( span) = prev_ty_default {
534
630
self . err_handler ( )
535
- . span_err ( param. ident . span , "lifetime parameters must be leading" ) ;
536
- } ,
537
- ( GenericParamKind :: Lifetime { .. } , false ) => { }
538
- ( GenericParamKind :: Type { ref default, .. } , _) => {
539
- seen_non_lifetime_param = true ;
540
- if default. is_some ( ) {
541
- seen_default = Some ( param. ident . span ) ;
542
- } else if let Some ( span) = seen_default {
543
- self . err_handler ( )
544
- . span_err ( span, "type parameters with a default must be trailing" ) ;
545
- break ;
546
- }
631
+ . span_err ( span, "type parameters with a default must be trailing" ) ;
632
+ break ;
547
633
}
548
634
}
549
635
}
636
+
637
+ validate_generics_order ( self . err_handler ( ) , generics. params . iter ( ) . map ( |param| {
638
+ ( match param. kind {
639
+ GenericParamKind :: Lifetime { .. } => ParamKindOrd :: Lifetime ,
640
+ GenericParamKind :: Type { .. } => ParamKindOrd :: Type ,
641
+ GenericParamKind :: Const { .. } => ParamKindOrd :: Const ,
642
+ } , param. ident . span , Some ( param. ident ) )
643
+ } ) , GenericPosition :: Param , generics. span ) ;
644
+
550
645
for predicate in & generics. where_clause . predicates {
551
646
if let WherePredicate :: EqPredicate ( ref predicate) = * predicate {
552
647
self . err_handler ( )
553
648
. span_err ( predicate. span , "equality constraints are not yet \
554
649
supported in where clauses (see #20041)") ;
555
650
}
556
651
}
652
+
557
653
visit:: walk_generics ( self , generics)
558
654
}
559
655
0 commit comments