3
3
//! A failed validation emits a diagnostic.
4
4
5
5
mod block;
6
-
7
- use rowan:: Direction ;
8
6
use rustc_lexer:: unescape:: { self , Mode , unescape_mixed, unescape_unicode} ;
9
7
10
8
use crate :: {
11
- AstNode , SyntaxError ,
9
+ AstNode , Direction , SyntaxError ,
12
10
SyntaxKind :: { CONST , FN , INT_NUMBER , TYPE_ALIAS } ,
13
- SyntaxNode , SyntaxToken , T , TextSize , algo,
11
+ SyntaxNode , SyntaxToken , T , TextRange , TextSize , algo,
14
12
ast:: { self , HasAttrs , HasVisibility , IsString , RangeItem } ,
15
13
match_ast,
16
14
} ;
@@ -339,27 +337,49 @@ fn validate_trait_object_fn_ptr_ret_ty(ty: ast::FnPtrType, errors: &mut Vec<Synt
339
337
}
340
338
}
341
339
342
- fn validate_trait_object_ty ( ty : ast:: DynTraitType ) -> Option < SyntaxError > {
343
- let tbl = ty. type_bound_list ( ) ?;
344
- let bounds_count = tbl. bounds ( ) . count ( ) ;
340
+ fn validate_object_ty (
341
+ bounds : impl Iterator < Item = ast:: TypeBound > ,
342
+ preceding_token : Option < SyntaxToken > ,
343
+ error_no_trait : & str ,
344
+ ty_syntax_range : TextRange ,
345
+ check_for_and_token : bool ,
346
+ ) -> Option < SyntaxError > {
347
+ let bounds: Vec < _ > = bounds. collect ( ) ;
348
+ let bounds_count = bounds. len ( ) ;
345
349
346
- match bounds_count {
347
- 0 => Some ( SyntaxError :: new (
348
- "At least one trait is required for an object type" ,
349
- ty. syntax ( ) . text_range ( ) ,
350
- ) ) ,
351
- _ if bounds_count > 1 => {
352
- let dyn_token = ty. dyn_token ( ) ?;
353
- let preceding_token =
354
- algo:: skip_trivia_token ( dyn_token. prev_token ( ) ?, Direction :: Prev ) ?;
355
-
356
- if !matches ! ( preceding_token. kind( ) , T ![ '(' ] | T ![ <] | T ![ =] ) {
357
- return Some ( SyntaxError :: new ( "ambiguous `+` in a type" , ty. syntax ( ) . text_range ( ) ) ) ;
350
+ if bounds. is_empty ( )
351
+ || bounds. iter ( ) . all ( |b| matches ! ( b. kind( ) , ast:: TypeBoundKind :: Lifetime ( _) ) )
352
+ {
353
+ return Some ( SyntaxError :: new ( error_no_trait, ty_syntax_range) ) ;
354
+ }
355
+
356
+ if bounds_count == 1 {
357
+ return None ;
358
+ }
359
+
360
+ if let Some ( preceding_token) = preceding_token {
361
+ if !matches ! ( preceding_token. kind( ) , T ![ '(' ] | T ![ <] | T ![ =] ) {
362
+ if !check_for_and_token || matches ! ( preceding_token. kind( ) , T ![ & ] ) {
363
+ return Some ( SyntaxError :: new ( "ambiguous `+` in a type" , ty_syntax_range) ) ;
358
364
}
359
- None
360
365
}
361
- _ => None ,
362
366
}
367
+
368
+ None
369
+ }
370
+
371
+ fn validate_trait_object_ty ( ty : ast:: DynTraitType ) -> Option < SyntaxError > {
372
+ let tbl = ty. type_bound_list ( ) ?;
373
+ let dyn_token = ty. dyn_token ( ) ?;
374
+ let preceding_token = algo:: skip_trivia_token ( dyn_token. prev_token ( ) ?, Direction :: Prev ) ;
375
+
376
+ validate_object_ty (
377
+ tbl. bounds ( ) ,
378
+ preceding_token,
379
+ "At least one trait is required for an object type" ,
380
+ ty. syntax ( ) . text_range ( ) ,
381
+ false ,
382
+ )
363
383
}
364
384
365
385
fn validate_impl_object_ty ( ty : ast:: ImplTraitType , errors : & mut Vec < SyntaxError > ) {
@@ -371,34 +391,19 @@ fn validate_impl_object_ty(ty: ast::ImplTraitType, errors: &mut Vec<SyntaxError>
371
391
return ;
372
392
} ;
373
393
374
- let bounds: Vec < _ > = bound_list. bounds ( ) . collect ( ) ;
375
-
376
- if bounds. is_empty ( )
377
- || bounds. iter ( ) . all ( |b| matches ! ( b. kind( ) , ast:: TypeBoundKind :: Lifetime ( _) ) )
378
- {
379
- errors. push ( SyntaxError :: new (
380
- "At least one trait must be specified" ,
381
- ty. syntax ( ) . text_range ( ) ,
382
- ) ) ;
383
- return ;
384
- }
385
-
386
- if bounds. len ( ) == 1 {
387
- return ;
388
- }
389
-
390
- let Some ( preceding_token) = ty
391
- . impl_token ( )
394
+ let impl_token = ty. impl_token ( ) ;
395
+ let preceding_token = impl_token
392
396
. and_then ( |token| token. prev_token ( ) )
393
- . and_then ( |prev| algo:: skip_trivia_token ( prev, Direction :: Prev ) )
394
- else {
395
- return ;
396
- } ;
397
-
398
- if !matches ! ( preceding_token. kind( ) , T ![ '(' ] | T ![ <] | T ![ =] )
399
- && matches ! ( preceding_token. kind( ) , T ![ & ] )
400
- {
401
- errors. push ( SyntaxError :: new ( "ambiguous `+` in a type" , ty. syntax ( ) . text_range ( ) ) ) ;
397
+ . and_then ( |prev| algo:: skip_trivia_token ( prev, Direction :: Prev ) ) ;
398
+
399
+ if let Some ( error) = validate_object_ty (
400
+ bound_list. bounds ( ) ,
401
+ preceding_token,
402
+ "At least one trait must be specified" ,
403
+ ty. syntax ( ) . text_range ( ) ,
404
+ true ,
405
+ ) {
406
+ errors. push ( error) ;
402
407
}
403
408
}
404
409
0 commit comments