@@ -5,9 +5,10 @@ use core::fmt;
5
5
use std:: fmt:: Write ;
6
6
7
7
use hir_expand:: {
8
+ ast_id_map:: FileAstId ,
8
9
db:: ExpandDatabase ,
9
10
name:: { AsName , Name } ,
10
- AstId ,
11
+ AstId , InFile ,
11
12
} ;
12
13
use intern:: Interned ;
13
14
use syntax:: ast:: { self , HasName } ;
@@ -118,7 +119,7 @@ pub enum TypeRef {
118
119
Reference ( Box < TypeRef > , Option < LifetimeRef > , Mutability ) ,
119
120
// FIXME: for full const generics, the latter element (length) here is going to have to be an
120
121
// expression that is further lowered later in hir_ty.
121
- Array ( Box < TypeRef > , ConstRefOrPath ) ,
122
+ Array ( Box < TypeRef > , ConstRef ) ,
122
123
Slice ( Box < TypeRef > ) ,
123
124
/// A fn pointer. Last element of the vector is the return type.
124
125
Fn ( Vec < ( Option < Name > , TypeRef ) > , bool /*varargs*/ , bool /*is_unsafe*/ ) ,
@@ -190,7 +191,7 @@ impl TypeRef {
190
191
// `hir_def::body::lower` to lower this into an `Expr` and then evaluate it at the
191
192
// `hir_ty` level, which would allow knowing the type of:
192
193
// let v: [u8; 2 + 2] = [0u8; 4];
193
- let len = ConstRefOrPath :: from_expr_opt ( inner. expr ( ) ) ;
194
+ let len = ConstRef :: from_expr_opt ( ctx , inner. expr ( ) ) ;
194
195
TypeRef :: Array ( Box :: new ( TypeRef :: from_ast_opt ( ctx, inner. ty ( ) ) ) , len)
195
196
}
196
197
ast:: Type :: SliceType ( inner) => {
@@ -380,73 +381,84 @@ impl TypeBound {
380
381
}
381
382
382
383
#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
383
- pub enum ConstRefOrPath {
384
- Scalar ( ConstRef ) ,
384
+ pub enum ConstRef {
385
+ Scalar ( ConcreteConstRef ) ,
385
386
Path ( Name ) ,
387
+ Complex ( InFile < FileAstId < ast:: Expr > > ) ,
386
388
}
387
389
388
- impl ConstRefOrPath {
389
- pub ( crate ) fn from_expr_opt ( expr : Option < ast:: Expr > ) -> Self {
390
+ impl ConstRef {
391
+ pub ( crate ) fn from_expr_opt ( lower_ctx : & LowerCtx < ' _ > , expr : Option < ast:: Expr > ) -> Self {
390
392
match expr {
391
- Some ( x) => Self :: from_expr ( x) ,
392
- None => Self :: Scalar ( ConstRef :: Unknown ) ,
393
+ Some ( x) => {
394
+ let ast_id = lower_ctx. ast_id ( & x) ;
395
+ Self :: from_expr ( x, ast_id)
396
+ }
397
+ None => Self :: Scalar ( ConcreteConstRef :: Unknown ) ,
393
398
}
394
399
}
395
400
396
401
pub fn display < ' a > ( & ' a self , db : & ' a dyn ExpandDatabase ) -> impl fmt:: Display + ' a {
397
- struct Display < ' a > ( & ' a dyn ExpandDatabase , & ' a ConstRefOrPath ) ;
402
+ struct Display < ' a > ( & ' a dyn ExpandDatabase , & ' a ConstRef ) ;
398
403
impl fmt:: Display for Display < ' _ > {
399
404
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
400
405
match self . 1 {
401
- ConstRefOrPath :: Scalar ( s) => s. fmt ( f) ,
402
- ConstRefOrPath :: Path ( n) => n. display ( self . 0 ) . fmt ( f) ,
406
+ ConstRef :: Scalar ( s) => s. fmt ( f) ,
407
+ ConstRef :: Path ( n) => n. display ( self . 0 ) . fmt ( f) ,
408
+ ConstRef :: Complex ( _) => f. write_str ( "{const}" ) ,
403
409
}
404
410
}
405
411
}
406
412
Display ( db, self )
407
413
}
408
414
409
- // FIXME: as per the comments on `TypeRef::Array`, this evaluation should not happen at this
410
- // parse stage.
411
- fn from_expr ( expr : ast:: Expr ) -> Self {
415
+ // We special case literals and single identifiers, to speed up things.
416
+ fn from_expr ( expr : ast:: Expr , ast_id : Option < InFile < FileAstId < ast:: Expr > > > ) -> Self {
417
+ fn is_path_ident ( p : & ast:: PathExpr ) -> bool {
418
+ let Some ( path) = p. path ( ) else {
419
+ return false ;
420
+ } ;
421
+ if path. coloncolon_token ( ) . is_some ( ) {
422
+ return false ;
423
+ }
424
+ if let Some ( s) = path. segment ( ) {
425
+ if s. coloncolon_token ( ) . is_some ( ) || s. generic_arg_list ( ) . is_some ( ) {
426
+ return false ;
427
+ }
428
+ }
429
+ true
430
+ }
412
431
match expr {
413
- ast:: Expr :: PathExpr ( p) => {
432
+ ast:: Expr :: PathExpr ( p) if is_path_ident ( & p ) => {
414
433
match p. path ( ) . and_then ( |x| x. segment ( ) ) . and_then ( |x| x. name_ref ( ) ) {
415
434
Some ( x) => Self :: Path ( x. as_name ( ) ) ,
416
- None => Self :: Scalar ( ConstRef :: Unknown ) ,
435
+ None => Self :: Scalar ( ConcreteConstRef :: Unknown ) ,
417
436
}
418
437
}
419
- ast:: Expr :: PrefixExpr ( prefix_expr) => match prefix_expr. op_kind ( ) {
420
- Some ( ast:: UnaryOp :: Neg ) => {
421
- let unsigned = Self :: from_expr_opt ( prefix_expr. expr ( ) ) ;
422
- // Add sign
423
- match unsigned {
424
- Self :: Scalar ( ConstRef :: UInt ( num) ) => {
425
- Self :: Scalar ( ConstRef :: Int ( -( num as i128 ) ) )
426
- }
427
- other => other,
428
- }
429
- }
430
- _ => Self :: from_expr_opt ( prefix_expr. expr ( ) ) ,
431
- } ,
432
438
ast:: Expr :: Literal ( literal) => Self :: Scalar ( match literal. kind ( ) {
433
439
ast:: LiteralKind :: IntNumber ( num) => {
434
- num. value ( ) . map ( ConstRef :: UInt ) . unwrap_or ( ConstRef :: Unknown )
440
+ num. value ( ) . map ( ConcreteConstRef :: UInt ) . unwrap_or ( ConcreteConstRef :: Unknown )
435
441
}
436
442
ast:: LiteralKind :: Char ( c) => {
437
- c. value ( ) . map ( ConstRef :: Char ) . unwrap_or ( ConstRef :: Unknown )
443
+ c. value ( ) . map ( ConcreteConstRef :: Char ) . unwrap_or ( ConcreteConstRef :: Unknown )
438
444
}
439
- ast:: LiteralKind :: Bool ( f) => ConstRef :: Bool ( f) ,
440
- _ => ConstRef :: Unknown ,
445
+ ast:: LiteralKind :: Bool ( f) => ConcreteConstRef :: Bool ( f) ,
446
+ _ => ConcreteConstRef :: Unknown ,
441
447
} ) ,
442
- _ => Self :: Scalar ( ConstRef :: Unknown ) ,
448
+ _ => {
449
+ if let Some ( ast_id) = ast_id {
450
+ Self :: Complex ( ast_id)
451
+ } else {
452
+ Self :: Scalar ( ConcreteConstRef :: Unknown )
453
+ }
454
+ }
443
455
}
444
456
}
445
457
}
446
458
447
459
/// A concrete constant value
448
460
#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
449
- pub enum ConstRef {
461
+ pub enum ConcreteConstRef {
450
462
Int ( i128 ) ,
451
463
UInt ( u128 ) ,
452
464
Bool ( bool ) ,
@@ -460,18 +472,20 @@ pub enum ConstRef {
460
472
Unknown ,
461
473
}
462
474
463
- impl ConstRef {
475
+ impl ConcreteConstRef {
464
476
pub fn builtin_type ( & self ) -> BuiltinType {
465
477
match self {
466
- ConstRef :: UInt ( _) | ConstRef :: Unknown => BuiltinType :: Uint ( BuiltinUint :: U128 ) ,
467
- ConstRef :: Int ( _) => BuiltinType :: Int ( BuiltinInt :: I128 ) ,
468
- ConstRef :: Char ( _) => BuiltinType :: Char ,
469
- ConstRef :: Bool ( _) => BuiltinType :: Bool ,
478
+ ConcreteConstRef :: UInt ( _) | ConcreteConstRef :: Unknown => {
479
+ BuiltinType :: Uint ( BuiltinUint :: U128 )
480
+ }
481
+ ConcreteConstRef :: Int ( _) => BuiltinType :: Int ( BuiltinInt :: I128 ) ,
482
+ ConcreteConstRef :: Char ( _) => BuiltinType :: Char ,
483
+ ConcreteConstRef :: Bool ( _) => BuiltinType :: Bool ,
470
484
}
471
485
}
472
486
}
473
487
474
- impl From < Literal > for ConstRef {
488
+ impl From < Literal > for ConcreteConstRef {
475
489
fn from ( literal : Literal ) -> Self {
476
490
match literal {
477
491
Literal :: Char ( c) => Self :: Char ( c) ,
@@ -483,14 +497,14 @@ impl From<Literal> for ConstRef {
483
497
}
484
498
}
485
499
486
- impl std:: fmt:: Display for ConstRef {
500
+ impl std:: fmt:: Display for ConcreteConstRef {
487
501
fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> Result < ( ) , std:: fmt:: Error > {
488
502
match self {
489
- ConstRef :: Int ( num) => num. fmt ( f) ,
490
- ConstRef :: UInt ( num) => num. fmt ( f) ,
491
- ConstRef :: Bool ( flag) => flag. fmt ( f) ,
492
- ConstRef :: Char ( c) => write ! ( f, "'{c}'" ) ,
493
- ConstRef :: Unknown => f. write_char ( '_' ) ,
503
+ ConcreteConstRef :: Int ( num) => num. fmt ( f) ,
504
+ ConcreteConstRef :: UInt ( num) => num. fmt ( f) ,
505
+ ConcreteConstRef :: Bool ( flag) => flag. fmt ( f) ,
506
+ ConcreteConstRef :: Char ( c) => write ! ( f, "'{c}'" ) ,
507
+ ConcreteConstRef :: Unknown => f. write_char ( '_' ) ,
494
508
}
495
509
}
496
510
}
0 commit comments