@@ -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*/ ) ,
@@ -186,11 +186,7 @@ impl TypeRef {
186186 TypeRef :: RawPtr ( Box :: new ( inner_ty) , mutability)
187187 }
188188 ast:: Type :: ArrayType ( inner) => {
189- // FIXME: This is a hack. We should probably reuse the machinery of
190- // `hir_def::body::lower` to lower this into an `Expr` and then evaluate it at the
191- // `hir_ty` level, which would allow knowing the type of:
192- // let v: [u8; 2 + 2] = [0u8; 4];
193- let len = ConstRefOrPath :: from_expr_opt ( inner. expr ( ) ) ;
189+ let len = ConstRef :: from_const_arg ( ctx, inner. const_arg ( ) ) ;
194190 TypeRef :: Array ( Box :: new ( TypeRef :: from_ast_opt ( ctx, inner. ty ( ) ) ) , len)
195191 }
196192 ast:: Type :: SliceType ( inner) => {
@@ -380,73 +376,84 @@ impl TypeBound {
380376}
381377
382378#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
383- pub enum ConstRefOrPath {
384- Scalar ( ConstRef ) ,
379+ pub enum ConstRef {
380+ Scalar ( LiteralConstRef ) ,
385381 Path ( Name ) ,
382+ Complex ( AstId < ast:: ConstArg > ) ,
386383}
387384
388- impl ConstRefOrPath {
389- pub ( crate ) fn from_expr_opt ( expr : Option < ast:: Expr > ) -> Self {
390- match expr {
391- Some ( x) => Self :: from_expr ( x) ,
392- None => Self :: Scalar ( ConstRef :: Unknown ) ,
385+ impl ConstRef {
386+ pub ( crate ) fn from_const_arg ( lower_ctx : & LowerCtx < ' _ > , arg : Option < ast:: ConstArg > ) -> Self {
387+ if let Some ( arg) = arg {
388+ let ast_id = lower_ctx. ast_id ( & arg) ;
389+ if let Some ( expr) = arg. expr ( ) {
390+ return Self :: from_expr ( expr, ast_id) ;
391+ }
393392 }
393+ Self :: Scalar ( LiteralConstRef :: Unknown )
394394 }
395395
396396 pub fn display < ' a > ( & ' a self , db : & ' a dyn ExpandDatabase ) -> impl fmt:: Display + ' a {
397- struct Display < ' a > ( & ' a dyn ExpandDatabase , & ' a ConstRefOrPath ) ;
397+ struct Display < ' a > ( & ' a dyn ExpandDatabase , & ' a ConstRef ) ;
398398 impl fmt:: Display for Display < ' _ > {
399399 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
400400 match self . 1 {
401- ConstRefOrPath :: Scalar ( s) => s. fmt ( f) ,
402- ConstRefOrPath :: Path ( n) => n. display ( self . 0 ) . fmt ( f) ,
401+ ConstRef :: Scalar ( s) => s. fmt ( f) ,
402+ ConstRef :: Path ( n) => n. display ( self . 0 ) . fmt ( f) ,
403+ ConstRef :: Complex ( _) => f. write_str ( "{const}" ) ,
403404 }
404405 }
405406 }
406407 Display ( db, self )
407408 }
408409
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 {
410+ // We special case literals and single identifiers, to speed up things.
411+ fn from_expr ( expr : ast:: Expr , ast_id : Option < AstId < ast:: ConstArg > > ) -> Self {
412+ fn is_path_ident ( p : & ast:: PathExpr ) -> bool {
413+ let Some ( path) = p. path ( ) else {
414+ return false ;
415+ } ;
416+ if path. coloncolon_token ( ) . is_some ( ) {
417+ return false ;
418+ }
419+ if let Some ( s) = path. segment ( ) {
420+ if s. coloncolon_token ( ) . is_some ( ) || s. generic_arg_list ( ) . is_some ( ) {
421+ return false ;
422+ }
423+ }
424+ true
425+ }
412426 match expr {
413- ast:: Expr :: PathExpr ( p) => {
427+ ast:: Expr :: PathExpr ( p) if is_path_ident ( & p ) => {
414428 match p. path ( ) . and_then ( |x| x. segment ( ) ) . and_then ( |x| x. name_ref ( ) ) {
415429 Some ( x) => Self :: Path ( x. as_name ( ) ) ,
416- None => Self :: Scalar ( ConstRef :: Unknown ) ,
430+ None => Self :: Scalar ( LiteralConstRef :: Unknown ) ,
417431 }
418432 }
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- } ,
432433 ast:: Expr :: Literal ( literal) => Self :: Scalar ( match literal. kind ( ) {
433434 ast:: LiteralKind :: IntNumber ( num) => {
434- num. value ( ) . map ( ConstRef :: UInt ) . unwrap_or ( ConstRef :: Unknown )
435+ num. value ( ) . map ( LiteralConstRef :: UInt ) . unwrap_or ( LiteralConstRef :: Unknown )
435436 }
436437 ast:: LiteralKind :: Char ( c) => {
437- c. value ( ) . map ( ConstRef :: Char ) . unwrap_or ( ConstRef :: Unknown )
438+ c. value ( ) . map ( LiteralConstRef :: Char ) . unwrap_or ( LiteralConstRef :: Unknown )
438439 }
439- ast:: LiteralKind :: Bool ( f) => ConstRef :: Bool ( f) ,
440- _ => ConstRef :: Unknown ,
440+ ast:: LiteralKind :: Bool ( f) => LiteralConstRef :: Bool ( f) ,
441+ _ => LiteralConstRef :: Unknown ,
441442 } ) ,
442- _ => Self :: Scalar ( ConstRef :: Unknown ) ,
443+ _ => {
444+ if let Some ( ast_id) = ast_id {
445+ Self :: Complex ( ast_id)
446+ } else {
447+ Self :: Scalar ( LiteralConstRef :: Unknown )
448+ }
449+ }
443450 }
444451 }
445452}
446453
447- /// A concrete constant value
454+ /// A literal constant value
448455#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
449- pub enum ConstRef {
456+ pub enum LiteralConstRef {
450457 Int ( i128 ) ,
451458 UInt ( u128 ) ,
452459 Bool ( bool ) ,
@@ -460,18 +467,20 @@ pub enum ConstRef {
460467 Unknown ,
461468}
462469
463- impl ConstRef {
470+ impl LiteralConstRef {
464471 pub fn builtin_type ( & self ) -> BuiltinType {
465472 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 ,
473+ LiteralConstRef :: UInt ( _) | LiteralConstRef :: Unknown => {
474+ BuiltinType :: Uint ( BuiltinUint :: U128 )
475+ }
476+ LiteralConstRef :: Int ( _) => BuiltinType :: Int ( BuiltinInt :: I128 ) ,
477+ LiteralConstRef :: Char ( _) => BuiltinType :: Char ,
478+ LiteralConstRef :: Bool ( _) => BuiltinType :: Bool ,
470479 }
471480 }
472481}
473482
474- impl From < Literal > for ConstRef {
483+ impl From < Literal > for LiteralConstRef {
475484 fn from ( literal : Literal ) -> Self {
476485 match literal {
477486 Literal :: Char ( c) => Self :: Char ( c) ,
@@ -483,14 +492,14 @@ impl From<Literal> for ConstRef {
483492 }
484493}
485494
486- impl std:: fmt:: Display for ConstRef {
495+ impl std:: fmt:: Display for LiteralConstRef {
487496 fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> Result < ( ) , std:: fmt:: Error > {
488497 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 ( '_' ) ,
498+ LiteralConstRef :: Int ( num) => num. fmt ( f) ,
499+ LiteralConstRef :: UInt ( num) => num. fmt ( f) ,
500+ LiteralConstRef :: Bool ( flag) => flag. fmt ( f) ,
501+ LiteralConstRef :: Char ( c) => write ! ( f, "'{c}'" ) ,
502+ LiteralConstRef :: Unknown => f. write_char ( '_' ) ,
494503 }
495504 }
496505}
0 commit comments