1
1
use std:: assert_matches:: assert_matches;
2
+ use std:: ops:: ControlFlow ;
2
3
3
4
use rustc_ast:: ptr:: P as AstP ;
4
5
use rustc_ast:: * ;
6
+ use rustc_ast_pretty:: pprust:: expr_to_string;
5
7
use rustc_data_structures:: stack:: ensure_sufficient_stack;
6
8
use rustc_data_structures:: sync:: Lrc ;
7
9
use rustc_hir as hir;
@@ -13,6 +15,7 @@ use rustc_span::source_map::{Spanned, respan};
13
15
use rustc_span:: symbol:: { Ident , Symbol , kw, sym} ;
14
16
use rustc_span:: { DUMMY_SP , DesugaringKind , Span } ;
15
17
use thin_vec:: { ThinVec , thin_vec} ;
18
+ use visit:: { Visitor , walk_expr} ;
16
19
17
20
use super :: errors:: {
18
21
AsyncCoroutinesNotSupported , AwaitOnlyInAsyncFnAndBlocks , BaseExpressionDoubleDot ,
@@ -23,9 +26,32 @@ use super::errors::{
23
26
use super :: {
24
27
GenericArgsMode , ImplTraitContext , LoweringContext , ParamMode , ResolverAstLoweringExt ,
25
28
} ;
26
- use crate :: errors:: YieldInClosure ;
29
+ use crate :: errors:: { InvalidLegacyConstGenericArg , UseConstGenericArg , YieldInClosure } ;
27
30
use crate :: { AllowReturnTypeNotation , FnDeclKind , ImplTraitPosition , fluent_generated} ;
28
31
32
+ struct WillCreateDefIdsVisitor { }
33
+
34
+ impl < ' v > rustc_ast:: visit:: Visitor < ' v > for WillCreateDefIdsVisitor {
35
+ type Result = ControlFlow < Span > ;
36
+
37
+ fn visit_anon_const ( & mut self , c : & ' v AnonConst ) -> Self :: Result {
38
+ ControlFlow :: Break ( c. value . span )
39
+ }
40
+
41
+ fn visit_item ( & mut self , item : & ' v Item ) -> Self :: Result {
42
+ ControlFlow :: Break ( item. span )
43
+ }
44
+
45
+ fn visit_expr ( & mut self , ex : & ' v Expr ) -> Self :: Result {
46
+ match ex. kind {
47
+ ExprKind :: Gen ( ..) | ExprKind :: ConstBlock ( ..) | ExprKind :: Closure ( ..) => {
48
+ ControlFlow :: Break ( ex. span )
49
+ }
50
+ _ => walk_expr ( self , ex) ,
51
+ }
52
+ }
53
+ }
54
+
29
55
impl < ' hir > LoweringContext < ' _ , ' hir > {
30
56
fn lower_exprs ( & mut self , exprs : & [ AstP < Expr > ] ) -> & ' hir [ hir:: Expr < ' hir > ] {
31
57
self . arena . alloc_from_iter ( exprs. iter ( ) . map ( |x| self . lower_expr_mut ( x) ) )
@@ -396,10 +422,23 @@ impl<'hir> LoweringContext<'_, 'hir> {
396
422
unreachable ! ( ) ;
397
423
} ;
398
424
425
+ // Collect const and non-const args for emitting replacement suggestions in case of invalid
426
+ // expressions being used as legacy const generic args.
427
+ let mut const_args = vec ! [ ] ;
428
+ let mut other_args = vec ! [ ] ;
429
+ for ( idx, arg) in args. iter ( ) . enumerate ( ) {
430
+ if legacy_args_idx. contains ( & idx) {
431
+ const_args. push ( format ! ( "{{ {} }}" , expr_to_string( arg) ) ) ;
432
+ } else {
433
+ other_args. push ( expr_to_string ( arg) ) ;
434
+ }
435
+ }
436
+ let mut error = None ;
437
+
399
438
// Split the arguments into const generics and normal arguments
400
439
let mut real_args = vec ! [ ] ;
401
440
let mut generic_args = ThinVec :: new ( ) ;
402
- for ( idx, arg) in args. into_iter ( ) . enumerate ( ) {
441
+ for ( idx, arg) in args. iter ( ) . cloned ( ) . enumerate ( ) {
403
442
if legacy_args_idx. contains ( & idx) {
404
443
let parent_def_id = self . current_def_id_parent ;
405
444
let node_id = self . next_node_id ( ) ;
@@ -410,7 +449,33 @@ impl<'hir> LoweringContext<'_, 'hir> {
410
449
self . create_def ( parent_def_id, node_id, kw:: Empty , DefKind :: AnonConst , f. span ) ;
411
450
}
412
451
413
- let anon_const = AnonConst { id : node_id, value : arg } ;
452
+ let mut visitor = WillCreateDefIdsVisitor { } ;
453
+ let const_value = if let ControlFlow :: Break ( span) = visitor. visit_expr ( & arg) {
454
+ if error. is_none ( ) {
455
+ let suggestion = UseConstGenericArg {
456
+ end_of_fn : f. span . shrink_to_hi ( ) ,
457
+ const_args : const_args. join ( ", " ) ,
458
+ other_args : other_args. join ( ", " ) ,
459
+ call_args : args[ 0 ] . span . to ( args. last ( ) . unwrap ( ) . span ) ,
460
+ } ;
461
+ error = Some (
462
+ self . tcx
463
+ . dcx ( )
464
+ . emit_err ( InvalidLegacyConstGenericArg { span, suggestion } ) ,
465
+ ) ;
466
+ }
467
+ AstP ( Expr {
468
+ id : self . next_node_id ( ) ,
469
+ kind : ExprKind :: Err ( error. unwrap ( ) ) ,
470
+ span : f. span ,
471
+ attrs : [ ] . into ( ) ,
472
+ tokens : None ,
473
+ } )
474
+ } else {
475
+ arg
476
+ } ;
477
+
478
+ let anon_const = AnonConst { id : node_id, value : const_value } ;
414
479
generic_args. push ( AngleBracketedArg :: Arg ( GenericArg :: Const ( anon_const) ) ) ;
415
480
} else {
416
481
real_args. push ( arg) ;
0 commit comments