@@ -5,10 +5,15 @@ use hir_expand::{
55 name:: { AsName , Name } ,
66 AstId , InFile ,
77} ;
8- use std:: { convert:: TryInto , fmt:: Write } ;
98use syntax:: ast:: { self , HasName } ;
109
11- use crate :: { body:: LowerCtx , intern:: Interned , path:: Path } ;
10+ use crate :: {
11+ body:: LowerCtx ,
12+ builtin_type:: { BuiltinInt , BuiltinType , BuiltinUint } ,
13+ expr:: Literal ,
14+ intern:: Interned ,
15+ path:: Path ,
16+ } ;
1217
1318#[ derive( Copy , Clone , PartialEq , Eq , Hash , Debug ) ]
1419pub enum Mutability {
@@ -177,7 +182,10 @@ impl TypeRef {
177182 // `hir_def::body::lower` to lower this into an `Expr` and then evaluate it at the
178183 // `hir_ty` level, which would allow knowing the type of:
179184 // let v: [u8; 2 + 2] = [0u8; 4];
180- let len = ConstScalarOrPath :: from_expr_opt ( inner. expr ( ) ) ;
185+ let len = inner. expr ( ) . map_or (
186+ ConstScalarOrPath :: Scalar ( ConstScalar :: Unknown ) ,
187+ ConstScalarOrPath :: from_expr,
188+ ) ;
181189
182190 TypeRef :: Array ( Box :: new ( TypeRef :: from_ast_opt ( ctx, inner. ty ( ) ) ) , len)
183191 }
@@ -386,39 +394,41 @@ impl std::fmt::Display for ConstScalarOrPath {
386394}
387395
388396impl ConstScalarOrPath {
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 ( ConstScalar :: Unknown ) ,
393- }
394- }
395-
396397 // FIXME: as per the comments on `TypeRef::Array`, this evaluation should not happen at this
397398 // parse stage.
398- fn from_expr ( expr : ast:: Expr ) -> Self {
399+ pub ( crate ) fn from_expr ( expr : ast:: Expr ) -> Self {
399400 match expr {
400401 ast:: Expr :: PathExpr ( p) => {
401402 match p. path ( ) . and_then ( |x| x. segment ( ) ) . and_then ( |x| x. name_ref ( ) ) {
402403 Some ( x) => Self :: Path ( x. as_name ( ) ) ,
403404 None => Self :: Scalar ( ConstScalar :: Unknown ) ,
404405 }
405406 }
406- ast:: Expr :: Literal ( lit) => {
407- let lkind = lit. kind ( ) ;
408- match lkind {
409- ast:: LiteralKind :: IntNumber ( num)
410- if num. suffix ( ) == None || num. suffix ( ) == Some ( "usize" ) =>
411- {
412- Self :: Scalar (
413- num. value ( )
414- . and_then ( |v| v. try_into ( ) . ok ( ) )
415- . map ( ConstScalar :: Usize )
416- . unwrap_or ( ConstScalar :: Unknown ) ,
417- )
407+ ast:: Expr :: PrefixExpr ( prefix_expr) => match prefix_expr. op_kind ( ) {
408+ Some ( ast:: UnaryOp :: Neg ) => {
409+ let unsigned = prefix_expr
410+ . expr ( )
411+ . map_or ( Self :: Scalar ( ConstScalar :: Unknown ) , Self :: from_expr) ;
412+ // Add sign
413+ match unsigned {
414+ Self :: Scalar ( ConstScalar :: UInt ( num) ) => {
415+ Self :: Scalar ( ConstScalar :: Int ( -( num as i128 ) ) )
416+ }
417+ other => other,
418418 }
419- _ => Self :: Scalar ( ConstScalar :: Unknown ) ,
420419 }
421- }
420+ _ => prefix_expr. expr ( ) . map_or ( Self :: Scalar ( ConstScalar :: Unknown ) , Self :: from_expr) ,
421+ } ,
422+ ast:: Expr :: Literal ( literal) => Self :: Scalar ( match literal. kind ( ) {
423+ ast:: LiteralKind :: IntNumber ( num) => {
424+ num. value ( ) . map ( ConstScalar :: UInt ) . unwrap_or ( ConstScalar :: Unknown )
425+ }
426+ ast:: LiteralKind :: Char ( c) => {
427+ c. value ( ) . map ( ConstScalar :: Char ) . unwrap_or ( ConstScalar :: Unknown )
428+ }
429+ ast:: LiteralKind :: Bool ( f) => ConstScalar :: Bool ( f) ,
430+ _ => ConstScalar :: Unknown ,
431+ } ) ,
422432 _ => Self :: Scalar ( ConstScalar :: Unknown ) ,
423433 }
424434 }
@@ -427,9 +437,10 @@ impl ConstScalarOrPath {
427437/// A concrete constant value
428438#[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
429439pub enum ConstScalar {
430- // for now, we only support the trivial case of constant evaluating the length of an array
431- // Note that this is u64 because the target usize may be bigger than our usize
432- Usize ( u64 ) ,
440+ Int ( i128 ) ,
441+ UInt ( u128 ) ,
442+ Bool ( bool ) ,
443+ Char ( char ) ,
433444
434445 /// Case of an unknown value that rustc might know but we don't
435446 // FIXME: this is a hack to get around chalk not being able to represent unevaluatable
@@ -439,21 +450,37 @@ pub enum ConstScalar {
439450 Unknown ,
440451}
441452
442- impl std :: fmt :: Display for ConstScalar {
443- fn fmt ( & self , f : & mut std :: fmt :: Formatter < ' _ > ) -> Result < ( ) , std :: fmt :: Error > {
453+ impl ConstScalar {
454+ pub fn builtin_type ( & self ) -> BuiltinType {
444455 match self {
445- ConstScalar :: Usize ( us) => us. fmt ( f) ,
446- ConstScalar :: Unknown => f. write_char ( '_' ) ,
456+ ConstScalar :: UInt ( _) | ConstScalar :: Unknown => BuiltinType :: Uint ( BuiltinUint :: U128 ) ,
457+ ConstScalar :: Int ( _) => BuiltinType :: Int ( BuiltinInt :: I128 ) ,
458+ ConstScalar :: Char ( _) => BuiltinType :: Char ,
459+ ConstScalar :: Bool ( _) => BuiltinType :: Bool ,
447460 }
448461 }
449462}
450463
451- impl ConstScalar {
452- /// Gets a target usize out of the ConstScalar
453- pub fn as_usize ( & self ) -> Option < u64 > {
464+ impl From < Literal > for ConstScalar {
465+ fn from ( literal : Literal ) -> Self {
466+ match literal {
467+ Literal :: Char ( c) => Self :: Char ( c) ,
468+ Literal :: Bool ( flag) => Self :: Bool ( flag) ,
469+ Literal :: Int ( num, _) => Self :: Int ( num) ,
470+ Literal :: Uint ( num, _) => Self :: UInt ( num) ,
471+ _ => Self :: Unknown ,
472+ }
473+ }
474+ }
475+
476+ impl std:: fmt:: Display for ConstScalar {
477+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> Result < ( ) , std:: fmt:: Error > {
454478 match self {
455- & ConstScalar :: Usize ( us) => Some ( us) ,
456- _ => None ,
479+ ConstScalar :: Int ( num) => num. fmt ( f) ,
480+ ConstScalar :: UInt ( num) => num. fmt ( f) ,
481+ ConstScalar :: Bool ( flag) => flag. fmt ( f) ,
482+ ConstScalar :: Char ( c) => write ! ( f, "'{c}'" ) ,
483+ ConstScalar :: Unknown => f. write_str ( "{unknown}" ) ,
457484 }
458485 }
459486}
0 commit comments