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).
This commit is contained in:
parent
7d41cbad6a
commit
3dac0f5a9c
5 changed files with 167 additions and 48 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 => {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
150
src/librustc_typeck/structured_errors.rs
Normal file
150
src/librustc_typeck/structured_errors.rs
Normal file
|
|
@ -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
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue