about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2018-01-22 18:07:35 -0800
committerEsteban Küber <esteban@kuber.com.ar>2018-01-23 11:01:38 -0800
commit3dac0f5a9ce8864a06916d3e8017a9b2c5262ae7 (patch)
tree0eedc24351ba95d4d2b1e0b7330a208218b5a604
parent7d41cbad6a34976e3d6d0321ba1d4c433e24e21c (diff)
downloadrust-3dac0f5a9ce8864a06916d3e8017a9b2c5262ae7.tar.gz
rust-3dac0f5a9ce8864a06916d3e8017a9b2c5262ae7.zip
Create `StructuredDiagnostic`
Create the concept of an `StructuredDiagnostic` that is self-contained
with enough knowledge of all variables to create a `DiagnosticBuilder`,
including different possible versions (one line output and expanded
explanations).
-rw-r--r--src/librustc/session/mod.rs4
-rw-r--r--src/librustc_typeck/check/cast.rs35
-rw-r--r--src/librustc_typeck/check/mod.rs19
-rw-r--r--src/librustc_typeck/lib.rs7
-rw-r--r--src/librustc_typeck/structured_errors.rs150
5 files changed, 167 insertions, 48 deletions
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index 94fcfb7e2aa..995aef51cad 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -831,6 +831,10 @@ impl Session {
             _ => true,
         }
     }
