@@ -36,6 +36,7 @@ use syntax::codemap::Span;
36
36
use syntax:: parse:: token:: InternedString ;
37
37
use syntax:: ptr:: P ;
38
38
use syntax:: codemap;
39
+ use syntax:: attr:: IntType ;
39
40
40
41
use std:: borrow:: Cow ;
41
42
use std:: cmp:: Ordering ;
@@ -462,6 +463,10 @@ pub enum ErrKind {
462
463
463
464
IndexOpFeatureGated ,
464
465
Math ( ConstMathErr ) ,
466
+
467
+ IntermediateUnsignedNegative ,
468
+ InferredWrongType ( ConstInt ) ,
469
+ BadType ( ConstVal ) ,
465
470
}
466
471
467
472
impl From < ConstMathErr > for ErrKind {
@@ -518,6 +523,13 @@ impl ConstEvalErr {
518
523
MiscCatchAll => "unsupported constant expr" . into_cow ( ) ,
519
524
IndexOpFeatureGated => "the index operation on const values is unstable" . into_cow ( ) ,
520
525
Math ( ref err) => err. description ( ) . into_cow ( ) ,
526
+
527
+ IntermediateUnsignedNegative => "during the computation of an unsigned a negative \
528
+ number was encountered. This is most likely a bug in\
529
+ the constant evaluator". into_cow ( ) ,
530
+
531
+ InferredWrongType ( ref i) => format ! ( "inferred wrong type for {}" , i) . into_cow ( ) ,
532
+ BadType ( ref i) => format ! ( "value of wrong type: {:?}" , i) . into_cow ( ) ,
521
533
}
522
534
}
523
535
}
@@ -974,7 +986,101 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
974
986
_ => signal ! ( e, MiscCatchAll )
975
987
} ;
976
988
977
- Ok ( result)
989
+ match ( ety. map ( |t| & t. sty ) , result) {
990
+ ( Some ( ref ty_hint) , Integral ( i) ) => Ok ( Integral ( try!( infer ( i, tcx, ty_hint, e. span ) ) ) ) ,
991
+ ( _, result) => Ok ( result) ,
992
+ }
993
+ }
994
+
995
+ fn infer < ' tcx > (
996
+ i : ConstInt ,
997
+ tcx : & TyCtxt < ' tcx > ,
998
+ ty_hint : & ty:: TypeVariants < ' tcx > ,
999
+ span : Span
1000
+ ) -> Result < ConstInt , ConstEvalErr > {
1001
+ use syntax:: ast:: * ;
1002
+ const I8MAX : u64 = :: std:: i8:: MAX as u64 ;
1003
+ const I16MAX : u64 = :: std:: i16:: MAX as u64 ;
1004
+ const I32MAX : u64 = :: std:: i32:: MAX as u64 ;
1005
+ const I64MAX : u64 = :: std:: i64:: MAX as u64 ;
1006
+
1007
+ const U8MAX : u64 = :: std:: u8:: MAX as u64 ;
1008
+ const U16MAX : u64 = :: std:: u16:: MAX as u64 ;
1009
+ const U32MAX : u64 = :: std:: u32:: MAX as u64 ;
1010
+
1011
+ const I8MAXI : i64 = :: std:: i8:: MAX as i64 ;
1012
+ const I16MAXI : i64 = :: std:: i16:: MAX as i64 ;
1013
+ const I32MAXI : i64 = :: std:: i32:: MAX as i64 ;
1014
+
1015
+ const I8MINI : i64 = :: std:: i8:: MIN as i64 ;
1016
+ const I16MINI : i64 = :: std:: i16:: MIN as i64 ;
1017
+ const I32MINI : i64 = :: std:: i32:: MIN as i64 ;
1018
+
1019
+ let err = |e| ConstEvalErr {
1020
+ span : span,
1021
+ kind : e,
1022
+ } ;
1023
+
1024
+ match ( ty_hint, i) {
1025
+ ( & ty:: TyInt ( IntTy :: I8 ) , result @ I8 ( _) ) => Ok ( result) ,
1026
+ ( & ty:: TyInt ( IntTy :: I16 ) , result @ I16 ( _) ) => Ok ( result) ,
1027
+ ( & ty:: TyInt ( IntTy :: I32 ) , result @ I32 ( _) ) => Ok ( result) ,
1028
+ ( & ty:: TyInt ( IntTy :: I64 ) , result @ I64 ( _) ) => Ok ( result) ,
1029
+ ( & ty:: TyInt ( IntTy :: Is ) , result @ Isize ( _) ) => Ok ( result) ,
1030
+
1031
+ ( & ty:: TyUint ( UintTy :: U8 ) , result @ U8 ( _) ) => Ok ( result) ,
1032
+ ( & ty:: TyUint ( UintTy :: U16 ) , result @ U16 ( _) ) => Ok ( result) ,
1033
+ ( & ty:: TyUint ( UintTy :: U32 ) , result @ U32 ( _) ) => Ok ( result) ,
1034
+ ( & ty:: TyUint ( UintTy :: U64 ) , result @ U64 ( _) ) => Ok ( result) ,
1035
+ ( & ty:: TyUint ( UintTy :: Us ) , result @ Usize ( _) ) => Ok ( result) ,
1036
+
1037
+ ( & ty:: TyInt ( IntTy :: I8 ) , Infer ( i @ 0 ...I8MAX ) ) => Ok ( I8 ( i as i8 ) ) ,
1038
+ ( & ty:: TyInt ( IntTy :: I16 ) , Infer ( i @ 0 ...I16MAX ) ) => Ok ( I16 ( i as i16 ) ) ,
1039
+ ( & ty:: TyInt ( IntTy :: I32 ) , Infer ( i @ 0 ...I32MAX ) ) => Ok ( I32 ( i as i32 ) ) ,
1040
+ ( & ty:: TyInt ( IntTy :: I64 ) , Infer ( i @ 0 ...I64MAX ) ) => Ok ( I64 ( i as i64 ) ) ,
1041
+ ( & ty:: TyInt ( IntTy :: Is ) , Infer ( i @ 0 ...I64MAX ) ) => {
1042
+ match ConstIsize :: new ( i as i64 , tcx. sess . target . int_type ) {
1043
+ Ok ( val) => Ok ( Isize ( val) ) ,
1044
+ Err ( e) => Err ( err ( e. into ( ) ) ) ,
1045
+ }
1046
+ } ,
1047
+ ( & ty:: TyInt ( _) , Infer ( _) ) => Err ( err ( Math ( ConstMathErr :: NotInRange ) ) ) ,
1048
+
1049
+ ( & ty:: TyInt ( IntTy :: I8 ) , InferSigned ( i @ I8MINI ...I8MAXI ) ) => Ok ( I8 ( i as i8 ) ) ,
1050
+ ( & ty:: TyInt ( IntTy :: I16 ) , InferSigned ( i @ I16MINI ...I16MAXI ) ) => Ok ( I16 ( i as i16 ) ) ,
1051
+ ( & ty:: TyInt ( IntTy :: I32 ) , InferSigned ( i @ I32MINI ...I32MAXI ) ) => Ok ( I32 ( i as i32 ) ) ,
1052
+ ( & ty:: TyInt ( IntTy :: I64 ) , InferSigned ( i) ) => Ok ( I64 ( i) ) ,
1053
+ ( & ty:: TyInt ( IntTy :: Is ) , InferSigned ( i) ) => {
1054
+ match ConstIsize :: new ( i, tcx. sess . target . int_type ) {
1055
+ Ok ( val) => Ok ( Isize ( val) ) ,
1056
+ Err ( e) => Err ( err ( e. into ( ) ) ) ,
1057
+ }
1058
+ } ,
1059
+ ( & ty:: TyInt ( _) , InferSigned ( _) ) => Err ( err ( Math ( ConstMathErr :: NotInRange ) ) ) ,
1060
+
1061
+ ( & ty:: TyUint ( UintTy :: U8 ) , Infer ( i @ 0 ...U8MAX ) ) => Ok ( U8 ( i as u8 ) ) ,
1062
+ ( & ty:: TyUint ( UintTy :: U16 ) , Infer ( i @ 0 ...U16MAX ) ) => Ok ( U16 ( i as u16 ) ) ,
1063
+ ( & ty:: TyUint ( UintTy :: U32 ) , Infer ( i @ 0 ...U32MAX ) ) => Ok ( U32 ( i as u32 ) ) ,
1064
+ ( & ty:: TyUint ( UintTy :: U64 ) , Infer ( i) ) => Ok ( U64 ( i) ) ,
1065
+ ( & ty:: TyUint ( UintTy :: Us ) , Infer ( i) ) => {
1066
+ match ConstUsize :: new ( i, tcx. sess . target . uint_type ) {
1067
+ Ok ( val) => Ok ( Usize ( val) ) ,
1068
+ Err ( e) => Err ( err ( e. into ( ) ) ) ,
1069
+ }
1070
+ } ,
1071
+ ( & ty:: TyUint ( _) , Infer ( _) ) => Err ( err ( Math ( ConstMathErr :: NotInRange ) ) ) ,
1072
+ ( & ty:: TyUint ( _) , InferSigned ( _) ) => Err ( err ( IntermediateUnsignedNegative ) ) ,
1073
+
1074
+ ( & ty:: TyInt ( _) , i) |
1075
+ ( & ty:: TyUint ( _) , i) => Err ( err ( InferredWrongType ( i) ) ) ,
1076
+
1077
+ ( & ty:: TyEnum ( ref adt, _) , i) => {
1078
+ let hints = tcx. lookup_repr_hints ( adt. did ) ;
1079
+ let int_ty = tcx. enum_repr_type ( hints. iter ( ) . next ( ) ) ;
1080
+ infer ( i, tcx, & int_ty. to_ty ( tcx) . sty , span)
1081
+ } ,
1082
+ ( _, i) => Err ( err ( BadType ( ConstVal :: Integral ( i) ) ) ) ,
1083
+ }
978
1084
}
979
1085
980
1086
fn impl_or_trait_container ( tcx : & TyCtxt , def_id : DefId ) -> ty:: ImplOrTraitItemContainer {
@@ -1083,7 +1189,7 @@ fn cast_const_int<'tcx>(tcx: &TyCtxt<'tcx>, val: ConstInt, ty: ty::Ty) -> CastRe
1083
1189
}
1084
1190
}
1085
1191
1086
- fn cast_const_float < ' tcx > ( tcx : & ty :: ctxt < ' tcx > , f : f64 , ty : ty:: Ty ) -> CastResult {
1192
+ fn cast_const_float < ' tcx > ( tcx : & TyCtxt < ' tcx > , f : f64 , ty : ty:: Ty ) -> CastResult {
1087
1193
match ty. sty {
1088
1194
ty:: TyInt ( _) if f >= 0.0 => cast_const_int ( tcx, Infer ( f as u64 ) , ty) ,
1089
1195
ty:: TyInt ( _) => cast_const_int ( tcx, InferSigned ( f as i64 ) , ty) ,
@@ -1094,7 +1200,7 @@ fn cast_const_float<'tcx>(tcx: &ty::ctxt<'tcx>, f: f64, ty: ty::Ty) -> CastResul
1094
1200
}
1095
1201
}
1096
1202
1097
- fn cast_const < ' tcx > ( tcx : & ty :: ctxt < ' tcx > , val : ConstVal , ty : ty:: Ty ) -> CastResult {
1203
+ fn cast_const < ' tcx > ( tcx : & TyCtxt < ' tcx > , val : ConstVal , ty : ty:: Ty ) -> CastResult {
1098
1204
match val {
1099
1205
Integral ( i) => cast_const_int ( tcx, i, ty) ,
1100
1206
Bool ( b) => cast_const_int ( tcx, Infer ( b as u64 ) , ty) ,
@@ -1105,7 +1211,7 @@ fn cast_const<'tcx>(tcx: &ty::ctxt<'tcx>, val: ConstVal, ty: ty::Ty) -> CastResu
1105
1211
}
1106
1212
1107
1213
fn lit_to_const < ' tcx > ( lit : & ast:: LitKind ,
1108
- tcx : & ty :: ctxt < ' tcx > ,
1214
+ tcx : & TyCtxt < ' tcx > ,
1109
1215
ty_hint : Option < Ty < ' tcx > > ,
1110
1216
span : Span ,
1111
1217
) -> Result < ConstVal , ConstMathErr > {
0 commit comments