@@ -17,7 +17,7 @@ use metadata::csearch;
17
17
use middle:: { astencode, def} ;
18
18
use middle:: pat_util:: def_to_path;
19
19
use middle:: ty:: { self , Ty } ;
20
- use middle:: astconv_util:: { ast_ty_to_prim_ty} ;
20
+ use middle:: astconv_util:: ast_ty_to_prim_ty;
21
21
22
22
use syntax:: ast:: { self , Expr } ;
23
23
use syntax:: codemap:: Span ;
@@ -132,16 +132,16 @@ pub fn lookup_const_by_id<'a>(tcx: &'a ty::ctxt, def_id: ast::DefId)
132
132
}
133
133
}
134
134
135
- // FIXME (#33): this doesn't handle big integer/float literals correctly
136
- // (nor does the rest of our literal handling).
137
135
#[ derive( Clone , PartialEq ) ]
138
136
pub enum const_val {
139
137
const_float( f64 ) ,
140
138
const_int( i64 ) ,
141
139
const_uint( u64 ) ,
142
140
const_str( InternedString ) ,
143
- const_binary( Rc < Vec < u8 > > ) ,
144
- const_bool( bool )
141
+ const_binary( Rc < Vec < u8 > > ) ,
142
+ const_bool( bool ) ,
143
+ Struct ( ast:: NodeId ) ,
144
+ Tuple ( ast:: NodeId )
145
145
}
146
146
147
147
pub fn const_expr_to_pat ( tcx : & ty:: ctxt , expr : & Expr , span : Span ) -> P < ast:: Pat > {
@@ -226,9 +226,13 @@ pub enum ErrKind {
226
226
NegateOnString ,
227
227
NegateOnBoolean ,
228
228
NegateOnBinary ,
229
+ NegateOnStruct ,
230
+ NegateOnTuple ,
229
231
NotOnFloat ,
230
232
NotOnString ,
231
233
NotOnBinary ,
234
+ NotOnStruct ,
235
+ NotOnTuple ,
232
236
233
237
AddiWithOverflow ( i64 , i64 ) ,
234
238
SubiWithOverflow ( i64 , i64 ) ,
@@ -242,7 +246,8 @@ pub enum ErrKind {
242
246
ModuloWithOverflow ,
243
247
MissingStructField ,
244
248
NonConstPath ,
245
- NonConstStruct ,
249
+ ExpectedConstTuple ,
250
+ ExpectedConstStruct ,
246
251
TupleIndexOutOfBounds ,
247
252
248
253
MiscBinaryOp ,
@@ -262,9 +267,13 @@ impl ConstEvalErr {
262
267
NegateOnString => "negate on string" . into_cow ( ) ,
263
268
NegateOnBoolean => "negate on boolean" . into_cow ( ) ,
264
269
NegateOnBinary => "negate on binary literal" . into_cow ( ) ,
270
+ NegateOnStruct => "negate on struct" . into_cow ( ) ,
271
+ NegateOnTuple => "negate on tuple" . into_cow ( ) ,
265
272
NotOnFloat => "not on float or string" . into_cow ( ) ,
266
273
NotOnString => "not on float or string" . into_cow ( ) ,
267
274
NotOnBinary => "not on binary literal" . into_cow ( ) ,
275
+ NotOnStruct => "not on struct" . into_cow ( ) ,
276
+ NotOnTuple => "not on tuple" . into_cow ( ) ,
268
277
269
278
AddiWithOverflow ( ..) => "attempted to add with overflow" . into_cow ( ) ,
270
279
SubiWithOverflow ( ..) => "attempted to sub with overflow" . into_cow ( ) ,
@@ -278,7 +287,8 @@ impl ConstEvalErr {
278
287
ModuloWithOverflow => "attempted remainder with overflow" . into_cow ( ) ,
279
288
MissingStructField => "nonexistent struct field" . into_cow ( ) ,
280
289
NonConstPath => "non-constant path in constant expr" . into_cow ( ) ,
281
- NonConstStruct => "non-constant struct in constant expr" . into_cow ( ) ,
290
+ ExpectedConstTuple => "expected constant tuple" . into_cow ( ) ,
291
+ ExpectedConstStruct => "expected constant struct" . into_cow ( ) ,
282
292
TupleIndexOutOfBounds => "tuple index out of bounds" . into_cow ( ) ,
283
293
284
294
MiscBinaryOp => "bad operands for binary" . into_cow ( ) ,
@@ -341,6 +351,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
341
351
const_str( _) => signal ! ( e, NegateOnString ) ,
342
352
const_bool( _) => signal ! ( e, NegateOnBoolean ) ,
343
353
const_binary( _) => signal ! ( e, NegateOnBinary ) ,
354
+ const_val:: Tuple ( _) => signal ! ( e, NegateOnTuple ) ,
355
+ const_val:: Struct ( ..) => signal ! ( e, NegateOnStruct ) ,
344
356
}
345
357
}
346
358
ast:: ExprUnary ( ast:: UnNot , ref inner) => {
@@ -351,6 +363,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
351
363
const_str( _) => signal ! ( e, NotOnString ) ,
352
364
const_float( _) => signal ! ( e, NotOnFloat ) ,
353
365
const_binary( _) => signal ! ( e, NotOnBinary ) ,
366
+ const_val:: Tuple ( _) => signal ! ( e, NotOnTuple ) ,
367
+ const_val:: Struct ( ..) => signal ! ( e, NotOnStruct ) ,
354
368
}
355
369
}
356
370
ast:: ExprBinary ( op, ref a, ref b) => {
@@ -540,33 +554,52 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
540
554
None => const_int ( 0 )
541
555
}
542
556
}
557
+ ast:: ExprTup ( _) => {
558
+ const_val:: Tuple ( e. id )
559
+ }
560
+ ast:: ExprStruct ( ..) => {
561
+ const_val:: Struct ( e. id )
562
+ }
543
563
ast:: ExprTupField ( ref base, index) => {
544
- // Get the base tuple if it is constant
545
- if let Some ( & ast:: ExprTup ( ref fields) ) = lookup_const ( tcx, & * * base) . map ( |s| & s. node ) {
546
- // Check that the given index is within bounds and evaluate its value
547
- if fields. len ( ) > index. node {
548
- return eval_const_expr_partial ( tcx, & * fields[ index. node ] , None ) ;
564
+ if let Ok ( c) = eval_const_expr_partial ( tcx, base, None ) {
565
+ if let const_val:: Tuple ( tup_id) = c {
566
+ if let ast:: ExprTup ( ref fields) = tcx. map . expect_expr ( tup_id) . node {
567
+ if index. node < fields. len ( ) {
568
+ return eval_const_expr_partial ( tcx, & fields[ index. node ] , None )
569
+ } else {
570
+ signal ! ( e, TupleIndexOutOfBounds ) ;
571
+ }
572
+ } else {
573
+ unreachable ! ( )
574
+ }
549
575
} else {
550
- signal ! ( e , TupleIndexOutOfBounds ) ;
576
+ signal ! ( base , ExpectedConstTuple ) ;
551
577
}
578
+ } else {
579
+ signal ! ( base, NonConstPath )
552
580
}
553
-
554
- signal ! ( e, NonConstStruct ) ;
555
581
}
556
582
ast:: ExprField ( ref base, field_name) => {
557
583
// Get the base expression if it is a struct and it is constant
558
- if let Some ( & ast:: ExprStruct ( _, ref fields, _) ) = lookup_const ( tcx, & * * base)
559
- . map ( |s| & s. node ) {
560
- // Check that the given field exists and evaluate it
561
- if let Some ( f) = fields. iter ( ) . find ( |f|
562
- f. ident . node . as_str ( ) == field_name. node . as_str ( ) ) {
563
- return eval_const_expr_partial ( tcx, & * f. expr , None ) ;
584
+ if let Ok ( c) = eval_const_expr_partial ( tcx, base, None ) {
585
+ if let const_val:: Struct ( struct_id) = c {
586
+ if let ast:: ExprStruct ( _, ref fields, _) = tcx. map . expect_expr ( struct_id) . node {
587
+ // Check that the given field exists and evaluate it
588
+ if let Some ( f) = fields. iter ( ) . find ( |f| f. ident . node . as_str ( )
589
+ == field_name. node . as_str ( ) ) {
590
+ return eval_const_expr_partial ( tcx, & * f. expr , None )
591
+ } else {
592
+ signal ! ( e, MissingStructField ) ;
593
+ }
594
+ } else {
595
+ unreachable ! ( )
596
+ }
564
597
} else {
565
- signal ! ( e , MissingStructField ) ;
598
+ signal ! ( base , ExpectedConstStruct ) ;
566
599
}
600
+ } else {
601
+ signal ! ( base, NonConstPath ) ;
567
602
}
568
-
569
- signal ! ( e, NonConstStruct ) ;
570
603
}
571
604
_ => signal ! ( e, MiscCatchAll )
572
605
} ;
0 commit comments