@@ -39,6 +39,7 @@ use std::borrow::{Cow, IntoCow};
39
39
use std:: num:: wrapping:: OverflowingOps ;
40
40
use std:: cmp:: Ordering ;
41
41
use std:: collections:: hash_map:: Entry :: Vacant ;
42
+ use std:: collections:: HashMap ;
42
43
use std:: hash;
43
44
use std:: mem:: transmute;
44
45
use std:: { i8, i16, i32, i64, u8, u16, u32, u64} ;
@@ -253,11 +254,11 @@ pub enum ConstVal {
253
254
Str ( InternedString ) ,
254
255
ByteStr ( Rc < Vec < u8 > > ) ,
255
256
Bool ( bool ) ,
256
- Struct ( ast:: NodeId ) ,
257
- Tuple ( ast :: NodeId ) ,
257
+ Struct ( ast:: NodeId , HashMap < ast :: Name , ConstVal > ) ,
258
+ Tuple ( Vec < ConstVal > ) ,
258
259
Function ( DefId ) ,
259
- Array ( ast :: NodeId , u64 ) ,
260
- Repeat ( ast :: NodeId , u64 ) ,
260
+ Array ( Vec < ConstVal > ) ,
261
+ Repeat ( Box < ConstVal > , usize ) ,
261
262
}
262
263
263
264
impl hash:: Hash for ConstVal {
@@ -269,11 +270,16 @@ impl hash::Hash for ConstVal {
269
270
Str ( ref a) => a. hash ( state) ,
270
271
ByteStr ( ref a) => a. hash ( state) ,
271
272
Bool ( a) => a. hash ( state) ,
272
- Struct ( a) => a. hash ( state) ,
273
- Tuple ( a) => a. hash ( state) ,
273
+ Struct ( id, ref a) => {
274
+ id. hash ( state) ;
275
+ for entry in a {
276
+ entry. hash ( state) ;
277
+ }
278
+ } ,
279
+ Tuple ( ref a) => a. hash ( state) ,
274
280
Function ( a) => a. hash ( state) ,
275
- Array ( a , n ) => { a. hash ( state) ; n . hash ( state ) } ,
276
- Repeat ( a, n) => { a. hash ( state) ; n. hash ( state) } ,
281
+ Array ( ref a ) => a. hash ( state) ,
282
+ Repeat ( ref a, n) => { a. hash ( state) ; n. hash ( state) } ,
277
283
}
278
284
}
279
285
}
@@ -291,11 +297,11 @@ impl PartialEq for ConstVal {
291
297
( & Str ( ref a) , & Str ( ref b) ) => a == b,
292
298
( & ByteStr ( ref a) , & ByteStr ( ref b) ) => a == b,
293
299
( & Bool ( a) , & Bool ( b) ) => a == b,
294
- ( & Struct ( a) , & Struct ( b) ) => a == b,
295
- ( & Tuple ( a) , & Tuple ( b) ) => a == b,
300
+ ( & Struct ( id , ref a) , & Struct ( idb , ref b) ) => ( id == idb ) && ( a == b) ,
301
+ ( & Tuple ( ref a) , & Tuple ( ref b) ) => a == b,
296
302
( & Function ( a) , & Function ( b) ) => a == b,
297
- ( & Array ( a , an ) , & Array ( b , bn ) ) => ( a == b) && ( an == bn ) ,
298
- ( & Repeat ( a, an) , & Repeat ( b, bn) ) => ( a == b) && ( an == bn) ,
303
+ ( & Array ( ref a ) , & Array ( ref b ) ) => a == b,
304
+ ( & Repeat ( ref a, an) , & Repeat ( ref b, bn) ) => ( a == b) && ( an == bn) ,
299
305
_ => false ,
300
306
}
301
307
}
@@ -313,7 +319,7 @@ impl ConstVal {
313
319
Str ( _) => "string literal" ,
314
320
ByteStr ( _) => "byte string literal" ,
315
321
Bool ( _) => "boolean" ,
316
- Struct ( _ ) => "struct" ,
322
+ Struct ( .. ) => "struct" ,
317
323
Tuple ( _) => "tuple" ,
318
324
Function ( _) => "function definition" ,
319
325
Array ( ..) => "array" ,
@@ -404,6 +410,8 @@ pub enum ErrKind {
404
410
InvalidOpForUintInt ( hir:: BinOp_ ) ,
405
411
NegateOn ( ConstVal ) ,
406
412
NotOn ( ConstVal ) ,
413
+ BadStructBase ( ConstVal ) ,
414
+ ExpectedStructDef ( def:: Def ) ,
407
415
408
416
NegateWithOverflow ( i64 ) ,
409
417
AddiWithOverflow ( i64 , i64 ) ,
@@ -448,6 +456,10 @@ impl ConstEvalErr {
448
456
InvalidOpForUintInt ( ..) => "can't do this op on a usize and isize" . into_cow ( ) ,
449
457
NegateOn ( ref const_val) => format ! ( "negate on {}" , const_val. description( ) ) . into_cow ( ) ,
450
458
NotOn ( ref const_val) => format ! ( "not on {}" , const_val. description( ) ) . into_cow ( ) ,
459
+ BadStructBase ( ref const_val) =>
460
+ format ! ( "bad struct base: `{}`" , const_val. description( ) ) . into_cow ( ) ,
461
+ ExpectedStructDef ( def) =>
462
+ format ! ( "expected struct definition, got: `{:?}`" , def) . into_cow ( ) ,
451
463
452
464
NegateWithOverflow ( ..) => "attempted to negate with overflow" . into_cow ( ) ,
453
465
AddiWithOverflow ( ..) => "attempted to add with overflow" . into_cow ( ) ,
@@ -838,18 +850,23 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
838
850
}
839
851
}
840
852
hir:: ExprBinary ( op, ref a, ref b) => {
841
- let b_ty = match op. node {
842
- hir:: BiShl | hir:: BiShr => {
843
- if let ExprTypeChecked = ty_hint {
844
- ExprTypeChecked
845
- } else {
846
- UncheckedExprHint ( tcx. types . usize )
847
- }
853
+ let a = try!( eval_const_expr_partial ( tcx, & * * a, ty_hint, fn_args) ) ;
854
+ let b_ty = if let ExprTypeChecked = ty_hint {
855
+ ExprTypeChecked
856
+ } else {
857
+ match op. node {
858
+ hir:: BiShl | hir:: BiShr => UncheckedExprHint ( tcx. types . usize ) ,
859
+ _ => match a {
860
+ Int ( _) => UncheckedExprHint ( tcx. types . isize ) ,
861
+ Uint ( _) => UncheckedExprHint ( tcx. types . usize ) ,
862
+ // don't care about the other types, they don't do much arithmetics
863
+ _ => ty_hint,
864
+ } ,
848
865
}
849
- _ => ty_hint
850
866
} ;
851
- match ( try!( eval_const_expr_partial ( tcx, & * * a, ty_hint, fn_args) ) ,
852
- try!( eval_const_expr_partial ( tcx, & * * b, b_ty, fn_args) ) ) {
867
+
868
+ let b = try!( eval_const_expr_partial ( tcx, & * * b, b_ty, fn_args) ) ;
869
+ match ( a, b) {
853
870
( Float ( a) , Float ( b) ) => {
854
871
match op. node {
855
872
hir:: BiAdd => Float ( a + b) ,
@@ -1032,7 +1049,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
1032
1049
( lookup_variant_by_id ( tcx, enum_def, variant_def) , None )
1033
1050
}
1034
1051
Some ( def:: DefStruct ( _) ) => {
1035
- return Ok ( ConstVal :: Struct ( e. id ) )
1052
+ // FIXME: necessary to check if struct is a unit struct?
1053
+ return Ok ( ConstVal :: Struct ( e. id , HashMap :: new ( ) ) )
1036
1054
}
1037
1055
Some ( def:: DefLocal ( _, id) ) => {
1038
1056
debug ! ( "DefLocal({:?}): {:?}" , id, fn_args) ;
@@ -1134,9 +1152,40 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
1134
1152
None => unreachable ! ( ) ,
1135
1153
}
1136
1154
}
1137
- hir:: ExprTup ( _) => Tuple ( e. id ) ,
1138
- hir:: ExprStruct ( ..) => Struct ( e. id ) ,
1155
+ hir:: ExprTup ( ref fields) => {
1156
+ let field_hint = if let ExprTypeChecked = ty_hint {
1157
+ ExprTypeChecked
1158
+ } else {
1159
+ UncheckedExprNoHint
1160
+ } ;
1161
+ let mut fs = Vec :: with_capacity ( fields. len ( ) ) ;
1162
+ for field in fields {
1163
+ fs. push ( try!( eval_const_expr_partial ( tcx, & * * field, field_hint, fn_args) ) )
1164
+ }
1165
+ Tuple ( fs)
1166
+ } ,
1167
+ hir:: ExprStruct ( _, ref fields, ref base_opt) => {
1168
+ let mut base = if let Some ( ref base) = * base_opt {
1169
+ match try!( eval_const_expr_partial ( tcx, & * * base, ty_hint, fn_args) ) {
1170
+ Struct ( _, base) => base,
1171
+ other => signal ! ( e, BadStructBase ( other) ) ,
1172
+ }
1173
+ } else {
1174
+ HashMap :: new ( )
1175
+ } ;
1176
+ let field_hint = if let ExprTypeChecked = ty_hint {
1177
+ ExprTypeChecked
1178
+ } else {
1179
+ UncheckedExprNoHint
1180
+ } ;
1181
+ for field in fields {
1182
+ let val = try!( eval_const_expr_partial ( tcx, & * field. expr , field_hint, fn_args) ) ;
1183
+ base. insert ( field. name . node , val) ;
1184
+ }
1185
+ Struct ( e. id , base)
1186
+ } ,
1139
1187
hir:: ExprIndex ( ref arr, ref idx) => {
1188
+ //if tcx.sess.features.borrow().const_index
1140
1189
let arr_hint = if let ExprTypeChecked = ty_hint {
1141
1190
ExprTypeChecked
1142
1191
} else {
@@ -1149,26 +1198,16 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
1149
1198
UncheckedExprHint ( tcx. types . usize )
1150
1199
} ;
1151
1200
let idx = match try!( eval_const_expr_partial ( tcx, idx, idx_hint, fn_args) ) {
1152
- Int ( i) if i >= 0 => i as u64 ,
1201
+ Int ( i) if i >= 0 => i as usize ,
1153
1202
Int ( _) => signal ! ( idx, IndexNegative ) ,
1154
- Uint ( i) => i,
1203
+ Uint ( i) => i as usize ,
1155
1204
_ => signal ! ( idx, IndexNotInt ) ,
1156
1205
} ;
1157
1206
match arr {
1158
- Array ( _, n) if idx >= n => signal ! ( e, IndexOutOfBounds ) ,
1159
- Array ( v, _) => if let hir:: ExprVec ( ref v) = tcx. map . expect_expr ( v) . node {
1160
- try!( eval_const_expr_partial ( tcx, & * v[ idx as usize ] , ty_hint, fn_args) )
1161
- } else {
1162
- unreachable ! ( )
1163
- } ,
1164
-
1207
+ Array ( ref v) if idx >= v. len ( ) => signal ! ( e, IndexOutOfBounds ) ,
1208
+ Array ( v) => v[ idx as usize ] . clone ( ) ,
1165
1209
Repeat ( _, n) if idx >= n => signal ! ( e, IndexOutOfBounds ) ,
1166
- Repeat ( elem, _) => try!( eval_const_expr_partial (
1167
- tcx,
1168
- & * tcx. map . expect_expr ( elem) ,
1169
- ty_hint,
1170
- fn_args,
1171
- ) ) ,
1210
+ Repeat ( elem, _) => * elem,
1172
1211
1173
1212
ByteStr ( ref data) if idx as usize >= data. len ( )
1174
1213
=> signal ! ( e, IndexOutOfBounds ) ,
@@ -1180,19 +1219,35 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
1180
1219
_ => signal ! ( e, IndexedNonVec ) ,
1181
1220
}
1182
1221
}
1183
- hir:: ExprVec ( ref v) => Array ( e. id , v. len ( ) as u64 ) ,
1184
- hir:: ExprRepeat ( _, ref n) => {
1222
+ hir:: ExprVec ( ref v) => {
1223
+ let hint = if let ExprTypeChecked = ty_hint {
1224
+ ExprTypeChecked
1225
+ } else {
1226
+ UncheckedExprNoHint
1227
+ } ;
1228
+ let mut fs = Vec :: with_capacity ( v. len ( ) ) ;
1229
+ for val in v {
1230
+ fs. push ( try!( eval_const_expr_partial ( tcx, & * * val, hint, fn_args) ) )
1231
+ }
1232
+ Array ( fs)
1233
+ }
1234
+ hir:: ExprRepeat ( ref val, ref n) => {
1185
1235
let len_hint = if let ExprTypeChecked = ty_hint {
1186
1236
ExprTypeChecked
1187
1237
} else {
1188
1238
UncheckedExprHint ( tcx. types . usize )
1189
1239
} ;
1240
+ let val_hint = if let ExprTypeChecked = ty_hint {
1241
+ ExprTypeChecked
1242
+ } else {
1243
+ UncheckedExprNoHint
1244
+ } ;
1190
1245
Repeat (
1191
- e . id ,
1246
+ box try! ( eval_const_expr_partial ( tcx , & * * val , val_hint , fn_args ) ) ,
1192
1247
match try!( eval_const_expr_partial ( tcx, & * * n, len_hint, fn_args) ) {
1193
- Int ( i) if i >= 0 => i as u64 ,
1248
+ Int ( i) if i >= 0 => i as usize ,
1194
1249
Int ( _) => signal ! ( e, RepeatCountNotNatural ) ,
1195
- Uint ( i) => i,
1250
+ Uint ( i) => i as usize ,
1196
1251
_ => signal ! ( e, RepeatCountNotInt ) ,
1197
1252
} ,
1198
1253
)
@@ -1203,22 +1258,15 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
1203
1258
} else {
1204
1259
UncheckedExprNoHint
1205
1260
} ;
1206
- if let Ok ( c) = eval_const_expr_partial ( tcx, base, base_hint, fn_args) {
1207
- if let Tuple ( tup_id) = c {
1208
- if let hir:: ExprTup ( ref fields) = tcx. map . expect_expr ( tup_id) . node {
1209
- if index. node < fields. len ( ) {
1210
- return eval_const_expr_partial ( tcx, & fields[ index. node ] , base_hint, fn_args)
1211
- } else {
1212
- signal ! ( e, TupleIndexOutOfBounds ) ;
1213
- }
1214
- } else {
1215
- unreachable ! ( )
1216
- }
1261
+ let c = try!( eval_const_expr_partial ( tcx, base, base_hint, fn_args) ) ;
1262
+ if let Tuple ( fields) = c {
1263
+ if index. node < fields. len ( ) {
1264
+ fields[ index. node ] . clone ( )
1217
1265
} else {
1218
- signal ! ( base , ExpectedConstTuple ) ;
1266
+ signal ! ( e , TupleIndexOutOfBounds ) ;
1219
1267
}
1220
1268
} else {
1221
- signal ! ( base, NonConstPath )
1269
+ signal ! ( base, ExpectedConstTuple ) ;
1222
1270
}
1223
1271
}
1224
1272
hir:: ExprField ( ref base, field_name) => {
@@ -1228,25 +1276,16 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
1228
1276
} else {
1229
1277
UncheckedExprNoHint
1230
1278
} ;
1231
- if let Ok ( c) = eval_const_expr_partial ( tcx, base, base_hint, fn_args) {
1232
- if let Struct ( struct_id) = c {
1233
- if let hir:: ExprStruct ( _, ref fields, _) = tcx. map . expect_expr ( struct_id) . node {
1234
- // Check that the given field exists and evaluate it
1235
- // if the idents are compared run-pass/issue-19244 fails
1236
- if let Some ( f) = fields. iter ( ) . find ( |f| f. name . node
1237
- == field_name. node ) {
1238
- return eval_const_expr_partial ( tcx, & * f. expr , base_hint, fn_args)
1239
- } else {
1240
- signal ! ( e, MissingStructField ) ;
1241
- }
1242
- } else {
1243
- unreachable ! ( )
1244
- }
1279
+ let c = try!( eval_const_expr_partial ( tcx, base, base_hint, fn_args) ) ;
1280
+ if let Struct ( _, mut fields) = c {
1281
+ if let Some ( f) = fields. remove ( & field_name. node ) {
1282
+ f
1245
1283
} else {
1246
- signal ! ( base, ExpectedConstStruct ) ;
1284
+ // FIXME: is this unreachable?
1285
+ signal ! ( e, MissingStructField ) ;
1247
1286
}
1248
1287
} else {
1249
- signal ! ( base, NonConstPath ) ;
1288
+ signal ! ( base, ExpectedConstStruct ) ;
1250
1289
}
1251
1290
}
1252
1291
_ => signal ! ( e, MiscCatchAll )
0 commit comments