1212#![ allow( unsigned_negation) ]
1313
1414use self :: ConstVal :: * ;
15-
1615use self :: ErrKind :: * ;
16+ use self :: EvalHint :: * ;
1717
1818use ast_map;
1919use ast_map:: blocks:: FnLikeNode ;
@@ -331,7 +331,7 @@ pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P<ast::Pat>
331331}
332332
333333pub fn eval_const_expr ( tcx : & ty:: ctxt , e : & Expr ) -> ConstVal {
334- match eval_const_expr_partial ( tcx, e, None ) {
334+ match eval_const_expr_partial ( tcx, e, ExprTypeChecked ) {
335335 Ok ( r) => r,
336336 Err ( s) => tcx. sess . span_fatal ( s. span , & s. description ( ) )
337337 }
@@ -436,6 +436,28 @@ impl ConstEvalErr {
436436pub type EvalResult = Result < ConstVal , ConstEvalErr > ;
437437pub type CastResult = Result < ConstVal , ErrKind > ;
438438
439+ // FIXME: Long-term, this enum should go away: trying to evaluate
440+ // an expression which hasn't been type-checked is a recipe for
441+ // disaster. That said, it's not clear how to fix ast_ty_to_ty
442+ // to avoid the ordering issue.
443+
444+ /// Hint to determine how to evaluate constant expressions which
445+ /// might not be type-checked.
446+ #[ derive( Copy , Clone , Debug ) ]
447+ pub enum EvalHint < ' tcx > {
448+ /// We have a type-checked expression.
449+ ExprTypeChecked ,
450+ /// We have an expression which hasn't been type-checked, but we have
451+ /// an idea of what the type will be because of the context. For example,
452+ /// the length of an array is always `usize`. (This is referred to as
453+ /// a hint because it isn't guaranteed to be consistent with what
454+ /// type-checking would compute.)
455+ UncheckedExprHint ( Ty < ' tcx > ) ,
456+ /// We have an expression which has not yet been type-checked, and
457+ /// and we have no clue what the type will be.
458+ UncheckedExprNoHint ,
459+ }
460+
439461#[ derive( Copy , Clone , PartialEq , Debug ) ]
440462pub enum IntTy { I8 , I16 , I32 , I64 }
441463#[ derive( Copy , Clone , PartialEq , Debug ) ]
@@ -706,26 +728,34 @@ pub_fn_checked_op!{ const_uint_checked_shr_via_int(a: u64, b: i64,.. UintTy) {
706728 uint_shift_body overflowing_shr Uint ShiftRightWithOverflow
707729} }
708730
709- // After type checking, `eval_const_expr_partial` should always suffice. The
710- // reason for providing `eval_const_expr_with_substs ` is to allow
711- // trait-associated consts to be evaluated * during* type checking, when the
712- // substs for each expression have not been written into `tcx` yet.
731+ /// Evaluate a constant expression in a context where the expression isn't
732+ /// guaranteed to be evaluatable. `ty_hint ` is usually ExprTypeChecked,
733+ /// but a few places need to evaluate constants during type- checking, like
734+ /// computing the length of an array. (See also the FIXME above EvalHint.)
713735pub fn eval_const_expr_partial < ' tcx > ( tcx : & ty:: ctxt < ' tcx > ,
714736 e : & Expr ,
715- ty_hint : Option < Ty < ' tcx > > ) -> EvalResult {
716- eval_const_expr_with_substs ( tcx, e, ty_hint, |id| {
717- tcx. node_id_item_substs ( id) . substs
718- } )
719- }
720-
721- pub fn eval_const_expr_with_substs < ' tcx , S > ( tcx : & ty:: ctxt < ' tcx > ,
722- e : & Expr ,
723- ty_hint : Option < Ty < ' tcx > > ,
724- get_substs : S ) -> EvalResult
725- where S : Fn ( ast:: NodeId ) -> subst:: Substs < ' tcx > {
737+ ty_hint : EvalHint < ' tcx > ) -> EvalResult {
726738 fn fromb ( b : bool ) -> ConstVal { Int ( b as i64 ) }
727739
728- let ety = ty_hint. or_else ( || tcx. expr_ty_opt ( e) ) ;
740+ // Try to compute the type of the expression based on the EvalHint.
741+ // (See also the definition of EvalHint, and the FIXME above EvalHint.)
742+ let ety = match ty_hint {
743+ ExprTypeChecked => {
744+ // After type-checking, expr_ty is guaranteed to succeed.
745+ Some ( tcx. expr_ty ( e) )
746+ }
747+ UncheckedExprHint ( ty) => {
748+ // Use the type hint; it's not guaranteed to be right, but it's
749+ // usually good enough.
750+ Some ( ty)
751+ }
752+ UncheckedExprNoHint => {
753+ // This expression might not be type-checked, and we have no hint.
754+ // Try to query the context for a type anyway; we might get lucky
755+ // (for example, if the expression was imported from another crate).
756+ tcx. expr_ty_opt ( e)
757+ }
758+ } ;
729759
730760 // If type of expression itself is int or uint, normalize in these
731761 // bindings so that isize/usize is mapped to a type with an
@@ -741,7 +771,7 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
741771
742772 let result = match e. node {
743773 ast:: ExprUnary ( ast:: UnNeg , ref inner) => {
744- match try!( eval_const_expr_partial ( tcx, & * * inner, ety ) ) {
774+ match try!( eval_const_expr_partial ( tcx, & * * inner, ty_hint ) ) {
745775 Float ( f) => Float ( -f) ,
746776 Int ( n) => try!( const_int_checked_neg ( n, e, expr_int_type) ) ,
747777 Uint ( i) => {
@@ -762,7 +792,7 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
762792 }
763793 }
764794 ast:: ExprUnary ( ast:: UnNot , ref inner) => {
765- match try!( eval_const_expr_partial ( tcx, & * * inner, ety ) ) {
795+ match try!( eval_const_expr_partial ( tcx, & * * inner, ty_hint ) ) {
766796 Int ( i) => Int ( !i) ,
767797 Uint ( i) => const_uint_not ( i, expr_uint_type) ,
768798 Bool ( b) => Bool ( !b) ,
@@ -775,10 +805,16 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
775805 }
776806 ast:: ExprBinary ( op, ref a, ref b) => {
777807 let b_ty = match op. node {
778- ast:: BiShl | ast:: BiShr => Some ( tcx. types . usize ) ,
779- _ => ety
808+ ast:: BiShl | ast:: BiShr => {
809+ if let ExprTypeChecked = ty_hint {
810+ ExprTypeChecked
811+ } else {
812+ UncheckedExprHint ( tcx. types . usize )
813+ }
814+ }
815+ _ => ty_hint
780816 } ;
781- match ( try!( eval_const_expr_partial ( tcx, & * * a, ety ) ) ,
817+ match ( try!( eval_const_expr_partial ( tcx, & * * a, ty_hint ) ) ,
782818 try!( eval_const_expr_partial ( tcx, & * * b, b_ty) ) ) {
783819 ( Float ( a) , Float ( b) ) => {
784820 match op. node {
@@ -868,22 +904,25 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
868904 }
869905 }
870906 ast:: ExprCast ( ref base, ref target_ty) => {
871- // This tends to get called w/o the type actually having been
872- // populated in the ctxt, which was causing things to blow up
873- // (#5900). Fall back to doing a limited lookup to get past it.
874907 let ety = ety. or_else ( || ast_ty_to_prim_ty ( tcx, & * * target_ty) )
875908 . unwrap_or_else ( || {
876909 tcx. sess . span_fatal ( target_ty. span ,
877910 "target type not found for const cast" )
878911 } ) ;
879912
880- // Prefer known type to noop, but always have a type hint.
881- //
882- // FIXME (#23833): the type-hint can cause problems,
883- // e.g. `(i8::MAX + 1_i8) as u32` feeds in `u32` as result
884- // type to the sum, and thus no overflow is signaled.
885- let base_hint = tcx. expr_ty_opt ( & * * base) . unwrap_or ( ety) ;
886- let val = try!( eval_const_expr_partial ( tcx, & * * base, Some ( base_hint) ) ) ;
913+ let base_hint = if let ExprTypeChecked = ty_hint {
914+ ExprTypeChecked
915+ } else {
916+ // FIXME (#23833): the type-hint can cause problems,
917+ // e.g. `(i8::MAX + 1_i8) as u32` feeds in `u32` as result
918+ // type to the sum, and thus no overflow is signaled.
919+ match tcx. expr_ty_opt ( & base) {
920+ Some ( t) => UncheckedExprHint ( t) ,
921+ None => ty_hint
922+ }
923+ } ;
924+
925+ let val = try!( eval_const_expr_partial ( tcx, & * * base, base_hint) ) ;
887926 match cast_const ( tcx, val, ety) {
888927 Ok ( val) => val,
889928 Err ( kind) => return Err ( ConstEvalErr { span : e. span , kind : kind } ) ,
@@ -913,12 +952,16 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
913952 def:: FromTrait ( trait_id) => match tcx. map . find ( def_id. node ) {
914953 Some ( ast_map:: NodeTraitItem ( ti) ) => match ti. node {
915954 ast:: ConstTraitItem ( ref ty, _) => {
916- let substs = get_substs ( e. id ) ;
917- ( resolve_trait_associated_const ( tcx,
918- ti,
919- trait_id,
920- substs) ,
921- Some ( & * * ty) )
955+ if let ExprTypeChecked = ty_hint {
956+ let substs = tcx. node_id_item_substs ( e. id ) . substs ;
957+ ( resolve_trait_associated_const ( tcx,
958+ ti,
959+ trait_id,
960+ substs) ,
961+ Some ( & * * ty) )
962+ } else {
963+ ( None , None )
964+ }
922965 }
923966 _ => ( None , None )
924967 } ,
@@ -947,27 +990,42 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
947990 Some ( actual_e) => actual_e,
948991 None => signal ! ( e, NonConstPath )
949992 } ;
950- let ety = ety. or_else ( || const_ty. and_then ( |ty| ast_ty_to_prim_ty ( tcx, ty) ) ) ;
951- try!( eval_const_expr_partial ( tcx, const_expr, ety) )
993+ let item_hint = if let UncheckedExprNoHint = ty_hint {
994+ match const_ty {
995+ Some ( ty) => match ast_ty_to_prim_ty ( tcx, ty) {
996+ Some ( ty) => UncheckedExprHint ( ty) ,
997+ None => UncheckedExprNoHint
998+ } ,
999+ None => UncheckedExprNoHint
1000+ }
1001+ } else {
1002+ ty_hint
1003+ } ;
1004+ try!( eval_const_expr_partial ( tcx, const_expr, item_hint) )
9521005 }
9531006 ast:: ExprLit ( ref lit) => {
9541007 lit_to_const ( & * * lit, ety)
9551008 }
956- ast:: ExprParen ( ref e) => try!( eval_const_expr_partial ( tcx, & * * e, ety ) ) ,
1009+ ast:: ExprParen ( ref e) => try!( eval_const_expr_partial ( tcx, & * * e, ty_hint ) ) ,
9571010 ast:: ExprBlock ( ref block) => {
9581011 match block. expr {
959- Some ( ref expr) => try!( eval_const_expr_partial ( tcx, & * * expr, ety ) ) ,
1012+ Some ( ref expr) => try!( eval_const_expr_partial ( tcx, & * * expr, ty_hint ) ) ,
9601013 None => Int ( 0 )
9611014 }
9621015 }
9631016 ast:: ExprTup ( _) => Tuple ( e. id ) ,
9641017 ast:: ExprStruct ( ..) => Struct ( e. id ) ,
9651018 ast:: ExprTupField ( ref base, index) => {
966- if let Ok ( c) = eval_const_expr_partial ( tcx, base, None ) {
1019+ let base_hint = if let ExprTypeChecked = ty_hint {
1020+ ExprTypeChecked
1021+ } else {
1022+ UncheckedExprNoHint
1023+ } ;
1024+ if let Ok ( c) = eval_const_expr_partial ( tcx, base, base_hint) {
9671025 if let Tuple ( tup_id) = c {
9681026 if let ast:: ExprTup ( ref fields) = tcx. map . expect_expr ( tup_id) . node {
9691027 if index. node < fields. len ( ) {
970- return eval_const_expr_partial ( tcx, & fields[ index. node ] , None )
1028+ return eval_const_expr_partial ( tcx, & fields[ index. node ] , base_hint )
9711029 } else {
9721030 signal ! ( e, TupleIndexOutOfBounds ) ;
9731031 }
@@ -983,13 +1041,18 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
9831041 }
9841042 ast:: ExprField ( ref base, field_name) => {
9851043 // Get the base expression if it is a struct and it is constant
986- if let Ok ( c) = eval_const_expr_partial ( tcx, base, None ) {
1044+ let base_hint = if let ExprTypeChecked = ty_hint {
1045+ ExprTypeChecked
1046+ } else {
1047+ UncheckedExprNoHint
1048+ } ;
1049+ if let Ok ( c) = eval_const_expr_partial ( tcx, base, base_hint) {
9871050 if let Struct ( struct_id) = c {
9881051 if let ast:: ExprStruct ( _, ref fields, _) = tcx. map . expect_expr ( struct_id) . node {
9891052 // Check that the given field exists and evaluate it
9901053 if let Some ( f) = fields. iter ( ) . find ( |f| f. ident . node . as_str ( )
9911054 == field_name. node . as_str ( ) ) {
992- return eval_const_expr_partial ( tcx, & * f. expr , None )
1055+ return eval_const_expr_partial ( tcx, & * f. expr , base_hint )
9931056 } else {
9941057 signal ! ( e, MissingStructField ) ;
9951058 }
@@ -1165,21 +1228,17 @@ pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> {
11651228 } )
11661229}
11671230
1168- pub fn compare_lit_exprs < ' tcx , S > ( tcx : & ty:: ctxt < ' tcx > ,
1169- a : & Expr ,
1170- b : & Expr ,
1171- ty_hint : Option < Ty < ' tcx > > ,
1172- get_substs : S ) -> Option < Ordering >
1173- where S : Fn ( ast:: NodeId ) -> subst:: Substs < ' tcx > {
1174- let a = match eval_const_expr_with_substs ( tcx, a, ty_hint,
1175- |id| { get_substs ( id) } ) {
1231+ pub fn compare_lit_exprs < ' tcx > ( tcx : & ty:: ctxt < ' tcx > ,
1232+ a : & Expr ,
1233+ b : & Expr ) -> Option < Ordering > {
1234+ let a = match eval_const_expr_partial ( tcx, a, ExprTypeChecked ) {
11761235 Ok ( a) => a,
11771236 Err ( e) => {
11781237 tcx. sess . span_err ( a. span , & e. description ( ) ) ;
11791238 return None ;
11801239 }
11811240 } ;
1182- let b = match eval_const_expr_with_substs ( tcx, b, ty_hint , get_substs ) {
1241+ let b = match eval_const_expr_partial ( tcx, b, ExprTypeChecked ) {
11831242 Ok ( b) => b,
11841243 Err ( e) => {
11851244 tcx. sess . span_err ( b. span , & e. description ( ) ) ;
0 commit comments