]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/structured_errors.rs
Auto merge of #56502 - Zoxc:hir-func, r=eddyb
[rust.git] / src / librustc_typeck / structured_errors.rs
1 // Copyright 2018 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 rustc::session::Session;
12 use syntax_pos::Span;
13 use errors::{Applicability, DiagnosticId, DiagnosticBuilder};
14 use rustc::ty::{Ty, TypeFoldable};
15
16 pub trait StructuredDiagnostic<'tcx> {
17     fn session(&self) -> &Session;
18
19     fn code(&self) -> DiagnosticId;
20
21     fn common(&self) -> DiagnosticBuilder<'tcx>;
22
23     fn diagnostic(&self) -> DiagnosticBuilder<'tcx> {
24         let err = self.common();
25         if self.session().teach(&self.code()) {
26             self.extended(err)
27         } else {
28             self.regular(err)
29         }
30     }
31
32     fn regular(&self, err: DiagnosticBuilder<'tcx>) -> DiagnosticBuilder<'tcx> {
33         err
34     }
35
36     fn extended(&self, err: DiagnosticBuilder<'tcx>) -> DiagnosticBuilder<'tcx> {
37         err
38     }
39 }
40
41 pub struct VariadicError<'tcx> {
42     sess: &'tcx Session,
43     span: Span,
44     t: Ty<'tcx>,
45     cast_ty: &'tcx str,
46 }
47
48 impl<'tcx> VariadicError<'tcx> {
49     pub fn new(sess: &'tcx Session,
50                span: Span,
51                t: Ty<'tcx>,
52                cast_ty: &'tcx str) -> VariadicError<'tcx> {
53         VariadicError { sess, span, t, cast_ty }
54     }
55 }
56
57 impl<'tcx> StructuredDiagnostic<'tcx> for VariadicError<'tcx> {
58     fn session(&self) -> &Session { self.sess }
59
60     fn code(&self) -> DiagnosticId {
61         __diagnostic_used!(E0617);
62         DiagnosticId::Error("E0617".to_owned())
63     }
64
65     fn common(&self) -> DiagnosticBuilder<'tcx> {
66         let mut err = if self.t.references_error() {
67             self.sess.diagnostic().struct_dummy()
68         } else {
69             self.sess.struct_span_fatal_with_code(
70                 self.span,
71                 &format!("can't pass `{}` to variadic function", self.t),
72                 self.code(),
73             )
74         };
75         if let Ok(snippet) = self.sess.source_map().span_to_snippet(self.span) {
76             err.span_suggestion_with_applicability(
77                 self.span,
78                 &format!("cast the value to `{}`", self.cast_ty),
79                 format!("{} as {}", snippet, self.cast_ty),
80                 Applicability::MachineApplicable,
81             );
82         } else {
83             err.help(&format!("cast the value to `{}`", self.cast_ty));
84         }
85         err
86     }
87
88     fn extended(&self, mut err: DiagnosticBuilder<'tcx>) -> DiagnosticBuilder<'tcx> {
89         err.note(&format!("certain types, like `{}`, must be cast before passing them to a \
90                            variadic function, because of arcane ABI rules dictated by the C \
91                            standard",
92                           self.t));
93         err
94     }
95 }
96
97 pub struct SizedUnsizedCastError<'tcx> {
98     sess: &'tcx Session,
99     span: Span,
100     expr_ty: Ty<'tcx>,
101     cast_ty: String,
102 }
103
104 impl<'tcx> SizedUnsizedCastError<'tcx> {
105     pub fn new(sess: &'tcx Session,
106                span: Span,
107                expr_ty: Ty<'tcx>,
108                cast_ty: String) -> SizedUnsizedCastError<'tcx> {
109         SizedUnsizedCastError { sess, span, expr_ty, cast_ty }
110     }
111 }
112
113 impl<'tcx> StructuredDiagnostic<'tcx> for SizedUnsizedCastError<'tcx> {
114     fn session(&self) -> &Session { self.sess }
115
116     fn code(&self) -> DiagnosticId {
117         __diagnostic_used!(E0607);
118         DiagnosticId::Error("E0607".to_owned())
119     }
120
121     fn common(&self) -> DiagnosticBuilder<'tcx> {
122         if self.expr_ty.references_error() {
123             self.sess.diagnostic().struct_dummy()
124         } else {
125             self.sess.struct_span_fatal_with_code(
126                 self.span,
127                 &format!("cannot cast thin pointer `{}` to fat pointer `{}`",
128                          self.expr_ty,
129                          self.cast_ty),
130                 self.code(),
131             )
132         }
133     }
134
135     fn extended(&self, mut err: DiagnosticBuilder<'tcx>) -> DiagnosticBuilder<'tcx> {
136         err.help(
137             "Thin pointers are \"simple\" pointers: they are purely a reference to a
138 memory address.
139
140 Fat pointers are pointers referencing \"Dynamically Sized Types\" (also
141 called DST). DST don't have a statically known size, therefore they can
142 only exist behind some kind of pointers that contain additional
143 information. Slices and trait objects are DSTs. In the case of slices,
144 the additional information the fat pointer holds is their size.
145
146 To fix this error, don't try to cast directly between thin and fat
147 pointers.
148
149 For more information about casts, take a look at The Book:
150 https://doc.rust-lang.org/book/first-edition/casting-between-types.html");
151         err
152     }
153 }