summary refs log tree commit diff
path: root/src/librustc_mir/build/expr/as_constant.rs
blob: a6d06c447a4c0efba77214fce174a150d87dc5aa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! See docs in build/expr/mod.rs

use rustc_data_structures::fnv::FnvHashMap;

use build::{Builder};
use hair::*;
use repr::*;

impl<H:Hair> Builder<H> {
    /// Compile `expr`, yielding a compile-time constant. Assumes that
    /// `expr` is a valid compile-time constant!
    pub fn as_constant<M>(&mut self, expr: M) -> Constant<H>
        where M: Mirror<H, Output=Expr<H>>
    {
        let expr = self.hir.mirror(expr);
        self.expr_as_constant(expr)
    }

    fn expr_as_constant(&mut self, expr: Expr<H>) -> Constant<H> {
        let this = self;
        let Expr { ty: _, temp_lifetime: _, span, kind } = expr;
        let kind = match kind {
            ExprKind::Scope { extent: _, value } => {
                return this.as_constant(value);
            }
            ExprKind::Paren { arg } => {
                return this.as_constant(arg);
            }
            ExprKind::Literal { literal } => {
                ConstantKind::Literal(literal)
            }
            ExprKind::Vec { fields } => {
                let fields = this.as_constants(fields);
                ConstantKind::Aggregate(AggregateKind::Vec, fields)
            }
            ExprKind::Tuple { fields } => {
                let fields = this.as_constants(fields);
                ConstantKind::Aggregate(AggregateKind::Tuple, fields)
            }
            ExprKind::Adt { adt_def, variant_index, substs, fields, base: None } => {
                let field_names = this.hir.fields(adt_def, variant_index);
                let fields = this.named_field_constants(field_names, fields);
                ConstantKind::Aggregate(AggregateKind::Adt(adt_def, variant_index, substs), fields)
            }
            ExprKind::Repeat { value, count } => {
                let value = Box::new(this.as_constant(value));
                let count = Box::new(this.as_constant(count));
                ConstantKind::Repeat(value, count)
            }
            ExprKind::Binary { op, lhs, rhs } => {
                let lhs = Box::new(this.as_constant(lhs));
                let rhs = Box::new(this.as_constant(rhs));
                ConstantKind::BinaryOp(op, lhs, rhs)
            }
            ExprKind::Unary { op, arg } => {
                let arg = Box::new(this.as_constant(arg));
                ConstantKind::UnaryOp(op, arg)
            }
            ExprKind::Field { lhs, name } => {
                let lhs = this.as_constant(lhs);
                ConstantKind::Projection(
                    Box::new(ConstantProjection {
                        base: lhs,
                        elem: ProjectionElem::Field(name),
                    }))
            }
            ExprKind::Deref { arg } => {
                let arg = this.as_constant(arg);
                ConstantKind::Projection(
                    Box::new(ConstantProjection {
                        base: arg,
                        elem: ProjectionElem::Deref,
                    }))
            }
            ExprKind::Call { fun, args } => {
                let fun = this.as_constant(fun);
                let args = this.as_constants(args);
                ConstantKind::Call(Box::new(fun), args)
            }
            _ => {
                this.hir.span_bug(
                    span,
                    &format!("expression is not a valid constant {:?}", kind));
            }
        };
        Constant { span: span, kind: kind }
    }

    fn as_constants(&mut self,
                    exprs: Vec<ExprRef<H>>)
                    -> Vec<Constant<H>>
    {
        exprs.into_iter().map(|expr| self.as_constant(expr)).collect()
    }

    fn named_field_constants(&mut self,
                             field_names: Vec<Field<H>>,
                             field_exprs: Vec<FieldExprRef<H>>)
                             -> Vec<Constant<H>>
    {
        let fields_map: FnvHashMap<_, _> =
            field_exprs.into_iter()
                       .map(|f| (f.name, self.as_constant(f.expr)))
                       .collect();

        let fields: Vec<_> =
            field_names.into_iter()
                       .map(|n| fields_map[&n].clone())
                       .collect();

        fields
    }
}