Skip to content

Commit 7237268

Browse files
committed
Allow enum discriminator exprs to refer to declared consts
Also some work towards #3521 Closes #2428
1 parent f6211ab commit 7237268

File tree

6 files changed

+215
-115
lines changed

6 files changed

+215
-115
lines changed

src/libsyntax/visit.rs

+2
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ fn visit_enum_def<E>(enum_definition: ast::enum_def, tps: ~[ast::ty_param],
182182
visit_enum_def(enum_definition, tps, e, v);
183183
}
184184
}
185+
// Visit the disr expr if it exists
186+
vr.node.disr_expr.iter(|ex| v.visit_expr(*ex, e, v));
185187
}
186188
}
187189

src/rustc/middle/const_eval.rs

+124-96
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use syntax::{ast,ast_util,visit};
1+
use syntax::{ast,ast_map,ast_util,visit};
22
use ast::*;
33

44
//
@@ -135,28 +135,7 @@ fn classify(e: @expr,
135135
// FIXME: (#3728) we can probably do something CCI-ish
136136
// surrounding nonlocal constants. But we don't yet.
137137
ast::expr_path(_) => {
138-
match def_map.find(e.id) {
139-
Some(ast::def_const(def_id)) => {
140-
if ast_util::is_local(def_id) {
141-
let ty = ty::expr_ty(tcx, e);
142-
if ty::type_is_integral(ty) {
143-
integral_const
144-
} else {
145-
general_const
146-
}
147-
} else {
148-
non_const
149-
}
150-
}
151-
Some(_) => {
152-
non_const
153-
}
154-
None => {
155-
tcx.sess.span_bug(e.span,
156-
~"unknown path when \
157-
classifying constants");
158-
}
159-
}
138+
lookup_constness(tcx, e)
160139
}
161140

162141
_ => non_const
@@ -167,6 +146,40 @@ fn classify(e: @expr,
167146
}
168147
}
169148

149+
fn lookup_const(tcx: ty::ctxt, e: @expr) -> Option<@expr> {
150+
match tcx.def_map.find(e.id) {
151+
Some(ast::def_const(def_id)) => {
152+
if ast_util::is_local(def_id) {
153+
match tcx.items.find(def_id.node) {
154+
None => None,
155+
Some(ast_map::node_item(it, _)) => match it.node {
156+
item_const(_, const_expr) => Some(const_expr),
157+
_ => None
158+
},
159+
Some(_) => None
160+
}
161+
}
162+
else { None }
163+
}
164+
Some(_) => None,
165+
None => None
166+
}
167+
}
168+
169+
fn lookup_constness(tcx: ty::ctxt, e: @expr) -> constness {
170+
match lookup_const(tcx, e) {
171+
Some(rhs) => {
172+
let ty = ty::expr_ty(tcx, rhs);
173+
if ty::type_is_integral(ty) {
174+
integral_const
175+
} else {
176+
general_const
177+
}
178+
}
179+
None => non_const
180+
}
181+
}
182+
170183
fn process_crate(crate: @ast::crate,
171184
def_map: resolve::DefMap,
172185
tcx: ty::ctxt) {
@@ -204,58 +217,67 @@ impl const_val : cmp::Eq {
204217
pure fn ne(other: &const_val) -> bool { !self.eq(other) }
205218
}
206219

207-
// FIXME: issue #1417
208220
fn eval_const_expr(tcx: middle::ty::ctxt, e: @expr) -> const_val {
221+
match eval_const_expr_partial(tcx, e) {
222+
Ok(r) => r,
223+
Err(s) => fail s
224+
}
225+
}
226+
227+
fn eval_const_expr_partial(tcx: middle::ty::ctxt, e: @expr)
228+
-> Result<const_val, ~str> {
209229
use middle::ty;
210-
fn fromb(b: bool) -> const_val { const_int(b as i64) }
230+
fn fromb(b: bool) -> Result<const_val, ~str> { Ok(const_int(b as i64)) }
211231
match e.node {
212232
expr_unary(neg, inner) => {
213-
match eval_const_expr(tcx, inner) {
214-
const_float(f) => const_float(-f),
215-
const_int(i) => const_int(-i),
216-
const_uint(i) => const_uint(-i),
217-
const_str(_) => fail ~"Negate on string",
218-
const_bool(_) => fail ~"Negate on boolean"
233+
match eval_const_expr_partial(tcx, inner) {
234+
Ok(const_float(f)) => Ok(const_float(-f)),
235+
Ok(const_int(i)) => Ok(const_int(-i)),
236+
Ok(const_uint(i)) => Ok(const_uint(-i)),
237+
Ok(const_str(_)) => Err(~"Negate on string"),
238+
Ok(const_bool(_)) => Err(~"Negate on boolean"),
239+
err => err
219240
}
220241
}
221242
expr_unary(not, inner) => {
222-
match eval_const_expr(tcx, inner) {
223-
const_int(i) => const_int(!i),
224-
const_uint(i) => const_uint(!i),
225-
const_bool(b) => const_bool(!b),
226-
_ => fail ~"Not on float or string"
243+
match eval_const_expr_partial(tcx, inner) {
244+
Ok(const_int(i)) => Ok(const_int(!i)),
245+
Ok(const_uint(i)) => Ok(const_uint(!i)),
246+
Ok(const_bool(b)) => Ok(const_bool(!b)),
247+
_ => Err(~"Not on float or string")
227248
}
228249
}
229250
expr_binary(op, a, b) => {
230-
match (eval_const_expr(tcx, a), eval_const_expr(tcx, b)) {
231-
(const_float(a), const_float(b)) => {
251+
match (eval_const_expr_partial(tcx, a),
252+
eval_const_expr_partial(tcx, b)) {
253+
(Ok(const_float(a)), Ok(const_float(b))) => {
232254
match op {
233-
add => const_float(a + b),
234-
subtract => const_float(a - b),
235-
mul => const_float(a * b),
236-
div => const_float(a / b),
237-
rem => const_float(a % b),
255+
add => Ok(const_float(a + b)),
256+
subtract => Ok(const_float(a - b)),
257+
mul => Ok(const_float(a * b)),
258+
div => Ok(const_float(a / b)),
259+
rem => Ok(const_float(a % b)),
238260
eq => fromb(a == b),
239261
lt => fromb(a < b),
240262
le => fromb(a <= b),
241263
ne => fromb(a != b),
242264
ge => fromb(a >= b),
243265
gt => fromb(a > b),
244-
_ => fail ~"Can't do this op on floats"
266+
_ => Err(~"Can't do this op on floats")
245267
}
246268
}
247-
(const_int(a), const_int(b)) => {
269+
(Ok(const_int(a)), Ok(const_int(b))) => {
248270
match op {
249-
add => const_int(a + b),
250-
subtract => const_int(a - b),
251-
mul => const_int(a * b),
252-
div => const_int(a / b),
253-
rem => const_int(a % b),
254-
and | bitand => const_int(a & b),
255-
or | bitor => const_int(a | b),
256-
bitxor => const_int(a ^ b),
257-
shl => const_int(a << b),
258-
shr => const_int(a >> b),
271+
add => Ok(const_int(a + b)),
272+
subtract => Ok(const_int(a - b)),
273+
mul => Ok(const_int(a * b)),
274+
div => Ok(const_int(a / b)),
275+
rem => Ok(const_int(a % b)),
276+
and | bitand => Ok(const_int(a & b)),
277+
or | bitor => Ok(const_int(a | b)),
278+
bitxor => Ok(const_int(a ^ b)),
279+
shl => Ok(const_int(a << b)),
280+
shr => Ok(const_int(a >> b)),
259281
eq => fromb(a == b),
260282
lt => fromb(a < b),
261283
le => fromb(a <= b),
@@ -264,18 +286,18 @@ fn eval_const_expr(tcx: middle::ty::ctxt, e: @expr) -> const_val {
264286
gt => fromb(a > b)
265287
}
266288
}
267-
(const_uint(a), const_uint(b)) => {
289+
(Ok(const_uint(a)), Ok(const_uint(b))) => {
268290
match op {
269-
add => const_uint(a + b),
270-
subtract => const_uint(a - b),
271-
mul => const_uint(a * b),
272-
div => const_uint(a / b),
273-
rem => const_uint(a % b),
274-
and | bitand => const_uint(a & b),
275-
or | bitor => const_uint(a | b),
276-
bitxor => const_uint(a ^ b),
277-
shl => const_uint(a << b),
278-
shr => const_uint(a >> b),
291+
add => Ok(const_uint(a + b)),
292+
subtract => Ok(const_uint(a - b)),
293+
mul => Ok(const_uint(a * b)),
294+
div => Ok(const_uint(a / b)),
295+
rem => Ok(const_uint(a % b)),
296+
and | bitand => Ok(const_uint(a & b)),
297+
or | bitor => Ok(const_uint(a | b)),
298+
bitxor => Ok(const_uint(a ^ b)),
299+
shl => Ok(const_uint(a << b)),
300+
shr => Ok(const_uint(a >> b)),
279301
eq => fromb(a == b),
280302
lt => fromb(a < b),
281303
le => fromb(a <= b),
@@ -285,70 +307,76 @@ fn eval_const_expr(tcx: middle::ty::ctxt, e: @expr) -> const_val {
285307
}
286308
}
287309
// shifts can have any integral type as their rhs
288-
(const_int(a), const_uint(b)) => {
310+
(Ok(const_int(a)), Ok(const_uint(b))) => {
289311
match op {
290-
shl => const_int(a << b),
291-
shr => const_int(a >> b),
292-
_ => fail ~"Can't do this op on an int and uint"
312+
shl => Ok(const_int(a << b)),
313+
shr => Ok(const_int(a >> b)),
314+
_ => Err(~"Can't do this op on an int and uint")
293315
}
294316
}
295-
(const_uint(a), const_int(b)) => {
317+
(Ok(const_uint(a)), Ok(const_int(b))) => {
296318
match op {
297-
shl => const_uint(a << b),
298-
shr => const_uint(a >> b),
299-
_ => fail ~"Can't do this op on a uint and int"
319+
shl => Ok(const_uint(a << b)),
320+
shr => Ok(const_uint(a >> b)),
321+
_ => Err(~"Can't do this op on a uint and int")
300322
}
301323
}
302-
(const_bool(a), const_bool(b)) => {
303-
const_bool(match op {
324+
(Ok(const_bool(a)), Ok(const_bool(b))) => {
325+
Ok(const_bool(match op {
304326
and => a && b,
305327
or => a || b,
306328
bitxor => a ^ b,
307329
bitand => a & b,
308330
bitor => a | b,
309331
eq => a == b,
310332
ne => a != b,
311-
_ => fail ~"Can't do this op on bools"
312-
})
333+
_ => return Err(~"Can't do this op on bools")
334+
}))
313335
}
314-
_ => fail ~"Bad operands for binary"
336+
_ => Err(~"Bad operands for binary")
315337
}
316338
}
317339
expr_cast(base, _) => {
318340
let ety = ty::expr_ty(tcx, e);
319-
let base = eval_const_expr(tcx, base);
341+
let base = eval_const_expr_partial(tcx, base);
320342
match ty::get(ety).sty {
321343
ty::ty_float(_) => {
322344
match base {
323-
const_uint(u) => const_float(u as f64),
324-
const_int(i) => const_float(i as f64),
325-
const_float(_) => base,
326-
_ => fail ~"Can't cast float to str"
345+
Ok(const_uint(u)) => Ok(const_float(u as f64)),
346+
Ok(const_int(i)) => Ok(const_float(i as f64)),
347+
Ok(const_float(_)) => base,
348+
_ => Err(~"Can't cast float to str")
327349
}
328350
}
329351
ty::ty_uint(_) => {
330352
match base {
331-
const_uint(_) => base,
332-
const_int(i) => const_uint(i as u64),
333-
const_float(f) => const_uint(f as u64),
334-
_ => fail ~"Can't cast str to uint"
353+
Ok(const_uint(_)) => base,
354+
Ok(const_int(i)) => Ok(const_uint(i as u64)),
355+
Ok(const_float(f)) => Ok(const_uint(f as u64)),
356+
_ => Err(~"Can't cast str to uint")
335357
}
336358
}
337359
ty::ty_int(_) | ty::ty_bool => {
338360
match base {
339-
const_uint(u) => const_int(u as i64),
340-
const_int(_) => base,
341-
const_float(f) => const_int(f as i64),
342-
_ => fail ~"Can't cast str to int"
361+
Ok(const_uint(u)) => Ok(const_int(u as i64)),
362+
Ok(const_int(_)) => base,
363+
Ok(const_float(f)) => Ok(const_int(f as i64)),
364+
_ => Err(~"Can't cast str to int")
343365
}
344366
}
345-
_ => fail ~"Can't cast this type"
367+
_ => Err(~"Can't cast this type")
346368
}
347369
}
348-
expr_lit(lit) => lit_to_const(lit),
370+
expr_path(_) => {
371+
match lookup_const(tcx, e) {
372+
Some(actual_e) => eval_const_expr_partial(tcx, actual_e),
373+
None => Err(~"Non-constant path in constant expr")
374+
}
375+
}
376+
expr_lit(lit) => Ok(lit_to_const(lit)),
349377
// If we have a vstore, just keep going; it has to be a string
350-
expr_vstore(e, _) => eval_const_expr(tcx, e),
351-
_ => fail ~"Unsupported constant expr"
378+
expr_vstore(e, _) => eval_const_expr_partial(tcx, e),
379+
_ => Err(~"Unsupported constant expr")
352380
}
353381
}
354382

0 commit comments

Comments
 (0)