Skip to content

Commit 6ee6003

Browse files
committed
infer integral types in presence of a type hint
1 parent 41f11d9 commit 6ee6003

File tree

1 file changed

+110
-4
lines changed

1 file changed

+110
-4
lines changed

src/librustc/middle/const_eval.rs

Lines changed: 110 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ use syntax::codemap::Span;
3636
use syntax::parse::token::InternedString;
3737
use syntax::ptr::P;
3838
use syntax::codemap;
39+
use syntax::attr::IntType;
3940

4041
use std::borrow::Cow;
4142
use std::cmp::Ordering;
@@ -462,6 +463,10 @@ pub enum ErrKind {
462463

463464
IndexOpFeatureGated,
464465
Math(ConstMathErr),
466+
467+
IntermediateUnsignedNegative,
468+
InferredWrongType(ConstInt),
469+
BadType(ConstVal),
465470
}
466471

467472
impl From<ConstMathErr> for ErrKind {
@@ -518,6 +523,13 @@ impl ConstEvalErr {
518523
MiscCatchAll => "unsupported constant expr".into_cow(),
519524
IndexOpFeatureGated => "the index operation on const values is unstable".into_cow(),
520525
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(),
521533
}
522534
}
523535
}
@@ -974,7 +986,101 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
974986
_ => signal!(e, MiscCatchAll)
975987
};
976988

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+
}
9781084
}
9791085

9801086
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
10831189
}
10841190
}
10851191

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 {
10871193
match ty.sty {
10881194
ty::TyInt(_) if f >= 0.0 => cast_const_int(tcx, Infer(f as u64), ty),
10891195
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
10941200
}
10951201
}
10961202

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 {
10981204
match val {
10991205
Integral(i) => cast_const_int(tcx, i, ty),
11001206
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
11051211
}
11061212

11071213
fn lit_to_const<'tcx>(lit: &ast::LitKind,
1108-
tcx: &ty::ctxt<'tcx>,
1214+
tcx: &TyCtxt<'tcx>,
11091215
ty_hint: Option<Ty<'tcx>>,
11101216
span: Span,
11111217
) -> Result<ConstVal, ConstMathErr> {

0 commit comments

Comments
 (0)