@@ -118,7 +118,7 @@ pub enum TypeRef {
118118 Reference ( Box < TypeRef > , Option < LifetimeRef > , Mutability ) ,
119119 // FIXME: for full const generics, the latter element (length) here is going to have to be an
120120 // expression that is further lowered later in hir_ty.
121- Array ( Box < TypeRef > , ConstRefOrPath ) ,
121+ Array ( Box < TypeRef > , ConstRef ) ,
122122 Slice ( Box < TypeRef > ) ,
123123 /// A fn pointer. Last element of the vector is the return type.
124124 Fn ( Vec < ( Option < Name > , TypeRef ) > , bool /*varargs*/ , bool /*is_unsafe*/ ) ,
@@ -190,7 +190,7 @@ impl TypeRef {
190190 // `hir_def::body::lower` to lower this into an `Expr` and then evaluate it at the
191191 // `hir_ty` level, which would allow knowing the type of:
192192 // let v: [u8; 2 + 2] = [0u8; 4];
193- let len = ConstRefOrPath :: from_expr_opt ( inner. expr ( ) ) ;
193+ let len = ConstRef :: from_expr_opt ( ctx , inner. expr ( ) ) ;
194194 TypeRef :: Array ( Box :: new ( TypeRef :: from_ast_opt ( ctx, inner. ty ( ) ) ) , len)
195195 }
196196 ast:: Type :: SliceType ( inner) => {
@@ -380,73 +380,84 @@ impl TypeBound {
380380}
381381
382382#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
383- pub enum ConstRefOrPath {
384- Scalar ( ConstRef ) ,
383+ pub enum ConstRef {
384+ Scalar ( LiteralConstRef ) ,
385385 Path ( Name ) ,
386+ Complex ( AstId < ast:: Expr > ) ,
386387}
387388
388- impl ConstRefOrPath {
389- pub ( crate ) fn from_expr_opt ( expr : Option < ast:: Expr > ) -> Self {
389+ impl ConstRef {
390+ pub ( crate ) fn from_expr_opt ( lower_ctx : & LowerCtx < ' _ > , expr : Option < ast:: Expr > ) -> Self {
390391 match expr {
391- Some ( x) => Self :: from_expr ( x) ,
392- None => Self :: Scalar ( ConstRef :: Unknown ) ,
392+ Some ( x) => {
393+ let ast_id = lower_ctx. ast_id ( & x) ;
394+ Self :: from_expr ( x, ast_id)
395+ }
396+ None => Self :: Scalar ( LiteralConstRef :: Unknown ) ,
393397 }
394398 }
395399
396400 pub fn display < ' a > ( & ' a self , db : & ' a dyn ExpandDatabase ) -> impl fmt:: Display + ' a {
397- struct Display < ' a > ( & ' a dyn ExpandDatabase , & ' a ConstRefOrPath ) ;
401+ struct Display < ' a > ( & ' a dyn ExpandDatabase , & ' a ConstRef ) ;
398402 impl fmt:: Display for Display < ' _ > {
399403 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
400404 match self . 1 {
401- ConstRefOrPath :: Scalar ( s) => s. fmt ( f) ,
402- ConstRefOrPath :: Path ( n) => n. display ( self . 0 ) . fmt ( f) ,
405+ ConstRef :: Scalar ( s) => s. fmt ( f) ,
406+ ConstRef :: Path ( n) => n. display ( self . 0 ) . fmt ( f) ,
407+ ConstRef :: Complex ( _) => f. write_str ( "{const}" ) ,
403408 }
404409 }
405410 }
406411 Display ( db, self )
407412 }
408413
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 {
414+ // We special case literals and single identifiers, to speed up things.
415+ fn from_expr ( expr : ast:: Expr , ast_id : Option < AstId < ast:: Expr > > ) -> Self {
416+ fn is_path_ident ( p : & ast:: PathExpr ) -> bool {
417+ let Some ( path) = p. path ( ) else {
418+ return false ;
419+ } ;
420+ if path. coloncolon_token ( ) . is_some ( ) {
421+ return false ;
422+ }
423+ if let Some ( s) = path. segment ( ) {
424+ if s. coloncolon_token ( ) . is_some ( ) || s. generic_arg_list ( ) . is_some ( ) {
425+ return false ;
426+ }
427+ }
428+ true
429+ }
412430 match expr {
413- ast:: Expr :: PathExpr ( p) => {
431+ ast:: Expr :: PathExpr ( p) if is_path_ident ( & p ) => {
414432 match p. path ( ) . and_then ( |x| x. segment ( ) ) . and_then ( |x| x. name_ref ( ) ) {
415433 Some ( x) => Self :: Path ( x. as_name ( ) ) ,
416- None => Self :: Scalar ( ConstRef :: Unknown ) ,
434+ None => Self :: Scalar ( LiteralConstRef :: Unknown ) ,
417435 }
418436 }
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- } ,
432437 ast:: Expr :: Literal ( literal) => Self :: Scalar ( match literal. kind ( ) {
433438 ast:: LiteralKind :: IntNumber ( num) => {
434- num. value ( ) . map ( ConstRef :: UInt ) . unwrap_or ( ConstRef :: Unknown )
439+ num. value ( ) . map ( LiteralConstRef :: UInt ) . unwrap_or ( LiteralConstRef :: Unknown )
435440 }
436441 ast:: LiteralKind :: Char ( c) => {
437- c. value ( ) . map ( ConstRef :: Char ) . unwrap_or ( ConstRef :: Unknown )
442+ c. value ( ) . map ( LiteralConstRef :: Char ) . unwrap_or ( LiteralConstRef :: Unknown )
438443 }
439- ast:: LiteralKind :: Bool ( f) => ConstRef :: Bool ( f) ,
440- _ => ConstRef :: Unknown ,
444+ ast:: LiteralKind :: Bool ( f) => LiteralConstRef :: Bool ( f) ,
445+ _ => LiteralConstRef :: Unknown ,
441446 } ) ,
442- _ => Self :: Scalar ( ConstRef :: Unknown ) ,
447+ _ => {
448+ if let Some ( ast_id) = ast_id {
449+ Self :: Complex ( ast_id)
450+ } else {
451+ Self :: Scalar ( LiteralConstRef :: Unknown )
452+ }
453+ }
443454 }
444455 }
445456}
446457
447- /// A concrete constant value
458+ /// A literal constant value
448459#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
449- pub enum ConstRef {
460+ pub enum LiteralConstRef {
450461 Int ( i128 ) ,
451462 UInt ( u128 ) ,
452463 Bool ( bool ) ,
@@ -460,18 +471,20 @@ pub enum ConstRef {
460471 Unknown ,
461472}
462473
463- impl ConstRef {
474+ impl LiteralConstRef {
464475 pub fn builtin_type ( & self ) -> BuiltinType {
465476 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 ,
477+ LiteralConstRef :: UInt ( _) | LiteralConstRef :: Unknown => {
478+ BuiltinType :: Uint ( BuiltinUint :: U128 )
479+ }
480+ LiteralConstRef :: Int ( _) => BuiltinType :: Int ( BuiltinInt :: I128 ) ,
481+ LiteralConstRef :: Char ( _) => BuiltinType :: Char ,
482+ LiteralConstRef :: Bool ( _) => BuiltinType :: Bool ,
470483 }
471484 }
472485}
473486
474- impl From < Literal > for ConstRef {
487+ impl From < Literal > for LiteralConstRef {
475488 fn from ( literal : Literal ) -> Self {
476489 match literal {
477490 Literal :: Char ( c) => Self :: Char ( c) ,
@@ -483,14 +496,14 @@ impl From<Literal> for ConstRef {
483496 }
484497}
485498
486- impl std:: fmt:: Display for ConstRef {
499+ impl std:: fmt:: Display for LiteralConstRef {
487500 fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> Result < ( ) , std:: fmt:: Error > {
488501 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 ( '_' ) ,
502+ LiteralConstRef :: Int ( num) => num. fmt ( f) ,
503+ LiteralConstRef :: UInt ( num) => num. fmt ( f) ,
504+ LiteralConstRef :: Bool ( flag) => flag. fmt ( f) ,
505+ LiteralConstRef :: Char ( c) => write ! ( f, "'{c}'" ) ,
506+ LiteralConstRef :: Unknown => f. write_char ( '_' ) ,
494507 }
495508 }
496509}
0 commit comments