+
+    pub fn explain(&self, code: &DiagnosticId) -> bool {
+        self.opts.debugging_opts.explain && !self.parse_sess.span_diagnostic.code_emitted(code)
+    }
 }
 
 pub fn build_session(sopts: config::Options,
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 334e1b06e37..b8be0d6c182 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -281,35 +281,12 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
                                 .emit();
             }
             CastError::SizedUnsizedCast => {
-                let mut err = type_error_struct!(
-                    fcx.tcx.sess,
-                    self.span,
-                    self.expr_ty,
-                    E0607,
-                    "cannot cast thin pointer `{}` to fat pointer `{}`",
-                    self.expr_ty,
-                    fcx.ty_to_string(self.cast_ty)
-                );
-                if fcx.tcx.sess.opts.debugging_opts.explain
-                    && !fcx.tcx.sess.parse_sess.span_diagnostic
-                        .code_emitted(&err.get_code().unwrap()) {
-                    err.help(
-                        "Thin pointers are \"simple\" pointers: they are purely a reference to a
-memory address.
-
-Fat pointers are pointers referencing \"Dynamically Sized Types\" (also
-called DST). DST don't have a statically known size, therefore they can
-only exist behind some kind of pointers that contain additional
-information. Slices and trait objects are DSTs. In the case of slices,
-the additional information the fat pointer holds is their size.
-
-To fix this error, don't try to cast directly between thin and fat
-pointers.
-
-For more information about casts, take a look at The Book:
-https://doc.rust-lang.org/book/first-edition/casting-between-types.html");
-                }
-                err.emit();
+                use structured_errors::{SizedUnsizedCastError, StructuredDiagnostic};
+                SizedUnsizedCastError::new(&fcx.tcx.sess,
+                                           self.span,
+                                           self.expr_ty,
+                                           fcx.ty_to_string(self.cast_ty))
+                    .diagnostic().emit();
             }
             CastError::UnknownCastPtrKind |
             CastError::UnknownExprPtrKind => {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 67b1a04d54f..3cd327adf22 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -103,6 +103,7 @@ use rustc::ty::maps::Providers;
 use rustc::ty::util::{Representability, IntTypeExt};
 use rustc::ty::layout::LayoutOf;
 use errors::{DiagnosticBuilder, DiagnosticId};
+
 use require_c_abi_if_variadic;
 use session::{CompileIncomplete, config, Session};
 use TypeAndSubsts;
@@ -2591,22 +2592,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // arguments which we skipped above.
         if variadic {
             fn variadic_error<'tcx>(s: &Session, span: Span, t: Ty<'tcx>, cast_ty: &str) {
-                let mut err = type_error_struct!(
-                    s, span, t, E0617, "can't pass `{}` to variadic function", t);
-                if s.opts.debugging_opts.explain {
-                    err.note(&format!("certain types, like `{}`, must be cast before passing them \
-                                       to a variadic function, because of arcane ABI rules \
-                                       dictated by the C standard",
-                                      t));
-                }
-                if let Ok(snippet) = s.codemap().span_to_snippet(span) {
-                    err.span_suggestion(span,
-                                        &format!("cast the value to `{}`", cast_ty),
-                                        format!("{} as {}", snippet, cast_ty));
-                } else {
-                    err.help(&format!("cast the value to `{}`", cast_ty));
-                }
-                err.emit();
+                use structured_errors::{VariadicError, StructuredDiagnostic};
+                VariadicError::new(s, span, t, cast_ty).diagnostic().emit();
             }
 
             for arg in args.iter().skip(expected_arg_count) {
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 786a6783440..8d5d7dc04ec 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -122,16 +122,17 @@ use std::iter;
 // registered before they are used.
 mod diagnostics;
 
+mod astconv;
 mod check;
 mod check_unused;
-mod astconv;
+mod coherence;
 mod collect;
 mod constrained_type_params;
+mod structured_errors;
 mod impl_wf_check;
-mod coherence;
+mod namespace;
 mod outlives;
 mod variance;
-mod namespace;
 
 pub struct TypeAndSubsts<'tcx> {
     substs: &'tcx Substs<'tcx>,
diff --git a/src/librustc_typeck/structured_errors.rs b/src/librustc_typeck/structured_errors.rs
new file mode 100644
index 00000000000..e9b96ed2d64
--- /dev/null
+++ b/src/librustc_typeck/structured_errors.rs
@@ -0,0 +1,150 @@
+// Copyright 2018 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.
+
+use rustc::session::Session;
+use syntax_pos::Span;
+use errors::{DiagnosticId, DiagnosticBuilder};
+use rustc::ty::{Ty, TypeFoldable};
+
+pub trait StructuredDiagnostic<'tcx> {
+    fn session(&self) -> &Session;
+
+    fn code(&self) -> DiagnosticId;
+
+    fn common(&self) -> DiagnosticBuilder<'tcx>;
+
+    fn diagnostic(&self) -> DiagnosticBuilder<'tcx> {
+        let err = self.common();
+        if self.session().explain(&self.code()) {
+            self.extended(err)
+        } else {
+            self.regular(err)
+        }
+    }
+
+    fn regular(&self, err: DiagnosticBuilder<'tcx>) -> DiagnosticBuilder<'tcx> {
+        err
+    }
+
+    fn extended(&self, err: DiagnosticBuilder<'tcx>) -> DiagnosticBuilder<'tcx> {
+        err
+    }
+}
+
+pub struct VariadicError<'tcx> {
+    sess: &'tcx Session,
+    span: Span,
+    t: Ty<'tcx>,
+    cast_ty: &'tcx str,
+}
+
+impl<'tcx> VariadicError<'tcx> {
+    pub fn new(sess: &'tcx Session,
+               span: Span,
+               t: Ty<'tcx>,
+               cast_ty: &'tcx str) -> VariadicError<'tcx> {
+        VariadicError { sess, span, t, cast_ty }
+    }
+}
+
+impl<'tcx> StructuredDiagnostic<'tcx> for VariadicError<'tcx> {
+    fn session(&self) -> &Session { self.sess }
+
+    fn code(&self) -> DiagnosticId {
+        __diagnostic_used!(E0617);
+        DiagnosticId::Error("E0617".to_owned())
+    }
+
+    fn common(&self) -> DiagnosticBuilder<'tcx> {
+        let mut err = if self.t.references_error() {
+            self.sess.diagnostic().struct_dummy()
+        } else {
+            self.sess.struct_span_fatal_with_code(
+                self.span,
+                &format!("can't pass `{}` to variadic function", self.t),
+                self.code(),
+            )
+        };
+        if let Ok(snippet) = self.sess.codemap().span_to_snippet(self.span) {
+            err.span_suggestion(self.span,
+                                &format!("cast the value to `{}`", self.cast_ty),
+                                format!("{} as {}", snippet, self.cast_ty));
+        } else {
+            err.help(&format!("cast the value to `{}`", self.cast_ty));
+        }
+        err
+    }
+
+    fn extended(&self, mut err: DiagnosticBuilder<'tcx>) -> DiagnosticBuilder<'tcx> {
+        err.note(&format!("certain types, like `{}`, must be cast before passing them to a \
+                           variadic function, because of arcane ABI rules dictated by the C \
+                           standard",
+                          self.t));
+        err
+    }
+}
+
+pub struct SizedUnsizedCastError<'tcx> {
+    sess: &'tcx Session,
+    span: Span,
+    expr_ty: Ty<'tcx>,
+    cast_ty: String,
+}
+
+impl<'tcx> SizedUnsizedCastError<'tcx> {
+    pub fn new(sess: &'tcx Session,
+               span: Span,
+               expr_ty: Ty<'tcx>,
+               cast_ty: String) -> SizedUnsizedCastError<'tcx> {
+        SizedUnsizedCastError { sess, span, expr_ty, cast_ty }
+    }
+}
+
+impl<'tcx> StructuredDiagnostic<'tcx> for SizedUnsizedCastError<'tcx> {
+    fn session(&self) -> &Session { self.sess }
+
+    fn code(&self) -> DiagnosticId {
+        __diagnostic_used!(E0607);
+        DiagnosticId::Error("E0607".to_owned())
+    }
+
+    fn common(&self) -> DiagnosticBuilder<'tcx> {
+        if self.expr_ty.references_error() {
+            self.sess.diagnostic().struct_dummy()
+        } else {
+            self.sess.struct_span_fatal_with_code(
+                self.span,
+                &format!("cannot cast thin pointer `{}` to fat pointer `{}`",
+                         self.expr_ty,
+                         self.cast_ty),
+                self.code(),
+            )
+        }
+    }
+
+    fn extended(&self, mut err: DiagnosticBuilder<'tcx>) -> DiagnosticBuilder<'tcx> {
+        err.help(
+            "Thin pointers are \"simple\" pointers: they are purely a reference to a
+memory address.
+
+Fat pointers are pointers referencing \"Dynamically Sized Types\" (also
+called DST). DST don't have a statically known size, therefore they can
+only exist behind some kind of pointers that contain additional
+information. Slices and trait objects are DSTs. In the case of slices,
+the additional information the fat pointer holds is their size.
+
+To fix this error, don't try to cast directly between thin and fat
+pointers.
+
+For more information about casts, take a look at The Book:
+https://doc.rust-lang.org/book/first-edition/casting-between-types.html");
+        err
+    }
+}