1111#![ allow( non_camel_case_types) ]
1212
1313use self :: ConstVal :: * ;
14-
1514use self :: ErrKind :: * ;
15+ use self :: EvalHint :: * ;
1616
1717use ast_map;
1818use ast_map:: blocks:: FnLikeNode ;
@@ -345,7 +345,7 @@ pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P<ast::Pat>
345345}
346346
347347pub fn eval_const_expr ( tcx : & ty:: ctxt , e : & Expr ) -> ConstVal {
348- match eval_const_expr_partial ( tcx, e, None ) {
348+ match eval_const_expr_partial ( tcx, e, ExprTypeChecked ) {
349349 Ok ( r) => r,
350350 Err ( s) => tcx. sess . span_fatal ( s. span , & s. description ( ) )
351351 }
@@ -434,6 +434,28 @@ impl ConstEvalErr {
434434pub type EvalResult = Result < ConstVal , ConstEvalErr > ;
435435pub type CastResult = Result < ConstVal , ErrKind > ;
436436
437+ // FIXME: Long-term, this enum should go away: trying to evaluate
438+ // an expression which hasn't been type-checked is a recipe for
439+ // disaster. That said, it's not clear how to fix ast_ty_to_ty
440+ // to avoid the ordering issue.
441+
442+ /// Hint to determine how to evaluate constant expressions which
443+ /// might not be type-checked.
444+ #[ derive( Copy , Clone , Debug ) ]
445+ pub enum EvalHint < ' tcx > {
446+ /// We have a type-checked expression.
447+ ExprTypeChecked ,
448+ /// We have an expression which hasn't been type-checked, but we have
449+ /// an idea of what the type will be because of the context. For example,
450+ /// the length of an array is always `usize`. (This is referred to as
451+ /// a hint because it isn't guaranteed to be consistent with what
452+ /// type-checking would compute.)
453+ UncheckedExprHint ( Ty < ' tcx > ) ,
454+ /// We have an expression which has not yet been type-checked, and
455+ /// and we have no clue what the type will be.
456+ UncheckedExprNoHint ,
457+ }
458+
437459#[ derive( Copy , Clone , PartialEq , Debug ) ]
438460pub enum IntTy { I8 , I16 , I32 , I64 }
439461#[ derive( Copy , Clone , PartialEq , Debug ) ]
@@ -704,26 +726,34 @@ pub_fn_checked_op!{ const_uint_checked_shr_via_int(a: u64, b: i64,.. UintTy) {
704726 uint_shift_body overflowing_shr Uint ShiftRightWithOverflow
705727} }
706728
707- // After type checking, `eval_const_expr_partial` should always suffice. The
708- // reason for providing `eval_const_expr_with_substs ` is to allow
709- // trait-associated consts to be evaluated * during* type checking, when the
710- // substs for each expression have not been written into `tcx` yet.
729+ /// Evaluate a constant expression in a context where the expression isn't
730+ /// guaranteed to be evaluatable. `ty_hint ` is usually ExprTypeChecked,
731+ /// but a few places need to evaluate constants during type- checking, like
732+ /// computing the length of an array. (See also the FIXME above EvalHint.)
711733pub fn eval_const_expr_partial < ' tcx > ( tcx : & ty:: ctxt < ' tcx > ,
712734 e : & Expr ,
713- ty_hint : Option < Ty < ' tcx > > ) -> EvalResult {
714- eval_const_expr_with_substs ( tcx, e, ty_hint, |id| {
715- tcx. node_id_item_substs ( id) . substs
716- } )
717- }
718-
719- pub fn eval_const_expr_with_substs < ' tcx , S > ( tcx : & ty:: ctxt < ' tcx > ,
720- e : & Expr ,
721- ty_hint : Option < Ty < ' tcx > > ,
722- get_substs : S ) -> EvalResult
723- where S : Fn ( ast:: NodeId ) -> subst:: Substs < ' tcx > {
735+ ty_hint : EvalHint < ' tcx > ) -> EvalResult {
724736 fn fromb ( b : bool ) -> ConstVal { Int ( b as i64 ) }
725737
726- let ety = ty_hint. or_else ( || tcx. expr_ty_opt ( e) ) ;
738+ // Try to compute the type of the expression based on the EvalHint.
739+ // (See also the definition of EvalHint, and the FIXME above EvalHint.)
740+ let ety = match ty_hint {
741+ ExprTypeChecked => {
742+ // After type-checking, expr_ty is guaranteed to succeed.
743+ Some ( tcx. expr_ty ( e) )
744+ }
745+ UncheckedExprHint ( ty) => {
746+ // Use the type hint; it's not guaranteed to be right, but it's
747+ // usually good enough.
748+ Some ( ty)
749+ }
750+ UncheckedExprNoHint => {
751+ // This expression might not be type-checked, and we have no hint.
752+ // Try to query the context for a type anyway; we might get lucky
753+ // (for example, if the expression was imported from another crate).
754+ tcx. expr_ty_opt ( e)
755+ }
756+ } ;
727757
728758 // If type of expression itself is int or uint, normalize in these
729759 // bindings so that isize/usize is mapped to a type with an
@@ -739,7 +769,7 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
739769
740770 let result = match e. node {
741771 ast:: ExprUnary ( ast:: UnNeg , ref inner) => {
742- match try!( eval_const_expr_partial ( tcx, & * * inner, ety ) ) {
772+ match try!( eval_const_expr_partial ( tcx, & * * inner, ty_hint ) ) {
743773 Float ( f) => Float ( -f) ,
744774 Int ( n) => try!( const_int_checked_neg ( n, e, expr_int_type) ) ,
745775 Uint ( i) => {
@@ -749,7 +779,7 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
749779 }
750780 }
751781 ast:: ExprUnary ( ast:: UnNot , ref inner) => {
752- match try!( eval_const_expr_partial ( tcx, & * * inner, ety ) ) {
782+ match try!( eval_const_expr_partial ( tcx, & * * inner, ty_hint ) ) {
753783 Int ( i) => Int ( !i) ,
754784 Uint ( i) => const_uint_not ( i, expr_uint_type) ,
755785 Bool ( b) => Bool ( !b) ,
@@ -758,10 +788,16 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
758788 }
759789 ast:: ExprBinary ( op, ref a, ref b) => {
760790 let b_ty = match op. node {
761- ast:: BiShl | ast:: BiShr => Some ( tcx. types . usize ) ,
762- _ => ety
791+ ast:: BiShl | ast:: BiShr => {
792+ if let ExprTypeChecked = ty_hint {
793+ ExprTypeChecked
794+ } else {
795+ UncheckedExprHint ( tcx. types . usize )
796+ }
797+ }
798+ _ => ty_hint
763799 } ;
764- match ( try!( eval_const_expr_partial ( tcx, & * * a, ety ) ) ,
800+ match ( try!( eval_const_expr_partial ( tcx, & * * a, ty_hint ) ) ,
765801 try!( eval_const_expr_partial ( tcx, & * * b, b_ty) ) ) {
766802 ( Float ( a) , Float ( b) ) => {
767803 match op. node {
@@ -851,22 +887,25 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
851887 }
852888 }
853889 ast:: ExprCast ( ref base, ref target_ty) => {
854- // This tends to get called w/o the type actually having been
855- // populated in the ctxt, which was causing things to blow up
856- // (#5900). Fall back to doing a limited lookup to get past it.
857890 let ety = ety. or_else ( || ast_ty_to_prim_ty ( tcx, & * * target_ty) )
858891 . unwrap_or_else ( || {
859892 tcx. sess . span_fatal ( target_ty. span ,
860893 "target type not found for const cast" )
861894 } ) ;
862895
863- // Prefer known type to noop, but always have a type hint.
864- //
865- // FIXME (#23833): the type-hint can cause problems,
866- // e.g. `(i8::MAX + 1_i8) as u32` feeds in `u32` as result
867- // type to the sum, and thus no overflow is signaled.
868- let base_hint = tcx. expr_ty_opt ( & * * base) . unwrap_or ( ety) ;
869- let val = try!( eval_const_expr_partial ( tcx, & * * base, Some ( base_hint) ) ) ;
896+ let base_hint = if let ExprTypeChecked = ty_hint {
897+ ExprTypeChecked
898+ } else {
899+ // FIXME (#23833): the type-hint can cause problems,
900+ // e.g. `(i8::MAX + 1_i8) as u32` feeds in `u32` as result
901+ // type to the sum, and thus no overflow is signaled.
902+ match tcx. expr_ty_opt ( & base) {
903+ Some ( t) => UncheckedExprHint ( t) ,
904+ None => ty_hint
905+ }
906+ } ;
907+
908+ let val = try!( eval_const_expr_partial ( tcx, & * * base, base_hint) ) ;
870909 match cast_const ( tcx, val, ety) {
871910 Ok ( val) => val,
872911 Err ( kind) => return Err ( ConstEvalErr { span : e. span , kind : kind } ) ,
@@ -896,12 +935,16 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
896935 def:: FromTrait ( trait_id) => match tcx. map . find ( def_id. node ) {
897936 Some ( ast_map:: NodeTraitItem ( ti) ) => match ti. node {
898937 ast:: ConstTraitItem ( ref ty, _) => {
899- let substs = get_substs ( e. id ) ;
900- ( resolve_trait_associated_const ( tcx,
901- ti,
902- trait_id,
903- substs) ,
904- Some ( & * * ty) )
938+ if let ExprTypeChecked = ty_hint {
939+ let substs = tcx. node_id_item_substs ( e. id ) . substs ;
940+ ( resolve_trait_associated_const ( tcx,
941+ ti,
942+ trait_id,
943+ substs) ,
944+ Some ( & * * ty) )
945+ } else {
946+ ( None , None )
947+ }
905948 }
906949 _ => ( None , None )
907950 } ,
@@ -930,27 +973,42 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
930973 Some ( actual_e) => actual_e,
931974 None => signal ! ( e, NonConstPath )
932975 } ;
933- let ety = ety. or_else ( || const_ty. and_then ( |ty| ast_ty_to_prim_ty ( tcx, ty) ) ) ;
934- try!( eval_const_expr_partial ( tcx, const_expr, ety) )
976+ let item_hint = if let UncheckedExprNoHint = ty_hint {
977+ match const_ty {
978+ Some ( ty) => match ast_ty_to_prim_ty ( tcx, ty) {
979+ Some ( ty) => UncheckedExprHint ( ty) ,
980+ None => UncheckedExprNoHint
981+ } ,
982+ None => UncheckedExprNoHint
983+ }
984+ } else {
985+ ty_hint
986+ } ;
987+ try!( eval_const_expr_partial ( tcx, const_expr, item_hint) )
935988 }
936989 ast:: ExprLit ( ref lit) => {
937990 lit_to_const ( & * * lit, ety)
938991 }
939- ast:: ExprParen ( ref e) => try!( eval_const_expr_partial ( tcx, & * * e, ety ) ) ,
992+ ast:: ExprParen ( ref e) => try!( eval_const_expr_partial ( tcx, & * * e, ty_hint ) ) ,
940993 ast:: ExprBlock ( ref block) => {
941994 match block. expr {
942- Some ( ref expr) => try!( eval_const_expr_partial ( tcx, & * * expr, ety ) ) ,
995+ Some ( ref expr) => try!( eval_const_expr_partial ( tcx, & * * expr, ty_hint ) ) ,
943996 None => Int ( 0 )
944997 }
945998 }
946999 ast:: ExprTup ( _) => Tuple ( e. id ) ,
9471000 ast:: ExprStruct ( ..) => Struct ( e. id ) ,
9481001 ast:: ExprTupField ( ref base, index) => {
949- if let Ok ( c) = eval_const_expr_partial ( tcx, base, None ) {
1002+ let base_hint = if let ExprTypeChecked = ty_hint {
1003+ ExprTypeChecked
1004+ } else {
1005+ UncheckedExprNoHint
1006+ } ;
1007+ if let Ok ( c) = eval_const_expr_partial ( tcx, base, base_hint) {
9501008 if let Tuple ( tup_id) = c {
9511009 if let ast:: ExprTup ( ref fields) = tcx. map . expect_expr ( tup_id) . node {
9521010 if index. node < fields. len ( ) {
953- return eval_const_expr_partial ( tcx, & fields[ index. node ] , None )
1011+ return eval_const_expr_partial ( tcx, & fields[ index. node ] , base_hint )
9541012 } else {
9551013 signal ! ( e, TupleIndexOutOfBounds ) ;
9561014 }
@@ -966,13 +1024,18 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
9661024 }
9671025 ast:: ExprField ( ref base, field_name) => {
9681026 // Get the base expression if it is a struct and it is constant
969- if let Ok ( c) = eval_const_expr_partial ( tcx, base, None ) {
1027+ let base_hint = if let ExprTypeChecked = ty_hint {
1028+ ExprTypeChecked
1029+ } else {
1030+ UncheckedExprNoHint
1031+ } ;
1032+ if let Ok ( c) = eval_const_expr_partial ( tcx, base, base_hint) {
9701033 if let Struct ( struct_id) = c {
9711034 if let ast:: ExprStruct ( _, ref fields, _) = tcx. map . expect_expr ( struct_id) . node {
9721035 // Check that the given field exists and evaluate it
9731036 if let Some ( f) = fields. iter ( ) . find ( |f| f. ident . node . as_str ( )
9741037 == field_name. node . as_str ( ) ) {
975- return eval_const_expr_partial ( tcx, & * f. expr , None )
1038+ return eval_const_expr_partial ( tcx, & * f. expr , base_hint )
9761039 } else {
9771040 signal ! ( e, MissingStructField ) ;
9781041 }
@@ -1148,21 +1211,17 @@ pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> {
11481211 } )
11491212}
11501213
1151- pub fn compare_lit_exprs < ' tcx , S > ( tcx : & ty:: ctxt < ' tcx > ,
1152- a : & Expr ,
1153- b : & Expr ,
1154- ty_hint : Option < Ty < ' tcx > > ,
1155- get_substs : S ) -> Option < Ordering >
1156- where S : Fn ( ast:: NodeId ) -> subst:: Substs < ' tcx > {
1157- let a = match eval_const_expr_with_substs ( tcx, a, ty_hint,
1158- |id| { get_substs ( id) } ) {
1214+ pub fn compare_lit_exprs < ' tcx > ( tcx : & ty:: ctxt < ' tcx > ,
1215+ a : & Expr ,
1216+ b : & Expr ) -> Option < Ordering > {
1217+ let a = match eval_const_expr_partial ( tcx, a, ExprTypeChecked ) {
11591218 Ok ( a) => a,
11601219 Err ( e) => {
11611220 tcx. sess . span_err ( a. span , & e. description ( ) ) ;
11621221 return None ;
11631222 }
11641223 } ;
1165- let b = match eval_const_expr_with_substs ( tcx, b, ty_hint , get_substs ) {
1224+ let b = match eval_const_expr_partial ( tcx, b, ExprTypeChecked ) {
11661225 Ok ( b) => b,
11671226 Err ( e) => {
11681227 tcx. sess . span_err ( b. span , & e. description ( ) ) ;
0 commit comments