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; 4 use rustc_hir as hir; 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; 9 use std::borrow::Cow; 10 use std::collections::hash_map::DefaultHasher; 11 use std::hash::{Hash, Hasher}; 12 use std::path::PathBuf; 13 14 #[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable, Lift)] 15 pub struct ExpectedFound<T> { 16 pub expected: T, 17 pub found: T, 18 } 19 20 impl<T> ExpectedFound<T> { new(a_is_expected: bool, a: T, b: T) -> Self21 pub fn new(a_is_expected: bool, a: T, b: T) -> Self { 22 if a_is_expected { 23 ExpectedFound { expected: a, found: b } 24 } else { 25 ExpectedFound { expected: b, found: a } 26 } 27 } 28 } 29 30 // Data structures used in type unification 31 #[derive(Copy, Clone, Debug, TypeVisitable, Lift, PartialEq, Eq)] 32 #[rustc_pass_by_value] 33 pub enum TypeError<'tcx> { 34 Mismatch, 35 ConstnessMismatch(ExpectedFound<ty::BoundConstness>), 36 PolarityMismatch(ExpectedFound<ty::ImplPolarity>), 37 UnsafetyMismatch(ExpectedFound<hir::Unsafety>), 38 AbiMismatch(ExpectedFound<abi::Abi>), 39 Mutability, 40 ArgumentMutability(usize), 41 TupleSize(ExpectedFound<usize>), 42 FixedArraySize(ExpectedFound<u64>), 43 ArgCount, 44 FieldMisMatch(Symbol, Symbol), 45 46 RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>), 47 RegionsInsufficientlyPolymorphic(BoundRegionKind, Region<'tcx>), 48 RegionsPlaceholderMismatch, 49 50 Sorts(ExpectedFound<Ty<'tcx>>), 51 ArgumentSorts(ExpectedFound<Ty<'tcx>>, usize), 52 IntMismatch(ExpectedFound<ty::IntVarValue>), 53 FloatMismatch(ExpectedFound<ty::FloatTy>), 54 Traits(ExpectedFound<DefId>), 55 VariadicMismatch(ExpectedFound<bool>), 56 57 /// Instantiating a type variable with the given type would have 58 /// created a cycle (because it appears somewhere within that 59 /// type). 60 CyclicTy(Ty<'tcx>), 61 CyclicConst(ty::Const<'tcx>), 62 ProjectionMismatched(ExpectedFound<DefId>), 63 ExistentialMismatch(ExpectedFound<&'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>>), 64 ConstMismatch(ExpectedFound<ty::Const<'tcx>>), 65 66 IntrinsicCast, 67 /// Safe `#[target_feature]` functions are not assignable to safe function pointers. 68 TargetFeatureCast(DefId), 69 } 70 71 impl TypeError<'_> { involves_regions(self) -> bool72 pub fn involves_regions(self) -> bool { 73 match self { 74 TypeError::RegionsDoesNotOutlive(_, _) 75 | TypeError::RegionsInsufficientlyPolymorphic(_, _) 76 | TypeError::RegionsPlaceholderMismatch => true, 77 _ => false, 78 } 79 } 80 } 81 82 /// Explains the source of a type err in a short, human readable way. This is meant to be placed 83 /// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()` 84 /// afterwards to present additional details, particularly when it comes to lifetime-related 85 /// errors. 86 impl<'tcx> TypeError<'tcx> { to_string(self, tcx: TyCtxt<'tcx>) -> Cow<'static, str>87 pub fn to_string(self, tcx: TyCtxt<'tcx>) -> Cow<'static, str> { 88 use self::TypeError::*; 89 fn report_maybe_different(expected: &str, found: &str) -> String { 90 // A naive approach to making sure that we're not reporting silly errors such as: 91 // (expected closure, found closure). 92 if expected == found { 93 format!("expected {}, found a different {}", expected, found) 94 } else { 95 format!("expected {}, found {}", expected, found) 96 } 97 } 98 99 match self { 100 CyclicTy(_) => "cyclic type of infinite size".into(), 101 CyclicConst(_) => "encountered a self-referencing constant".into(), 102 Mismatch => "types differ".into(), 103 ConstnessMismatch(values) => { 104 format!("expected {} bound, found {} bound", values.expected, values.found).into() 105 } 106 PolarityMismatch(values) => { 107 format!("expected {} polarity, found {} polarity", values.expected, values.found) 108 .into() 109 } 110 UnsafetyMismatch(values) => { 111 format!("expected {} fn, found {} fn", values.expected, values.found).into() 112 } 113 AbiMismatch(values) => { 114 format!("expected {} fn, found {} fn", values.expected, values.found).into() 115 } 116 ArgumentMutability(_) | Mutability => "types differ in mutability".into(), 117 TupleSize(values) => format!( 118 "expected a tuple with {} element{}, found one with {} element{}", 119 values.expected, 120 pluralize!(values.expected), 121 values.found, 122 pluralize!(values.found) 123 ) 124 .into(), 125 FixedArraySize(values) => format!( 126 "expected an array with a fixed size of {} element{}, found one with {} element{}", 127 values.expected, 128 pluralize!(values.expected), 129 values.found, 130 pluralize!(values.found) 131 ) 132 .into(), 133 ArgCount => "incorrect number of function parameters".into(), 134 FieldMisMatch(adt, field) => format!("field type mismatch: {}.{}", adt, field).into(), 135 RegionsDoesNotOutlive(..) => "lifetime mismatch".into(), 136 // Actually naming the region here is a bit confusing because context is lacking 137 RegionsInsufficientlyPolymorphic(..) => { 138 "one type is more general than the other".into() 139 } 140 RegionsPlaceholderMismatch => "one type is more general than the other".into(), 141 ArgumentSorts(values, _) | Sorts(values) => { 142 let expected = values.expected.sort_string(tcx); 143 let found = values.found.sort_string(tcx); 144 report_maybe_different(&expected, &found).into() 145 } 146 Traits(values) => { 147 let (mut expected, mut found) = with_forced_trimmed_paths!(( 148 tcx.def_path_str(values.expected), 149 tcx.def_path_str(values.found), 150 )); 151 if expected == found { 152 expected = tcx.def_path_str(values.expected); 153 found = tcx.def_path_str(values.found); 154 } 155 report_maybe_different(&format!("trait `{expected}`"), &format!("trait `{found}`")) 156 .into() 157 } 158 IntMismatch(ref values) => { 159 let expected = match values.expected { 160 ty::IntVarValue::IntType(ty) => ty.name_str(), 161 ty::IntVarValue::UintType(ty) => ty.name_str(), 162 }; 163 let found = match values.found { 164 ty::IntVarValue::IntType(ty) => ty.name_str(), 165 ty::IntVarValue::UintType(ty) => ty.name_str(), 166 }; 167 format!("expected `{}`, found `{}`", expected, found).into() 168 } 169 FloatMismatch(ref values) => format!( 170 "expected `{}`, found `{}`", 171 values.expected.name_str(), 172 values.found.name_str() 173 ) 174 .into(), 175 VariadicMismatch(ref values) => format!( 176 "expected {} fn, found {} function", 177 if values.expected { "variadic" } else { "non-variadic" }, 178 if values.found { "variadic" } else { "non-variadic" } 179 ) 180 .into(), 181 ProjectionMismatched(ref values) => format!( 182 "expected `{}`, found `{}`", 183 tcx.def_path_str(values.expected), 184 tcx.def_path_str(values.found) 185 ) 186 .into(), 187 ExistentialMismatch(ref values) => report_maybe_different( 188 &format!("trait `{}`", values.expected), 189 &format!("trait `{}`", values.found), 190 ) 191 .into(), 192 ConstMismatch(ref values) => { 193 format!("expected `{}`, found `{}`", values.expected, values.found).into() 194 } 195 IntrinsicCast => "cannot coerce intrinsics to function pointers".into(), 196 TargetFeatureCast(_) => { 197 "cannot coerce functions with `#[target_feature]` to safe function pointers".into() 198 } 199 } 200 } 201 } 202 203 impl<'tcx> TypeError<'tcx> { must_include_note(self) -> bool204 pub fn must_include_note(self) -> bool { 205 use self::TypeError::*; 206 match self { 207 CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | ConstnessMismatch(_) 208 | PolarityMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_) 209 | ArgumentSorts(..) | Sorts(_) | IntMismatch(_) | FloatMismatch(_) 210 | VariadicMismatch(_) | TargetFeatureCast(_) => false, 211 212 Mutability 213 | ArgumentMutability(_) 214 | TupleSize(_) 215 | ArgCount 216 | FieldMisMatch(..) 217 | RegionsDoesNotOutlive(..) 218 | RegionsInsufficientlyPolymorphic(..) 219 | RegionsPlaceholderMismatch 220 | Traits(_) 221 | ProjectionMismatched(_) 222 | ExistentialMismatch(_) 223 | ConstMismatch(_) 224 | IntrinsicCast => true, 225 } 226 } 227 } 228 229 impl<'tcx> Ty<'tcx> { sort_string(self, tcx: TyCtxt<'tcx>) -> Cow<'static, str>230 pub fn sort_string(self, tcx: TyCtxt<'tcx>) -> Cow<'static, str> { 231 match *self.kind() { 232 ty::Foreign(def_id) => format!("extern type `{}`", tcx.def_path_str(def_id)).into(), 233 ty::FnDef(def_id, ..) => match tcx.def_kind(def_id) { 234 DefKind::Ctor(CtorOf::Struct, _) => "struct constructor".into(), 235 DefKind::Ctor(CtorOf::Variant, _) => "enum constructor".into(), 236 _ => "fn item".into(), 237 }, 238 ty::FnPtr(_) => "fn pointer".into(), 239 ty::Dynamic(ref inner, ..) if let Some(principal) = inner.principal() => { 240 format!("`dyn {}`", tcx.def_path_str(principal.def_id())).into() 241 } 242 ty::Dynamic(..) => "trait object".into(), 243 ty::Closure(..) => "closure".into(), 244 ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(), 245 ty::GeneratorWitness(..) | 246 ty::GeneratorWitnessMIR(..) => "generator witness".into(), 247 ty::Infer(ty::TyVar(_)) => "inferred type".into(), 248 ty::Infer(ty::IntVar(_)) => "integer".into(), 249 ty::Infer(ty::FloatVar(_)) => "floating-point number".into(), 250 ty::Placeholder(..) => "placeholder type".into(), 251 ty::Bound(..) => "bound type".into(), 252 ty::Infer(ty::FreshTy(_)) => "fresh type".into(), 253 ty::Infer(ty::FreshIntTy(_)) => "fresh integral type".into(), 254 ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(), 255 ty::Alias(ty::Projection | ty::Inherent, _) => "associated type".into(), 256 ty::Param(p) => format!("type parameter `{p}`").into(), 257 ty::Alias(ty::Opaque, ..) => if tcx.ty_is_opaque_future(self) { "future".into() } else { "opaque type".into() }, 258 ty::Error(_) => "type error".into(), 259 _ => { 260 let width = tcx.sess.diagnostic_width(); 261 let length_limit = std::cmp::max(width / 4, 15); 262 format!("`{}`", tcx.ty_string_with_limit(self, length_limit)).into() 263 } 264 } 265 } 266 prefix_string(self, tcx: TyCtxt<'_>) -> Cow<'static, str>267 pub fn prefix_string(self, tcx: TyCtxt<'_>) -> Cow<'static, str> { 268 match *self.kind() { 269 ty::Infer(_) 270 | ty::Error(_) 271 | ty::Bool 272 | ty::Char 273 | ty::Int(_) 274 | ty::Uint(_) 275 | ty::Float(_) 276 | ty::Str 277 | ty::Never => "type".into(), 278 ty::Tuple(ref tys) if tys.is_empty() => "unit type".into(), 279 ty::Adt(def, _) => def.descr().into(), 280 ty::Foreign(_) => "extern type".into(), 281 ty::Array(..) => "array".into(), 282 ty::Slice(_) => "slice".into(), 283 ty::RawPtr(_) => "raw pointer".into(), 284 ty::Ref(.., mutbl) => match mutbl { 285 hir::Mutability::Mut => "mutable reference", 286 _ => "reference", 287 } 288 .into(), 289 ty::FnDef(def_id, ..) => match tcx.def_kind(def_id) { 290 DefKind::Ctor(CtorOf::Struct, _) => "struct constructor".into(), 291 DefKind::Ctor(CtorOf::Variant, _) => "enum constructor".into(), 292 _ => "fn item".into(), 293 }, 294 ty::FnPtr(_) => "fn pointer".into(), 295 ty::Dynamic(..) => "trait object".into(), 296 ty::Closure(..) => "closure".into(), 297 ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(), 298 ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) => "generator witness".into(), 299 ty::Tuple(..) => "tuple".into(), 300 ty::Placeholder(..) => "higher-ranked type".into(), 301 ty::Bound(..) => "bound type variable".into(), 302 ty::Alias(ty::Projection | ty::Inherent, _) => "associated type".into(), 303 ty::Alias(ty::Weak, _) => "type alias".into(), 304 ty::Param(_) => "type parameter".into(), 305 ty::Alias(ty::Opaque, ..) => "opaque type".into(), 306 } 307 } 308 } 309 310 impl<'tcx> TyCtxt<'tcx> { ty_string_with_limit(self, ty: Ty<'tcx>, length_limit: usize) -> String311 pub fn ty_string_with_limit(self, ty: Ty<'tcx>, length_limit: usize) -> String { 312 let mut type_limit = 50; 313 let regular = FmtPrinter::new(self, hir::def::Namespace::TypeNS) 314 .pretty_print_type(ty) 315 .expect("could not write to `String`") 316 .into_buffer(); 317 if regular.len() <= length_limit { 318 return regular; 319 } 320 let mut short; 321 loop { 322 // Look for the longest properly trimmed path that still fits in length_limit. 323 short = with_forced_trimmed_paths!( 324 FmtPrinter::new_with_limit( 325 self, 326 hir::def::Namespace::TypeNS, 327 rustc_session::Limit(type_limit), 328 ) 329 .pretty_print_type(ty) 330 .expect("could not write to `String`") 331 .into_buffer() 332 ); 333 if short.len() <= length_limit || type_limit == 0 { 334 break; 335 } 336 type_limit -= 1; 337 } 338 short 339 } 340 short_ty_string(self, ty: Ty<'tcx>) -> (String, Option<PathBuf>)341 pub fn short_ty_string(self, ty: Ty<'tcx>) -> (String, Option<PathBuf>) { 342 let width = self.sess.diagnostic_width(); 343 let length_limit = width.saturating_sub(30); 344 let regular = FmtPrinter::new(self, hir::def::Namespace::TypeNS) 345 .pretty_print_type(ty) 346 .expect("could not write to `String`") 347 .into_buffer(); 348 if regular.len() <= width { 349 return (regular, None); 350 } 351 let short = self.ty_string_with_limit(ty, length_limit); 352 if regular == short { 353 return (regular, None); 354 } 355 // Multiple types might be shortened in a single error, ensure we create a file for each. 356 let mut s = DefaultHasher::new(); 357 ty.hash(&mut s); 358 let hash = s.finish(); 359 let path = self.output_filenames(()).temp_path_ext(&format!("long-type-{hash}.txt"), None); 360 match std::fs::write(&path, ®ular) { 361 Ok(_) => (short, Some(path)), 362 Err(_) => (regular, None), 363 } 364 } 365 } 366