]> git.proxmox.com Git - rustc.git/blame - src/librustc/middle/const_val.rs
New upstream version 1.23.0+dfsg1
[rustc.git] / src / librustc / middle / const_val.rs
CommitLineData
54a0048b
SL
1// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
cc61c64b
XL
11pub use rustc_const_math::ConstInt;
12
54a0048b 13use hir::def_id::DefId;
3b2f2976 14use ty::{self, TyCtxt, layout};
8bb4bdeb 15use ty::subst::Substs;
54a0048b 16use rustc_const_math::*;
8bb4bdeb 17
cc61c64b
XL
18use graphviz::IntoCow;
19use errors::DiagnosticBuilder;
ea8adc8c 20use serialize::{self, Encodable, Encoder, Decodable, Decoder};
cc61c64b
XL
21use syntax::symbol::InternedString;
22use syntax::ast;
23use syntax_pos::Span;
54a0048b 24
cc61c64b 25use std::borrow::Cow;
cc61c64b 26
ea8adc8c 27pub type EvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ConstEvalErr<'tcx>>;
32a655c1 28
ea8adc8c 29#[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)]
8bb4bdeb 30pub enum ConstVal<'tcx> {
54a0048b 31 Integral(ConstInt),
ea8adc8c 32 Float(ConstFloat),
54a0048b 33 Str(InternedString),
ea8adc8c 34 ByteStr(ByteArray<'tcx>),
54a0048b 35 Bool(bool),
cc61c64b
XL
36 Char(char),
37 Variant(DefId),
8bb4bdeb 38 Function(DefId, &'tcx Substs<'tcx>),
ea8adc8c
XL
39 Aggregate(ConstAggregate<'tcx>),
40 Unevaluated(DefId, &'tcx Substs<'tcx>),
54a0048b
SL
41}
42
ea8adc8c
XL
43#[derive(Copy, Clone, Debug, Hash, RustcEncodable, Eq, PartialEq)]
44pub struct ByteArray<'tcx> {
45 pub data: &'tcx [u8],
46}
47
48impl<'tcx> serialize::UseSpecializedDecodable for ByteArray<'tcx> {}
49
50#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
51pub enum ConstAggregate<'tcx> {
52 Struct(&'tcx [(ast::Name, &'tcx ty::Const<'tcx>)]),
53 Tuple(&'tcx [&'tcx ty::Const<'tcx>]),
54 Array(&'tcx [&'tcx ty::Const<'tcx>]),
55 Repeat(&'tcx ty::Const<'tcx>, u64),
56}
57
58impl<'tcx> Encodable for ConstAggregate<'tcx> {
59 fn encode<S: Encoder>(&self, _: &mut S) -> Result<(), S::Error> {
60 bug!("should never encode ConstAggregate::{:?}", self)
61 }
62}
63
64impl<'tcx> Decodable for ConstAggregate<'tcx> {
65 fn decode<D: Decoder>(_: &mut D) -> Result<Self, D::Error> {
66 bug!("should never decode ConstAggregate")
54a0048b 67 }
ea8adc8c 68}
8bb4bdeb 69
ea8adc8c 70impl<'tcx> ConstVal<'tcx> {
8bb4bdeb
XL
71 pub fn to_const_int(&self) -> Option<ConstInt> {
72 match *self {
73 ConstVal::Integral(i) => Some(i),
74 ConstVal::Bool(b) => Some(ConstInt::U8(b as u8)),
75 ConstVal::Char(ch) => Some(ConstInt::U32(ch as u32)),
76 _ => None
77 }
78 }
54a0048b 79}
cc61c64b
XL
80
81#[derive(Clone, Debug)]
82pub struct ConstEvalErr<'tcx> {
83 pub span: Span,
84 pub kind: ErrKind<'tcx>,
85}
86
87#[derive(Clone, Debug)]
88pub enum ErrKind<'tcx> {
89 CannotCast,
90 MissingStructField,
cc61c64b
XL
91
92 NonConstPath,
93 UnimplementedConstVal(&'static str),
94 ExpectedConstTuple,
95 ExpectedConstStruct,
96 IndexedNonVec,
97 IndexNotUsize,
98 IndexOutOfBounds { len: u64, index: u64 },
99
100 MiscBinaryOp,
101 MiscCatchAll,
102
103 IndexOpFeatureGated,
104 Math(ConstMathErr),
3b2f2976 105 LayoutError(layout::LayoutError<'tcx>),
cc61c64b
XL
106
107 ErroneousReferencedConstant(Box<ConstEvalErr<'tcx>>),
108
109 TypeckError
110}
111
112impl<'tcx> From<ConstMathErr> for ErrKind<'tcx> {
113 fn from(err: ConstMathErr) -> ErrKind<'tcx> {
114 match err {
115 ConstMathErr::UnsignedNegation => ErrKind::TypeckError,
116 _ => ErrKind::Math(err)
117 }
118 }
119}
120
121#[derive(Clone, Debug)]
122pub enum ConstEvalErrDescription<'a> {
123 Simple(Cow<'a, str>),
124}
125
126impl<'a> ConstEvalErrDescription<'a> {
127 /// Return a one-line description of the error, for lints and such
128 pub fn into_oneline(self) -> Cow<'a, str> {
129 match self {
130 ConstEvalErrDescription::Simple(simple) => simple,
131 }
132 }
133}
134
135impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
136 pub fn description(&self) -> ConstEvalErrDescription {
137 use self::ErrKind::*;
138 use self::ConstEvalErrDescription::*;
139
140 macro_rules! simple {
141 ($msg:expr) => ({ Simple($msg.into_cow()) });
142 ($fmt:expr, $($arg:tt)+) => ({
143 Simple(format!($fmt, $($arg)+).into_cow())
144 })
145 }
146
147 match self.kind {
148 CannotCast => simple!("can't cast this type"),
cc61c64b
XL
149 MissingStructField => simple!("nonexistent struct field"),
150 NonConstPath => simple!("non-constant path in constant expression"),
151 UnimplementedConstVal(what) =>
152 simple!("unimplemented constant expression: {}", what),
153 ExpectedConstTuple => simple!("expected constant tuple"),
154 ExpectedConstStruct => simple!("expected constant struct"),
155 IndexedNonVec => simple!("indexing is only supported for arrays"),
156 IndexNotUsize => simple!("indices must be of type `usize`"),
157 IndexOutOfBounds { len, index } => {
158 simple!("index out of bounds: the len is {} but the index is {}",
159 len, index)
160 }
161
162 MiscBinaryOp => simple!("bad operands for binary"),
163 MiscCatchAll => simple!("unsupported constant expr"),
164 IndexOpFeatureGated => simple!("the index operation on const values is unstable"),
165 Math(ref err) => Simple(err.description().into_cow()),
3b2f2976 166 LayoutError(ref err) => Simple(err.to_string().into_cow()),
cc61c64b
XL
167
168 ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"),
169
170 TypeckError => simple!("type-checking failed"),
171 }
172 }
173
174 pub fn struct_error(&self,
175 tcx: TyCtxt<'a, 'gcx, 'tcx>,
176 primary_span: Span,
177 primary_kind: &str)
178 -> DiagnosticBuilder<'gcx>
179 {
180 let mut err = self;
181 while let &ConstEvalErr {
182 kind: ErrKind::ErroneousReferencedConstant(box ref i_err), ..
183 } = err {
184 err = i_err;
185 }
186
187 let mut diag = struct_span_err!(tcx.sess, err.span, E0080, "constant evaluation error");
188 err.note(tcx, primary_span, primary_kind, &mut diag);
189 diag
190 }
191
192 pub fn note(&self,
193 _tcx: TyCtxt<'a, 'gcx, 'tcx>,
194 primary_span: Span,
195 primary_kind: &str,
196 diag: &mut DiagnosticBuilder)
197 {
198 match self.description() {
199 ConstEvalErrDescription::Simple(message) => {
7cac9316 200 diag.span_label(self.span, message);
cc61c64b
XL
201 }
202 }
203
204 if !primary_span.contains(self.span) {
205 diag.span_note(primary_span,
206 &format!("for {} here", primary_kind));
207 }
208 }
209
210 pub fn report(&self,
211 tcx: TyCtxt<'a, 'gcx, 'tcx>,
212 primary_span: Span,
213 primary_kind: &str)
214 {
215 if let ErrKind::TypeckError = self.kind {
216 return;
217 }
218 self.struct_error(tcx, primary_span, primary_kind).emit();
219 }
220}