rustrust-compiler-plugin

How to get a tuple out of a ConstVal?


With current nightlies, one can use rustc::middle::const_eval_partial(..) to get a Result<ConstVal, _>. However, that ConstVal is a Tuple { node: NodeId } for tuple values. How can I get the contents of this tuple?

Example code (here a minimal lint to use as compiler plugin):

use rustc::lint::*;
use syntax::ptr::P;
use rustc_front::hir::*;
use rustc::middle::const_eval::ConstVal::Tuple;
use rustc::middle::const_eval::eval_const_expr_partial;
use rustc::middle::const_eval::EvalHint::ExprTypeChecked;

declare_lint! { pub TEST_LINT, Warn, "Just a test, ignore this" }

#[derive(Copy,Clone)]
pub struct TestLint;

impl LintPass for TestLint {
    fn get_lints(&self) -> LintArray {
        lint_array!TEST_LINT)
    }
}

impl LateLintPass for BitMask {
    fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
        let res = eval_const_expr_partial(cx.tcx, expr, ExprTypeChecked, None);
        if let Ok(Tuple(node_id))) = res {
            // ... how to get the parts of the tuple?
        }
    }
}

Solution

  • If you look at the code for the constant evaluation of the ExprTupField expression (indexing into tuples), you can see how to extract a specific field:

    if let hir::ExprTup(ref fields) = tcx.map.expect_expr(tup_id).node {
        if index.node < fields.len() {
            return eval_const_expr_partial(tcx, &fields[index.node], base_hint, fn_args)
        } else {
            signal!(e, TupleIndexOutOfBounds);
        }
    } else {
        unreachable!()
    }
    

    fields is a Vec<P<Expr>>. So you can iterate over that Vec and call eval_const_expr_partial on it to obtain a ConstVal of the tuple field.

    Note that you will get into trouble if the tuple was created in a const fn: https://github.com/rust-lang/rust/issues/29928