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.
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.
11 use hir::def_id::DefId;
13 use ty::subst::Substs;
14 use ty::query::TyCtxtAt;
15 use mir::interpret::ConstValue;
16 use errors::DiagnosticBuilder;
18 use graphviz::IntoCow;
23 use rustc_data_structures::sync::Lrc;
25 pub type EvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ConstEvalErr<'tcx>>;
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>),
33 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
34 pub struct ConstEvalErr<'tcx> {
36 pub kind: Lrc<ErrKind<'tcx>>,
39 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
40 pub enum ErrKind<'tcx> {
45 Miri(::mir::interpret::EvalError<'tcx>, Vec<FrameInfo>),
48 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
49 pub struct FrameInfo {
52 pub lint_root: Option<ast::NodeId>,
55 #[derive(Clone, Debug)]
56 pub enum ConstEvalErrDescription<'a, 'tcx: 'a> {
58 Backtrace(&'a ::mir::interpret::EvalError<'tcx>, &'a [FrameInfo]),
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> {
65 ConstEvalErrDescription::Simple(simple) => simple,
66 ConstEvalErrDescription::Backtrace(miri, _) => format!("{}", miri).into_cow(),
71 impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
72 pub fn description(&'a self) -> ConstEvalErrDescription<'a, 'tcx> {
74 use self::ConstEvalErrDescription::*;
77 ($msg:expr) => ({ Simple($msg.into_cow()) });
78 ($fmt:expr, $($arg:tt)+) => ({
79 Simple(format!($fmt, $($arg)+).into_cow())
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),
91 pub fn struct_error(&self,
92 tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
94 -> Option<DiagnosticBuilder<'tcx>>
96 self.struct_generic(tcx, message, None, true)
99 pub fn report_as_error(&self,
100 tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
103 let err = self.struct_generic(tcx, message, None, true);
104 if let Some(mut err) = err {
109 pub fn report_as_lint(&self,
110 tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
112 lint_root: ast::NodeId,
114 let lint = self.struct_generic(
120 if let Some(mut lint) = lint {
127 tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
129 lint_root: Option<ast::NodeId>,
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) => {
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)
142 _ => (miri.to_string(), frames),
145 _ => (self.description().into_oneline().to_string(), &[]),
147 trace!("reporting const eval failure at {:?}", self.span);
148 let mut err = if as_err {
149 struct_error(tcx, message)
154 .filter_map(|frame| frame.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,
165 err.span_label(self.span, msg);
166 for FrameInfo { span, location, .. } in frames {
167 err.span_label(*span, format!("inside call to `{}`", location));
173 pub fn struct_error<'a, 'gcx, 'tcx>(
174 tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
176 ) -> DiagnosticBuilder<'tcx> {
177 struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)