Skip to content

Commit 7237268

Browse files
committedOct 15, 2012
Allow enum discriminator exprs to refer to declared consts
Also some work towards #3521 Closes #2428
·
release-0.70.5
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‎

Lines changed: 2 additions & 0 deletions
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‎

Lines changed: 124 additions & 96 deletions
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

‎src/rustc/middle/resolve.rs‎

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,10 @@ enum RibKind {
257257
MethodRibKind(node_id, MethodSort),
258258

259259
// We passed through a function *item* scope. Disallow upvars.
260-
OpaqueFunctionRibKind
260+
OpaqueFunctionRibKind,
261+
262+
// We're in a constant item. Can't refer to dynamic stuff.
263+
ConstantItemRibKind
261264
}
262265

263266
// Methods can be required or provided. Required methods only occur in traits.
@@ -3114,9 +3117,16 @@ impl Resolver {
31143117

31153118
return None;
31163119
}
3120+
ConstantItemRibKind => {
3121+
// Still doesn't deal with upvars
3122+
self.session.span_err(span,
3123+
~"attempt to use a non-constant \
3124+
value in a constant");
3125+
3126+
}
31173127
}
31183128

3119-
rib_index += 1u;
3129+
rib_index += 1;
31203130
}
31213131

31223132
return Some(dl_def(def));
@@ -3130,8 +3140,8 @@ impl Resolver {
31303140
// XXX: Try caching?
31313141

31323142
let mut i = (*ribs).len();
3133-
while i != 0u {
3134-
i -= 1u;
3143+
while i != 0 {
3144+
i -= 1;
31353145
let rib = (*ribs).get_elt(i);
31363146
match rib.bindings.find(name) {
31373147
Some(def_like) => {
@@ -3179,7 +3189,33 @@ impl Resolver {
31793189
}
31803190

31813191
match item.node {
3182-
item_enum(_, type_parameters) |
3192+
3193+
// enum item: resolve all the variants' discrs,
3194+
// then resolve the ty params
3195+
item_enum(enum_def, type_parameters) => {
3196+
3197+
for enum_def.variants.each() |variant| {
3198+
do variant.node.disr_expr.iter() |dis_expr| {
3199+
// resolve the discriminator expr
3200+
// as a constant
3201+
self.with_constant_rib(|| {
3202+
self.resolve_expr(*dis_expr, visitor);
3203+
});
3204+
}
3205+
}
3206+
3207+
// n.b. the discr expr gets visted twice.
3208+
// but maybe it's okay since the first time will signal an
3209+
// error if there is one? -- tjc
3210+
do self.with_type_parameter_rib
3211+
(HasTypeParameters(&type_parameters, item.id, 0,
3212+
NormalRibKind))
3213+
|| {
3214+
3215+
visit_item(item, (), visitor);
3216+
}
3217+
}
3218+
31833219
item_ty(_, type_parameters) => {
31843220
do self.with_type_parameter_rib
31853221
(HasTypeParameters(&type_parameters, item.id, 0u,
@@ -3344,7 +3380,9 @@ impl Resolver {
33443380
}
33453381

33463382
item_const(*) => {
3347-
visit_item(item, (), visitor);
3383+
self.with_constant_rib(|| {
3384+
visit_item(item, (), visitor);
3385+
});
33483386
}
33493387

33503388
item_mac(*) => {
@@ -3401,6 +3439,12 @@ impl Resolver {
34013439
f();
34023440
(*self.label_ribs).pop();
34033441
}
3442+
fn with_constant_rib(f: fn()) {
3443+
(*self.value_ribs).push(@Rib(ConstantItemRibKind));
3444+
f();
3445+
(*self.value_ribs).pop();
3446+
}
3447+
34043448

34053449
fn resolve_function(rib_kind: RibKind,
34063450
optional_declaration: Option<@fn_decl>,
@@ -4127,7 +4171,7 @@ impl Resolver {
41274171
namespace);
41284172
}
41294173
4130-
if path.idents.len() > 1u {
4174+
if path.idents.len() > 1 {
41314175
return self.resolve_module_relative_path(path,
41324176
self.xray_context,
41334177
namespace);

‎src/rustc/middle/typeck/check.rs‎

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2219,9 +2219,14 @@ fn check_block(fcx0: @fn_ctxt, blk: ast::blk) -> bool {
22192219
fn check_const(ccx: @crate_ctxt, _sp: span, e: @ast::expr, id: ast::node_id) {
22202220
let rty = ty::node_id_to_type(ccx.tcx, id);
22212221
let fcx = blank_fn_ctxt(ccx, rty, e.id);
2222+
let declty = fcx.ccx.tcx.tcache.get(local_def(id)).ty;
2223+
check_const_with_ty(fcx, _sp, e, declty);
2224+
}
2225+
2226+
fn check_const_with_ty(fcx: @fn_ctxt, _sp: span, e: @ast::expr,
2227+
declty: ty::t) {
22222228
check_expr(fcx, e, None);
22232229
let cty = fcx.expr_ty(e);
2224-
let declty = fcx.ccx.tcx.tcache.get(local_def(id)).ty;
22252230
demand::suptype(fcx, e.span, declty, cty);
22262231
regionck::regionck_expr(fcx, e);
22272232
writeback::resolve_type_vars_in_expr(fcx, e);
@@ -2259,27 +2264,31 @@ fn check_enum_variants(ccx: @crate_ctxt,
22592264
variants: &mut ~[ty::variant_info]) {
22602265
let rty = ty::node_id_to_type(ccx.tcx, id);
22612266
for vs.each |v| {
2262-
match v.node.disr_expr {
2263-
Some(e) => {
2264-
let fcx = blank_fn_ctxt(ccx, rty, e.id);
2265-
check_expr(fcx, e, None);
2266-
let cty = fcx.expr_ty(e);
2267+
do v.node.disr_expr.iter |e_ref| {
2268+
let e = *e_ref;
2269+
debug!("disr expr, checking %s",
2270+
expr_to_str(e, ccx.tcx.sess.intr()));
22672271
let declty = ty::mk_int(ccx.tcx);
2268-
demand::suptype(fcx, e.span, declty, cty);
2272+
let fcx = blank_fn_ctxt(ccx, rty, e.id);
2273+
check_const_with_ty(fcx, e.span, e, declty);
22692274
// check_expr (from check_const pass) doesn't guarantee
22702275
// that the expression is in an form that eval_const_expr can
22712276
// handle, so we may still get an internal compiler error
2272-
match const_eval::eval_const_expr(ccx.tcx, e) {
2273-
const_eval::const_int(val) => {
2277+
2278+
match const_eval::eval_const_expr_partial(ccx.tcx, e) {
2279+
Ok(const_eval::const_int(val)) => {
22742280
*disr_val = val as int;
22752281
}
2276-
_ => {
2282+
Ok(_) => {
22772283
ccx.tcx.sess.span_err(e.span, ~"expected signed integer \
22782284
constant");
22792285
}
2286+
Err(err) => {
2287+
ccx.tcx.sess.span_err(e.span,
2288+
#fmt("expected constant: %s", err));
2289+
2290+
}
22802291
}
2281-
}
2282-
_ => ()
22832292
}
22842293
if vec::contains(*disr_vals, &*disr_val) {
22852294
ccx.tcx.sess.span_err(v.span,
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
fn main() {
2+
let foo = 100;
3+
4+
const y: int = foo + 1; //~ ERROR: attempt to use a non-constant value in a constant
5+
6+
log(error, y);
7+
}

‎src/test/run-pass/issue-2428.rs‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
fn main() {
2+
let foo = 100;
3+
const quux: int = 5;
4+
5+
enum Stuff {
6+
Bar = quux
7+
}
8+
9+
assert (Bar as int == quux);
10+
}

0 commit comments

Comments
 (0)
Please sign in to comment.