1 use crate::ty::print::{with_forced_trimmed_paths, FmtPrinter, PrettyPrinter};
2 use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt};
3 use rustc_errors::pluralize;
5 use rustc_hir::def::{CtorOf, DefKind};
6 use rustc_hir::def_id::DefId;
7 use rustc_span::symbol::Symbol;
8 use rustc_target::spec::abi;
10 use std::collections::hash_map::DefaultHasher;
11 use std::hash::{Hash, Hasher};
12 use std::path::PathBuf;
14 #[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable, Lift)]
15 pub struct ExpectedFound<T> {
20 impl<T> ExpectedFound<T> {
21 pub fn new(a_is_expected: bool, a: T, b: T) -> Self {
23 ExpectedFound { expected: a, found: b }
25 ExpectedFound { expected: b, found: a }
30 // Data structures used in type unification
31 #[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift)]
32 #[rustc_pass_by_value]
33 pub enum TypeError<'tcx> {
35 ConstnessMismatch(ExpectedFound<ty::BoundConstness>),
36 PolarityMismatch(ExpectedFound<ty::ImplPolarity>),
37 UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
38 AbiMismatch(ExpectedFound<abi::Abi>),
40 ArgumentMutability(usize),
41 TupleSize(ExpectedFound<usize>),
42 FixedArraySize(ExpectedFound<u64>),
44 FieldMisMatch(Symbol, Symbol),
46 RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>),
47 RegionsInsufficientlyPolymorphic(BoundRegionKind, Region<'tcx>),
48 RegionsOverlyPolymorphic(BoundRegionKind, Region<'tcx>),
49 RegionsPlaceholderMismatch,
51 Sorts(ExpectedFound<Ty<'tcx>>),
52 ArgumentSorts(ExpectedFound<Ty<'tcx>>, usize),
53 IntMismatch(ExpectedFound<ty::IntVarValue>),
54 FloatMismatch(ExpectedFound<ty::FloatTy>),
55 Traits(ExpectedFound<DefId>),
56 VariadicMismatch(ExpectedFound<bool>),
58 /// Instantiating a type variable with the given type would have
59 /// created a cycle (because it appears somewhere within that
62 CyclicConst(ty::Const<'tcx>),
63 ProjectionMismatched(ExpectedFound<DefId>),
64 ExistentialMismatch(ExpectedFound<&'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>>),
65 ConstMismatch(ExpectedFound<ty::Const<'tcx>>),
68 /// Safe `#[target_feature]` functions are not assignable to safe function pointers.
69 TargetFeatureCast(DefId),
73 pub fn involves_regions(self) -> bool {
75 TypeError::RegionsDoesNotOutlive(_, _)
76 | TypeError::RegionsInsufficientlyPolymorphic(_, _)
77 | TypeError::RegionsOverlyPolymorphic(_, _)
78 | TypeError::RegionsPlaceholderMismatch => true,
84 /// Explains the source of a type err in a short, human readable way. This is meant to be placed
85 /// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()`
86 /// afterwards to present additional details, particularly when it comes to lifetime-related
88 impl<'tcx> TypeError<'tcx> {
89 pub fn to_string(self, tcx: TyCtxt<'tcx>) -> Cow<'static, str> {
90 use self::TypeError::*;
91 fn report_maybe_different(expected: &str, found: &str) -> String {
92 // A naive approach to making sure that we're not reporting silly errors such as:
93 // (expected closure, found closure).
94 if expected == found {
95 format!("expected {}, found a different {}", expected, found)
97 format!("expected {}, found {}", expected, found)
101 let br_string = |br: ty::BoundRegionKind| match br {
102 ty::BrNamed(_, name) => format!(" {}", name),
107 CyclicTy(_) => "cyclic type of infinite size".into(),
108 CyclicConst(_) => "encountered a self-referencing constant".into(),
109 Mismatch => "types differ".into(),
110 ConstnessMismatch(values) => {
111 format!("expected {} bound, found {} bound", values.expected, values.found).into()
113 PolarityMismatch(values) => {
114 format!("expected {} polarity, found {} polarity", values.expected, values.found)
117 UnsafetyMismatch(values) => {
118 format!("expected {} fn, found {} fn", values.expected, values.found).into()
120 AbiMismatch(values) => {
121 format!("expected {} fn, found {} fn", values.expected, values.found).into()
123 ArgumentMutability(_) | Mutability => "types differ in mutability".into(),
124 TupleSize(values) => format!(
125 "expected a tuple with {} element{}, found one with {} element{}",
127 pluralize!(values.expected),
129 pluralize!(values.found)
132 FixedArraySize(values) => format!(
133 "expected an array with a fixed size of {} element{}, found one with {} element{}",
135 pluralize!(values.expected),
137 pluralize!(values.found)
140 ArgCount => "incorrect number of function parameters".into(),
141 FieldMisMatch(adt, field) => format!("field type mismatch: {}.{}", adt, field).into(),
142 RegionsDoesNotOutlive(..) => "lifetime mismatch".into(),
143 // Actually naming the region here is a bit confusing because context is lacking
144 RegionsInsufficientlyPolymorphic(..) => {
145 "one type is more general than the other".into()
147 RegionsOverlyPolymorphic(br, _) => format!(
148 "expected concrete lifetime, found bound lifetime parameter{}",
152 RegionsPlaceholderMismatch => "one type is more general than the other".into(),
153 ArgumentSorts(values, _) | Sorts(values) => {
154 let mut expected = values.expected.sort_string(tcx);
155 let mut found = values.found.sort_string(tcx);
156 if expected == found {
157 expected = values.expected.sort_string(tcx);
158 found = values.found.sort_string(tcx);
160 report_maybe_different(&expected, &found).into()
163 let (mut expected, mut found) = with_forced_trimmed_paths!((
164 tcx.def_path_str(values.expected),
165 tcx.def_path_str(values.found),
167 if expected == found {
168 expected = tcx.def_path_str(values.expected);
169 found = tcx.def_path_str(values.found);
171 report_maybe_different(&format!("trait `{expected}`"), &format!("trait `{found}`"))
174 IntMismatch(ref values) => {
175 let expected = match values.expected {
176 ty::IntVarValue::IntType(ty) => ty.name_str(),
177 ty::IntVarValue::UintType(ty) => ty.name_str(),
179 let found = match values.found {
180 ty::IntVarValue::IntType(ty) => ty.name_str(),
181 ty::IntVarValue::UintType(ty) => ty.name_str(),
183 format!("expected `{}`, found `{}`", expected, found).into()
185 FloatMismatch(ref values) => format!(
186 "expected `{}`, found `{}`",
187 values.expected.name_str(),
188 values.found.name_str()
191 VariadicMismatch(ref values) => format!(
192 "expected {} fn, found {} function",
193 if values.expected { "variadic" } else { "non-variadic" },
194 if values.found { "variadic" } else { "non-variadic" }
197 ProjectionMismatched(ref values) => format!(
198 "expected {}, found {}",
199 tcx.def_path_str(values.expected),
200 tcx.def_path_str(values.found)
203 ExistentialMismatch(ref values) => report_maybe_different(
204 &format!("trait `{}`", values.expected),
205 &format!("trait `{}`", values.found),
208 ConstMismatch(ref values) => {
209 format!("expected `{}`, found `{}`", values.expected, values.found).into()
211 IntrinsicCast => "cannot coerce intrinsics to function pointers".into(),
212 TargetFeatureCast(_) => {
213 "cannot coerce functions with `#[target_feature]` to safe function pointers".into()
219 impl<'tcx> TypeError<'tcx> {
220 pub fn must_include_note(self) -> bool {
221 use self::TypeError::*;
223 CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | ConstnessMismatch(_)
224 | PolarityMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_)
225 | ArgumentSorts(..) | Sorts(_) | IntMismatch(_) | FloatMismatch(_)
226 | VariadicMismatch(_) | TargetFeatureCast(_) => false,
229 | ArgumentMutability(_)
233 | RegionsDoesNotOutlive(..)
234 | RegionsInsufficientlyPolymorphic(..)
235 | RegionsOverlyPolymorphic(..)
236 | RegionsPlaceholderMismatch
238 | ProjectionMismatched(_)
239 | ExistentialMismatch(_)
241 | IntrinsicCast => true,
246 impl<'tcx> Ty<'tcx> {
247 pub fn sort_string(self, tcx: TyCtxt<'tcx>) -> Cow<'static, str> {
249 ty::Foreign(def_id) => format!("extern type `{}`", tcx.def_path_str(def_id)).into(),
250 ty::FnDef(def_id, ..) => match tcx.def_kind(def_id) {
251 DefKind::Ctor(CtorOf::Struct, _) => "struct constructor".into(),
252 DefKind::Ctor(CtorOf::Variant, _) => "enum constructor".into(),
253 _ => "fn item".into(),
255 ty::FnPtr(_) => "fn pointer".into(),
256 ty::Dynamic(ref inner, ..) if let Some(principal) = inner.principal() => {
257 format!("`dyn {}`", tcx.def_path_str(principal.def_id())).into()
259 ty::Dynamic(..) => "trait object".into(),
260 ty::Closure(..) => "closure".into(),
261 ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(),
262 ty::GeneratorWitness(..) |
263 ty::GeneratorWitnessMIR(..) => "generator witness".into(),
264 ty::Infer(ty::TyVar(_)) => "inferred type".into(),
265 ty::Infer(ty::IntVar(_)) => "integer".into(),
266 ty::Infer(ty::FloatVar(_)) => "floating-point number".into(),
267 ty::Placeholder(..) => "placeholder type".into(),
268 ty::Bound(..) => "bound type".into(),
269 ty::Infer(ty::FreshTy(_)) => "fresh type".into(),
270 ty::Infer(ty::FreshIntTy(_)) => "fresh integral type".into(),
271 ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(),
272 ty::Alias(ty::Projection, _) => "associated type".into(),
273 ty::Param(p) => format!("type parameter `{p}`").into(),
274 ty::Alias(ty::Opaque, ..) => "opaque type".into(),
275 ty::Error(_) => "type error".into(),
277 let width = tcx.sess.diagnostic_width();
278 let length_limit = std::cmp::max(width / 4, 15);
279 format!("`{}`", tcx.ty_string_with_limit(self, length_limit)).into()
284 pub fn prefix_string(self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
294 | ty::Never => "type".into(),
295 ty::Tuple(ref tys) if tys.is_empty() => "unit type".into(),
296 ty::Adt(def, _) => def.descr().into(),
297 ty::Foreign(_) => "extern type".into(),
298 ty::Array(..) => "array".into(),
299 ty::Slice(_) => "slice".into(),
300 ty::RawPtr(_) => "raw pointer".into(),
301 ty::Ref(.., mutbl) => match mutbl {
302 hir::Mutability::Mut => "mutable reference",
306 ty::FnDef(def_id, ..) => match tcx.def_kind(def_id) {
307 DefKind::Ctor(CtorOf::Struct, _) => "struct constructor".into(),
308 DefKind::Ctor(CtorOf::Variant, _) => "enum constructor".into(),
309 _ => "fn item".into(),
311 ty::FnPtr(_) => "fn pointer".into(),
312 ty::Dynamic(..) => "trait object".into(),
313 ty::Closure(..) => "closure".into(),
314 ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(),
315 ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) => "generator witness".into(),
316 ty::Tuple(..) => "tuple".into(),
317 ty::Placeholder(..) => "higher-ranked type".into(),
318 ty::Bound(..) => "bound type variable".into(),
319 ty::Alias(ty::Projection, _) => "associated type".into(),
320 ty::Param(_) => "type parameter".into(),
321 ty::Alias(ty::Opaque, ..) => "opaque type".into(),
326 impl<'tcx> TyCtxt<'tcx> {
327 pub fn ty_string_with_limit(self, ty: Ty<'tcx>, length_limit: usize) -> String {
328 let mut type_limit = 50;
329 let regular = FmtPrinter::new(self, hir::def::Namespace::TypeNS)
330 .pretty_print_type(ty)
331 .expect("could not write to `String`")
333 if regular.len() <= length_limit {
338 // Look for the longest properly trimmed path that still fits in length_limit.
339 short = with_forced_trimmed_paths!(
340 FmtPrinter::new_with_limit(
342 hir::def::Namespace::TypeNS,
343 rustc_session::Limit(type_limit),
345 .pretty_print_type(ty)
346 .expect("could not write to `String`")
349 if short.len() <= length_limit || type_limit == 0 {
357 pub fn short_ty_string(self, ty: Ty<'tcx>) -> (String, Option<PathBuf>) {
358 let width = self.sess.diagnostic_width();
359 let length_limit = width.saturating_sub(30);
360 let regular = FmtPrinter::new(self, hir::def::Namespace::TypeNS)
361 .pretty_print_type(ty)
362 .expect("could not write to `String`")
364 if regular.len() <= width {
365 return (regular, None);
367 let short = self.ty_string_with_limit(ty, length_limit);
368 if regular == short {
369 return (regular, None);
371 // Multiple types might be shortened in a single error, ensure we create a file for each.
372 let mut s = DefaultHasher::new();
374 let hash = s.finish();
375 let path = self.output_filenames(()).temp_path_ext(&format!("long-type-{hash}.txt"), None);
376 match std::fs::write(&path, ®ular) {
377 Ok(_) => (short, Some(path)),
378 Err(_) => (regular, None),