]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/const_val.rs
Use assert_eq! in copy_from_slice
[rust.git] / src / librustc / middle / const_val.rs
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
11 use hir::def_id::DefId;
12 use ty;
13 use ty::subst::Substs;
14 use ty::query::TyCtxtAt;
15 use mir::interpret::ConstValue;
16 use errors::DiagnosticBuilder;
17
18 use graphviz::IntoCow;
19 use syntax_pos::Span;
20 use syntax::ast;
21
22 use std::borrow::Cow;
23 use rustc_data_structures::sync::Lrc;
24
25 pub type EvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ConstEvalErr<'tcx>>;
26
27 #[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq, Ord, PartialOrd)]
28 pub enum ConstVal<'tcx> {
29     Unevaluated(DefId, &'tcx Substs<'tcx>),
30     Value(ConstValue<'tcx>),
31 }
32
33 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
34 pub struct ConstEvalErr<'tcx> {
35     pub span: Span,
36     pub kind: Lrc<ErrKind<'tcx>>,
37 }
38
39 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
40 pub enum ErrKind<'tcx> {
41
42     CouldNotResolve,
43     TypeckError,
44     CheckMatchError,
45     Miri(::mir::interpret::EvalError<'tcx>, Vec<FrameInfo>),
46 }
47
48 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
49 pub struct FrameInfo {
50     pub span: Span,
51     pub location: String,
52     pub lint_root: Option<ast::NodeId>,
53 }
54
55 #[derive(Clone, Debug)]
56 pub enum ConstEvalErrDescription<'a, 'tcx: 'a> {
57     Simple(Cow<'a, str>),
58     Backtrace(&'a ::mir::interpret::EvalError<'tcx>, &'a [FrameInfo]),
59 }
60
61 impl<'a, 'tcx> ConstEvalErrDescription<'a, 'tcx> {
62     /// Return a one-line description of the error, for lints and such
63     pub fn into_oneline(self) -> Cow<'a, str> {
64         match self {
65             ConstEvalErrDescription::Simple(simple) => simple,
66             ConstEvalErrDescription::Backtrace(miri, _) => format!("{}", miri).into_cow(),
67         }
68     }
69 }
70
71 impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
72     pub fn description(&'a self) -> ConstEvalErrDescription<'a, 'tcx> {
73         use self::ErrKind::*;
74         use self::ConstEvalErrDescription::*;
75
76         macro_rules! simple {
77             ($msg:expr) => ({ Simple($msg.into_cow()) });
78             ($fmt:expr, $($arg:tt)+) => ({
79                 Simple(format!($fmt, $($arg)+).into_cow())
80             })
81         }
82
83         match *self.kind {
84             CouldNotResolve => simple!("could not resolve"),
85             TypeckError => simple!("type-checking failed"),
86             CheckMatchError => simple!("match-checking failed"),
87             Miri(ref err, ref trace) => Backtrace(err, trace),
88         }
89     }
90
91     pub fn struct_error(&self,
92         tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
93         message: &str)
94         -> Option<DiagnosticBuilder<'tcx>>
95     {
96         self.struct_generic(tcx, message, None, true)
97     }
98
99     pub fn report_as_error(&self,
100         tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
101         message: &str
102     ) {
103         let err = self.struct_generic(tcx, message, None, true);
104         if let Some(mut err) = err {
105             err.emit();
106         }
107     }
108
109     pub fn report_as_lint(&self,
110         tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
111         message: &str,
112         lint_root: ast::NodeId,
113     ) {
114         let lint = self.struct_generic(
115             tcx,
116             message,
117             Some(lint_root),
118             false,
119         );
120         if let Some(mut lint) = lint {
121             lint.emit();
122         }
123     }
124
125     fn struct_generic(
126         &self,
127         tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
128         message: &str,
129         lint_root: Option<ast::NodeId>,
130         as_err: bool,
131     ) -> Option<DiagnosticBuilder<'tcx>> {
132         let (msg, frames): (_, &[_]) = match *self.kind {
133             ErrKind::TypeckError | ErrKind::CheckMatchError => return None,
134             ErrKind::Miri(ref miri, ref frames) => {
135                 match miri.kind {
136                     ::mir::interpret::EvalErrorKind::TypeckError |
137                     ::mir::interpret::EvalErrorKind::Layout(_) => return None,
138                     ::mir::interpret::EvalErrorKind::ReferencedConstant(ref inner) => {
139                         inner.struct_generic(tcx, "referenced constant", lint_root, as_err)?.emit();
140                         (miri.to_string(), frames)
141                     },
142                     _ => (miri.to_string(), frames),
143                 }
144             }
145             _ => (self.description().into_oneline().to_string(), &[]),
146         };
147         trace!("reporting const eval failure at {:?}", self.span);
148         let mut err = if as_err {
149             struct_error(tcx, message)
150         } else {
151             let node_id = frames
152                 .iter()
153                 .rev()
154                 .filter_map(|frame| frame.lint_root)
155                 .next()
156                 .or(lint_root)
157                 .expect("some part of a failing const eval must be local");
158             tcx.struct_span_lint_node(
159                 ::rustc::lint::builtin::CONST_ERR,
160                 node_id,
161                 tcx.span,
162                 message,
163             )
164         };
165         err.span_label(self.span, msg);
166         for FrameInfo { span, location, .. } in frames {
167             err.span_label(*span, format!("inside call to `{}`", location));
168         }
169         Some(err)
170     }
171 }
172
173 pub fn struct_error<'a, 'gcx, 'tcx>(
174     tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
175     msg: &str,
176 ) -> DiagnosticBuilder<'tcx> {
177     struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
178 }