]>
Commit | Line | Data |
---|---|---|
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 | ||
54a0048b | 11 | use hir::def_id::DefId; |
94b46f34 | 12 | use ty; |
8bb4bdeb | 13 | use ty::subst::Substs; |
94b46f34 XL |
14 | use ty::query::TyCtxtAt; |
15 | use mir::interpret::ConstValue; | |
0531ce1d | 16 | use errors::DiagnosticBuilder; |
8bb4bdeb | 17 | |
cc61c64b | 18 | use graphviz::IntoCow; |
cc61c64b | 19 | use syntax_pos::Span; |
94b46f34 | 20 | use syntax::ast; |
54a0048b | 21 | |
cc61c64b | 22 | use std::borrow::Cow; |
0531ce1d | 23 | use rustc_data_structures::sync::Lrc; |
cc61c64b | 24 | |
ea8adc8c | 25 | pub type EvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ConstEvalErr<'tcx>>; |
32a655c1 | 26 | |
94b46f34 | 27 | #[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq, Ord, PartialOrd)] |
8bb4bdeb | 28 | pub enum ConstVal<'tcx> { |
ea8adc8c | 29 | Unevaluated(DefId, &'tcx Substs<'tcx>), |
94b46f34 | 30 | Value(ConstValue<'tcx>), |
ea8adc8c | 31 | } |
8bb4bdeb | 32 | |
94b46f34 | 33 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] |
cc61c64b XL |
34 | pub struct ConstEvalErr<'tcx> { |
35 | pub span: Span, | |
0531ce1d | 36 | pub kind: Lrc<ErrKind<'tcx>>, |
cc61c64b XL |
37 | } |
38 | ||
94b46f34 | 39 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] |
cc61c64b | 40 | pub enum ErrKind<'tcx> { |
cc61c64b | 41 | |
94b46f34 | 42 | CouldNotResolve, |
ff7c6d11 XL |
43 | TypeckError, |
44 | CheckMatchError, | |
0531ce1d XL |
45 | Miri(::mir::interpret::EvalError<'tcx>, Vec<FrameInfo>), |
46 | } | |
47 | ||
94b46f34 | 48 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] |
0531ce1d XL |
49 | pub struct FrameInfo { |
50 | pub span: Span, | |
51 | pub location: String, | |
94b46f34 | 52 | pub lint_root: Option<ast::NodeId>, |
cc61c64b XL |
53 | } |
54 | ||
cc61c64b | 55 | #[derive(Clone, Debug)] |
0531ce1d | 56 | pub enum ConstEvalErrDescription<'a, 'tcx: 'a> { |
cc61c64b | 57 | Simple(Cow<'a, str>), |
0531ce1d | 58 | Backtrace(&'a ::mir::interpret::EvalError<'tcx>, &'a [FrameInfo]), |
cc61c64b XL |
59 | } |
60 | ||
0531ce1d | 61 | impl<'a, 'tcx> ConstEvalErrDescription<'a, 'tcx> { |
cc61c64b XL |
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, | |
0531ce1d | 66 | ConstEvalErrDescription::Backtrace(miri, _) => format!("{}", miri).into_cow(), |
cc61c64b XL |
67 | } |
68 | } | |
69 | } | |
70 | ||
71 | impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { | |
0531ce1d | 72 | pub fn description(&'a self) -> ConstEvalErrDescription<'a, 'tcx> { |
cc61c64b XL |
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 | ||
0531ce1d | 83 | match *self.kind { |
94b46f34 | 84 | CouldNotResolve => simple!("could not resolve"), |
cc61c64b | 85 | TypeckError => simple!("type-checking failed"), |
ff7c6d11 | 86 | CheckMatchError => simple!("match-checking failed"), |
0531ce1d | 87 | Miri(ref err, ref trace) => Backtrace(err, trace), |
cc61c64b XL |
88 | } |
89 | } | |
90 | ||
91 | pub fn struct_error(&self, | |
94b46f34 XL |
92 | tcx: TyCtxtAt<'a, 'gcx, 'tcx>, |
93 | message: &str) | |
94 | -> Option<DiagnosticBuilder<'tcx>> | |
cc61c64b | 95 | { |
94b46f34 | 96 | self.struct_generic(tcx, message, None, true) |
cc61c64b XL |
97 | } |
98 | ||
94b46f34 XL |
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(); | |
cc61c64b | 106 | } |
94b46f34 | 107 | } |
cc61c64b | 108 | |
94b46f34 XL |
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(); | |
cc61c64b XL |
122 | } |
123 | } | |
124 | ||
94b46f34 XL |
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) => { | |
0531ce1d XL |
135 | match miri.kind { |
136 | ::mir::interpret::EvalErrorKind::TypeckError | | |
94b46f34 XL |
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), | |
0531ce1d XL |
143 | } |
144 | } | |
94b46f34 XL |
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)); | |
cc61c64b | 168 | } |
94b46f34 | 169 | Some(err) |
cc61c64b XL |
170 | } |
171 | } | |
0531ce1d XL |
172 | |
173 | pub fn struct_error<'a, 'gcx, 'tcx>( | |
94b46f34 | 174 | tcx: TyCtxtAt<'a, 'gcx, 'tcx>, |
0531ce1d | 175 | msg: &str, |
94b46f34 XL |
176 | ) -> DiagnosticBuilder<'tcx> { |
177 | struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg) | |
0531ce1d | 178 | } |