1 // Copyright 2012-2015 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;
12 use ty::{self, BoundRegion, Region, Ty, TyCtxt};
15 use rustc_target::spec::abi;
17 use errors::{Applicability, DiagnosticBuilder};
22 #[derive(Clone, Copy, Debug)]
23 pub struct ExpectedFound<T> {
28 // Data structures used in type unification
29 #[derive(Clone, Debug)]
30 pub enum TypeError<'tcx> {
32 UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
33 AbiMismatch(ExpectedFound<abi::Abi>),
35 TupleSize(ExpectedFound<usize>),
36 FixedArraySize(ExpectedFound<u64>),
39 RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>),
40 RegionsInsufficientlyPolymorphic(BoundRegion, Region<'tcx>),
41 RegionsOverlyPolymorphic(BoundRegion, Region<'tcx>),
43 Sorts(ExpectedFound<Ty<'tcx>>),
44 IntMismatch(ExpectedFound<ty::IntVarValue>),
45 FloatMismatch(ExpectedFound<ast::FloatTy>),
46 Traits(ExpectedFound<DefId>),
47 VariadicMismatch(ExpectedFound<bool>),
49 /// Instantiating a type variable with the given type would have
50 /// created a cycle (because it appears somewhere within that
53 ProjectionMismatched(ExpectedFound<DefId>),
54 ProjectionBoundsLength(ExpectedFound<usize>),
55 ExistentialMismatch(ExpectedFound<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>),
58 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
59 pub enum UnconstrainedNumeric {
65 /// Explains the source of a type err in a short, human readable way. This is meant to be placed
66 /// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()`
67 /// afterwards to present additional details, particularly when it comes to lifetime-related
69 impl<'tcx> fmt::Display for TypeError<'tcx> {
70 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71 use self::TypeError::*;
72 fn report_maybe_different(f: &mut fmt::Formatter<'_>,
73 expected: &str, found: &str) -> fmt::Result {
74 // A naive approach to making sure that we're not reporting silly errors such as:
75 // (expected closure, found closure).
76 if expected == found {
77 write!(f, "expected {}, found a different {}", expected, found)
79 write!(f, "expected {}, found {}", expected, found)
84 CyclicTy(_) => write!(f, "cyclic type of infinite size"),
85 Mismatch => write!(f, "types differ"),
86 UnsafetyMismatch(values) => {
87 write!(f, "expected {} fn, found {} fn",
91 AbiMismatch(values) => {
92 write!(f, "expected {} fn, found {} fn",
96 Mutability => write!(f, "types differ in mutability"),
97 FixedArraySize(values) => {
98 write!(f, "expected an array with a fixed size of {} elements, \
99 found one with {} elements",
103 TupleSize(values) => {
104 write!(f, "expected a tuple with {} elements, \
105 found one with {} elements",
110 write!(f, "incorrect number of function parameters")
112 RegionsDoesNotOutlive(..) => {
113 write!(f, "lifetime mismatch")
115 RegionsInsufficientlyPolymorphic(br, _) => {
117 "expected bound lifetime parameter{}{}, found concrete lifetime",
118 if br.is_named() { " " } else { "" },
121 RegionsOverlyPolymorphic(br, _) => {
123 "expected concrete lifetime, found bound lifetime parameter{}{}",
124 if br.is_named() { " " } else { "" },
127 Sorts(values) => ty::tls::with(|tcx| {
128 report_maybe_different(f, &values.expected.sort_string(tcx),
129 &values.found.sort_string(tcx))
131 Traits(values) => ty::tls::with(|tcx| {
132 report_maybe_different(f,
133 &format!("trait `{}`",
134 tcx.item_path_str(values.expected)),
135 &format!("trait `{}`",
136 tcx.item_path_str(values.found)))
138 IntMismatch(ref values) => {
139 write!(f, "expected `{:?}`, found `{:?}`",
143 FloatMismatch(ref values) => {
144 write!(f, "expected `{:?}`, found `{:?}`",
148 VariadicMismatch(ref values) => {
149 write!(f, "expected {} fn, found {} function",
150 if values.expected { "variadic" } else { "non-variadic" },
151 if values.found { "variadic" } else { "non-variadic" })
153 ProjectionMismatched(ref values) => ty::tls::with(|tcx| {
154 write!(f, "expected {}, found {}",
155 tcx.item_path_str(values.expected),
156 tcx.item_path_str(values.found))
158 ProjectionBoundsLength(ref values) => {
159 write!(f, "expected {} associated type bindings, found {}",
163 ExistentialMismatch(ref values) => {
164 report_maybe_different(f, &format!("trait `{}`", values.expected),
165 &format!("trait `{}`", values.found))
171 impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> {
172 pub fn sort_string(&self, tcx: TyCtxt<'a, 'gcx, 'lcx>) -> Cow<'static, str> {
174 ty::Bool | ty::Char | ty::Int(_) |
175 ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => self.to_string().into(),
176 ty::Tuple(ref tys) if tys.is_empty() => self.to_string().into(),
178 ty::Adt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)).into(),
179 ty::Foreign(def_id) => format!("extern type `{}`", tcx.item_path_str(def_id)).into(),
181 match n.assert_usize(tcx) {
182 Some(n) => format!("array of {} elements", n).into(),
183 None => "array".into(),
186 ty::Slice(_) => "slice".into(),
187 ty::RawPtr(_) => "*-ptr".into(),
188 ty::Ref(region, ty, mutbl) => {
189 let tymut = ty::TypeAndMut { ty, mutbl };
190 let tymut_string = tymut.to_string();
191 if tymut_string == "_" || //unknown type name,
192 tymut_string.len() > 10 || //name longer than saying "reference",
193 region.to_string() != "" //... or a complex type
195 format!("{}reference", match mutbl {
196 hir::Mutability::MutMutable => "mutable ",
200 format!("&{}", tymut_string).into()
203 ty::FnDef(..) => "fn item".into(),
204 ty::FnPtr(_) => "fn pointer".into(),
205 ty::Dynamic(ref inner, ..) => {
206 format!("trait {}", tcx.item_path_str(inner.principal().def_id())).into()
208 ty::Closure(..) => "closure".into(),
209 ty::Generator(..) => "generator".into(),
210 ty::GeneratorWitness(..) => "generator witness".into(),
211 ty::Tuple(..) => "tuple".into(),
212 ty::Infer(ty::TyVar(_)) => "inferred type".into(),
213 ty::Infer(ty::IntVar(_)) => "integral variable".into(),
214 ty::Infer(ty::FloatVar(_)) => "floating-point variable".into(),
215 ty::Infer(ty::BoundTy(_)) |
216 ty::Infer(ty::FreshTy(_)) => "fresh type".into(),
217 ty::Infer(ty::FreshIntTy(_)) => "fresh integral type".into(),
218 ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(),
219 ty::Projection(_) => "associated type".into(),
220 ty::UnnormalizedProjection(_) => "non-normalized associated type".into(),
221 ty::Param(ref p) => {
225 "type parameter".into()
228 ty::Opaque(..) => "opaque type".into(),
229 ty::Error => "type error".into(),
234 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
235 pub fn note_and_explain_type_err(self,
236 db: &mut DiagnosticBuilder<'_>,
237 err: &TypeError<'tcx>,
239 use self::TypeError::*;
243 let expected_str = values.expected.sort_string(self);
244 let found_str = values.found.sort_string(self);
245 if expected_str == found_str && expected_str == "closure" {
246 db.note("no two closures, even if identical, have the same type");
247 db.help("consider boxing your closure and/or using it as a trait object");
249 if let (ty::Infer(ty::IntVar(_)), ty::Float(_)) =
250 (&values.found.sty, &values.expected.sty) // Issue #53280
252 if let Ok(snippet) = self.sess.source_map().span_to_snippet(sp) {
253 if snippet.chars().all(|c| c.is_digit(10) || c == '-' || c == '_') {
254 db.span_suggestion_with_applicability(
256 "use a float literal",
257 format!("{}.0", snippet),
258 Applicability::MachineApplicable
265 // Watch out for various cases of cyclic types and try to explain.
266 if ty.is_closure() || ty.is_generator() {
267 db.note("closures cannot capture themselves or take themselves as argument;\n\
268 this error may be the result of a recent compiler bug-fix,\n\
269 see https://github.com/rust-lang/rust/issues/46062 for more details");