77// or type checking or some other kind of complex analysis.
88
99use std:: mem;
10+ use syntax:: print:: pprust;
1011use rustc:: lint;
1112use rustc:: session:: Session ;
13+ use rustc_data_structures:: fx:: FxHashMap ;
1214use syntax:: ast:: * ;
1315use syntax:: attr;
1416use syntax:: source_map:: Spanned ;
@@ -271,7 +273,74 @@ impl<'a> AstValidator<'a> {
271273 _ => None ,
272274 }
273275 }
276+ }
274277
278+ enum GenericPosition {
279+ Param ,
280+ Arg ,
281+ }
282+
283+ fn validate_generics_order < ' a > (
284+ handler : & errors:: Handler ,
285+ generics : impl Iterator < Item = ( ParamKindOrd , Span , Option < String > ) > ,
286+ pos : GenericPosition ,
287+ span : Span ,
288+ ) {
289+ let mut max_param: Option < ParamKindOrd > = None ;
290+ let mut out_of_order = FxHashMap :: default ( ) ;
291+ let mut param_idents = vec ! [ ] ;
292+
293+ for ( kind, span, ident) in generics {
294+ if let Some ( ident) = ident {
295+ param_idents. push ( ( kind, param_idents. len ( ) , ident) ) ;
296+ }
297+ let max_param = & mut max_param;
298+ match max_param {
299+ Some ( max_param) if * max_param > kind => {
300+ let entry = out_of_order. entry ( kind) . or_insert ( ( * max_param, vec ! [ ] ) ) ;
301+ entry. 1 . push ( span) ;
302+ }
303+ Some ( _) | None => * max_param = Some ( kind) ,
304+ } ;
305+ }
306+
307+ let mut ordered_params = "<" . to_string ( ) ;
308+ if !out_of_order. is_empty ( ) {
309+ param_idents. sort_by_key ( |& ( po, i, _) | ( po, i) ) ;
310+ let mut first = true ;
311+ for ( _, _, ident) in param_idents {
312+ if !first {
313+ ordered_params += ", " ;
314+ }
315+ ordered_params += & ident;
316+ first = false ;
317+ }
318+ }
319+ ordered_params += ">" ;
320+
321+ let pos_str = match pos {
322+ GenericPosition :: Param => "parameter" ,
323+ GenericPosition :: Arg => "argument" ,
324+ } ;
325+
326+ for ( param_ord, ( max_param, spans) ) in out_of_order {
327+ let mut err = handler. struct_span_err ( spans,
328+ & format ! (
329+ "{} {pos}s must be declared prior to {} {pos}s" ,
330+ param_ord,
331+ max_param,
332+ pos = pos_str,
333+ ) ) ;
334+ if let GenericPosition :: Param = pos {
335+ err. span_suggestion (
336+ span,
337+ & format ! ( "reorder the {}s: lifetimes, then types, then consts" , pos_str) ,
338+ ordered_params. clone ( ) ,
339+ Applicability :: MachineApplicable ,
340+ ) ;
341+ }
342+ err. emit ( ) ;
343+ }
275344}
276345
277346impl < ' a > Visitor < ' a > for AstValidator < ' a > {
@@ -412,6 +481,26 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
412481 . note ( "only trait implementations may be annotated with default" ) . emit ( ) ;
413482 }
414483 }
484+ ItemKind :: Fn ( _, header, ref generics, _) => {
485+ // We currently do not permit const generics in `const fn`, as
486+ // this is tantamount to allowing compile-time dependent typing.
487+ if header. constness . node == Constness :: Const {
488+ // Look for const generics and error if we find any.
489+ for param in & generics. params {
490+ match param. kind {
491+ GenericParamKind :: Const { .. } => {
492+ self . err_handler ( )
493+ . struct_span_err (
494+ item. span ,
495+ "const parameters are not permitted in `const fn`" ,
496+ )
497+ . emit ( ) ;
498+ }
499+ _ => { }
500+ }
501+ }
502+ }
503+ }
415504 ItemKind :: ForeignMod ( ..) => {
416505 self . invalid_visibility (
417506 & item. vis ,
@@ -508,6 +597,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
508597 match * generic_args {
509598 GenericArgs :: AngleBracketed ( ref data) => {
510599 walk_list ! ( self , visit_generic_arg, & data. args) ;
600+ validate_generics_order ( self . err_handler ( ) , data. args . iter ( ) . map ( |arg| {
601+ ( match arg {
602+ GenericArg :: Lifetime ( ..) => ParamKindOrd :: Lifetime ,
603+ GenericArg :: Type ( ..) => ParamKindOrd :: Type ,
604+ GenericArg :: Const ( ..) => ParamKindOrd :: Const ,
605+ } , arg. span ( ) , None )
606+ } ) , GenericPosition :: Arg , generic_args. span ( ) ) ;
511607 // Type bindings such as `Item=impl Debug` in `Iterator<Item=Debug>`
512608 // are allowed to contain nested `impl Trait`.
513609 self . with_impl_trait ( None , |this| {
@@ -526,34 +622,40 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
526622 }
527623
528624 fn visit_generics ( & mut self , generics : & ' a Generics ) {
529- let mut seen_non_lifetime_param = false ;
530- let mut seen_default = None ;
625+ let mut prev_ty_default = None ;
531626 for param in & generics. params {
532- match ( & param. kind , seen_non_lifetime_param) {
533- ( GenericParamKind :: Lifetime { .. } , true ) => {
627+ if let GenericParamKind :: Type { ref default, .. } = param. kind {
628+ if default. is_some ( ) {
629+ prev_ty_default = Some ( param. ident . span ) ;
630+ } else if let Some ( span) = prev_ty_default {
534631 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- }
632+ . span_err ( span, "type parameters with a default must be trailing" ) ;
633+ break ;
547634 }
548635 }
549636 }
637+
638+ validate_generics_order ( self . err_handler ( ) , generics. params . iter ( ) . map ( |param| {
639+ let span = param. ident . span ;
640+ let ident = Some ( param. ident . to_string ( ) ) ;
641+ match & param. kind {
642+ GenericParamKind :: Lifetime { .. } => ( ParamKindOrd :: Lifetime , span, ident) ,
643+ GenericParamKind :: Type { .. } => ( ParamKindOrd :: Type , span, ident) ,
644+ GenericParamKind :: Const { ref ty } => {
645+ let ty = pprust:: ty_to_string ( ty) ;
646+ ( ParamKindOrd :: Const , span, Some ( format ! ( "const {}: {}" , param. ident, ty) ) )
647+ }
648+ }
649+ } ) , GenericPosition :: Param , generics. span ) ;
650+
550651 for predicate in & generics. where_clause . predicates {
551652 if let WherePredicate :: EqPredicate ( ref predicate) = * predicate {
552653 self . err_handler ( )
553654 . span_err ( predicate. span , "equality constraints are not yet \
554655 supported in where clauses (see #20041)") ;
555656 }
556657 }
658+
557659 visit:: walk_generics ( self , generics)
558660 }
559661
0 commit comments