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