Skip to content

const_eval sometimes confuses (a guess at) expected type with expression's actual type #23833

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Closed
pnkfelix opened this issue Mar 29, 2015 · 5 comments
Labels
A-type-system Area: Type system

Comments

@pnkfelix
Copy link
Member

const_eval sometimes confuses a guess at expected type with expression's actual type

Here's an example:

use std::fmt;
use std::{i8, i16, i32, i64, isize};
use std::{u8, u16, u32, u64, usize};

const A_I8_T
    : [u32; (i8::MAX as i8 - 1i8) as usize]
    = [0; (i8::MAX as usize) - 1];

fn main() {
    foo(&A_I8_T[..]);
}

fn foo<T:fmt::Debug>(x: T) {
    println!("{:?}", x);
}

playpen yields:

<anon>:6:14: 6:33 error: array length constant evaluation error: can't do this op on a usize and isize [E0250]
<anon>:6     : [u32; (i8::MAX as i8 - 1i8) as usize]
                      ^~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
playpen: application terminated with error code 101

I believe this is due to this line in const_eval.rs:

https://github.com/rust-lang/rust/blob/master/src/librustc/middle/const_eval.rs#L504
(transcribed immediately below for ease of reference:)

Namely, the logic here takes a constant expression like the one in the above count expression and feeds the expected usize type down into the computation of (i8::MAX as i8 - 1i8).

      ast::ExprCast(ref base, ref target_ty) => {
        // This tends to get called w/o the type actually having been
        // populated in the ctxt, which was causing things to blow up
        // (#5900). Fall back to doing a limited lookup to get past it.
        let ety = ety.or_else(|| ast_ty_to_prim_ty(tcx, &**target_ty))
                .unwrap_or_else(|| {
                    tcx.sess.span_fatal(target_ty.span,
                                        "target type not found for const cast")
                });
        // Prefer known type to noop, but always have a type hint.
        let base_hint = ty::expr_ty_opt(tcx, &**base).unwrap_or(ety);
        let val = try!(eval_const_expr_partial(tcx, &**base, Some(base_hint)));
        match cast_const(val, ety) {
            Ok(val) => val,
            Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }),
        }
      }

Even though there are many many hints in (i8::MAX as i8 - 1i8) that are attempting to force the left- and right-hand sides to both be i8, the const_eval is ignoring them and trying to force the left-hand-side to be a usize.

(This causes problems for proper overflow detection in const_eval.)

@pnkfelix
Copy link
Member Author

this is related to #22531 and should be treated as a sub-bug of #22020.

@pnkfelix
Copy link
Member Author

(Not quite sure why it is so important to always have a type hint; seems like it would be more accurate to instead carry (a bottom-up determined, (update: partially-determined if necessary)) type along with the value during const-eval.)

@steveklabnik steveklabnik added the A-type-system Area: Type system label Mar 30, 2015
@pnkfelix
Copy link
Member Author

cc #23897

@pnkfelix
Copy link
Member Author

This example, adapted from #18744 , is probably another instance of this:

fn main() {
    match 1u64 {
        0...0xFFFF_FFFF_FFFF_FFFF => { },
        _ => { },
    }
}

It currently errors with error: lower range bound must be less than upper [E0030]

(The workaround is to add explicit suffixes to at least the 0 and optionally both ends of the range.)

@nagisa
Copy link
Member

nagisa commented Aug 11, 2016

Not an issue anymore, should be closed.

@eddyb eddyb closed this as completed Aug 11, 2016
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
A-type-system Area: Type system
Projects
None yet
Development

No branches or pull requests

4 participants