1 use crate::traits::{ObligationCause, ObligationCauseCode}; 2 use crate::ty::diagnostics::suggest_constraining_type_param; 3 use crate::ty::print::{FmtPrinter, Printer}; 4 use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt}; 5 use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect}; 6 use rustc_errors::{pluralize, DiagnosticBuilder}; 7 use rustc_hir as hir; 8 use rustc_hir::def_id::DefId; 9 use rustc_span::symbol::{sym, Symbol}; 10 use rustc_span::{BytePos, MultiSpan, Span}; 11 use rustc_target::spec::abi; 12 13 use std::borrow::Cow; 14 use std::fmt; 15 16 #[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable)] 17 pub struct ExpectedFound<T> { 18 pub expected: T, 19 pub found: T, 20 } 21 22 impl<T> ExpectedFound<T> { new(a_is_expected: bool, a: T, b: T) -> Self23 pub fn new(a_is_expected: bool, a: T, b: T) -> Self { 24 if a_is_expected { 25 ExpectedFound { expected: a, found: b } 26 } else { 27 ExpectedFound { expected: b, found: a } 28 } 29 } 30 } 31 32 // Data structures used in type unification 33 #[derive(Clone, Debug, TypeFoldable)] 34 pub enum TypeError<'tcx> { 35 Mismatch, 36 ConstnessMismatch(ExpectedFound<ty::BoundConstness>), 37 PolarityMismatch(ExpectedFound<ty::ImplPolarity>), 38 UnsafetyMismatch(ExpectedFound<hir::Unsafety>), 39 AbiMismatch(ExpectedFound<abi::Abi>), 40 Mutability, 41 ArgumentMutability(usize), 42 TupleSize(ExpectedFound<usize>), 43 FixedArraySize(ExpectedFound<u64>), 44 ArgCount, 45 FieldMisMatch(Symbol, Symbol), 46 47 RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>), 48 RegionsInsufficientlyPolymorphic(BoundRegionKind, Region<'tcx>), 49 RegionsOverlyPolymorphic(BoundRegionKind, Region<'tcx>), 50 RegionsPlaceholderMismatch, 51 52 Sorts(ExpectedFound<Ty<'tcx>>), 53 ArgumentSorts(ExpectedFound<Ty<'tcx>>, usize), 54 IntMismatch(ExpectedFound<ty::IntVarValue>), 55 FloatMismatch(ExpectedFound<ty::FloatTy>), 56 Traits(ExpectedFound<DefId>), 57 VariadicMismatch(ExpectedFound<bool>), 58 59 /// Instantiating a type variable with the given type would have 60 /// created a cycle (because it appears somewhere within that 61 /// type). 62 CyclicTy(Ty<'tcx>), 63 CyclicConst(&'tcx ty::Const<'tcx>), 64 ProjectionMismatched(ExpectedFound<DefId>), 65 ExistentialMismatch( 66 ExpectedFound<&'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>>, 67 ), 68 ObjectUnsafeCoercion(DefId), 69 ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>), 70 71 IntrinsicCast, 72 /// Safe `#[target_feature]` functions are not assignable to safe function pointers. 73 TargetFeatureCast(DefId), 74 } 75 76 /// Explains the source of a type err in a short, human readable way. This is meant to be placed 77 /// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()` 78 /// afterwards to present additional details, particularly when it comes to lifetime-related 79 /// errors. 80 impl<'tcx> fmt::Display for TypeError<'tcx> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result81 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 82 use self::TypeError::*; 83 fn report_maybe_different( 84 f: &mut fmt::Formatter<'_>, 85 expected: &str, 86 found: &str, 87 ) -> fmt::Result { 88 // A naive approach to making sure that we're not reporting silly errors such as: 89 // (expected closure, found closure). 90 if expected == found { 91 write!(f, "expected {}, found a different {}", expected, found) 92 } else { 93 write!(f, "expected {}, found {}", expected, found) 94 } 95 } 96 97 let br_string = |br: ty::BoundRegionKind| match br { 98 ty::BrNamed(_, name) => format!(" {}", name), 99 _ => String::new(), 100 }; 101 102 match *self { 103 CyclicTy(_) => write!(f, "cyclic type of infinite size"), 104 CyclicConst(_) => write!(f, "encountered a self-referencing constant"), 105 Mismatch => write!(f, "types differ"), 106 ConstnessMismatch(values) => { 107 write!(f, "expected {} bound, found {} bound", values.expected, values.found) 108 } 109 PolarityMismatch(values) => { 110 write!(f, "expected {} polarity, found {} polarity", values.expected, values.found) 111 } 112 UnsafetyMismatch(values) => { 113 write!(f, "expected {} fn, found {} fn", values.expected, values.found) 114 } 115 AbiMismatch(values) => { 116 write!(f, "expected {} fn, found {} fn", values.expected, values.found) 117 } 118 ArgumentMutability(_) | Mutability => write!(f, "types differ in mutability"), 119 TupleSize(values) => write!( 120 f, 121 "expected a tuple with {} element{}, \ 122 found one with {} element{}", 123 values.expected, 124 pluralize!(values.expected), 125 values.found, 126 pluralize!(values.found) 127 ), 128 FixedArraySize(values) => write!( 129 f, 130 "expected an array with a fixed size of {} element{}, \ 131 found one with {} element{}", 132 values.expected, 133 pluralize!(values.expected), 134 values.found, 135 pluralize!(values.found) 136 ), 137 ArgCount => write!(f, "incorrect number of function parameters"), 138 FieldMisMatch(adt, field) => write!(f, "field type mismatch: {}.{}", adt, field), 139 RegionsDoesNotOutlive(..) => write!(f, "lifetime mismatch"), 140 RegionsInsufficientlyPolymorphic(br, _) => write!( 141 f, 142 "expected bound lifetime parameter{}, found concrete lifetime", 143 br_string(br) 144 ), 145 RegionsOverlyPolymorphic(br, _) => write!( 146 f, 147 "expected concrete lifetime, found bound lifetime parameter{}", 148 br_string(br) 149 ), 150 RegionsPlaceholderMismatch => write!(f, "one type is more general than the other"), 151 ArgumentSorts(values, _) | Sorts(values) => ty::tls::with(|tcx| { 152 report_maybe_different( 153 f, 154 &values.expected.sort_string(tcx), 155 &values.found.sort_string(tcx), 156 ) 157 }), 158 Traits(values) => ty::tls::with(|tcx| { 159 report_maybe_different( 160 f, 161 &format!("trait `{}`", tcx.def_path_str(values.expected)), 162 &format!("trait `{}`", tcx.def_path_str(values.found)), 163 ) 164 }), 165 IntMismatch(ref values) => { 166 let expected = match values.expected { 167 ty::IntVarValue::IntType(ty) => ty.name_str(), 168 ty::IntVarValue::UintType(ty) => ty.name_str(), 169 }; 170 let found = match values.found { 171 ty::IntVarValue::IntType(ty) => ty.name_str(), 172 ty::IntVarValue::UintType(ty) => ty.name_str(), 173 }; 174 write!(f, "expected `{}`, found `{}`", expected, found) 175 } 176 FloatMismatch(ref values) => { 177 write!( 178 f, 179 "expected `{}`, found `{}`", 180 values.expected.name_str(), 181 values.found.name_str() 182 ) 183 } 184 VariadicMismatch(ref values) => write!( 185 f, 186 "expected {} fn, found {} function", 187 if values.expected { "variadic" } else { "non-variadic" }, 188 if values.found { "variadic" } else { "non-variadic" } 189 ), 190 ProjectionMismatched(ref values) => ty::tls::with(|tcx| { 191 write!( 192 f, 193 "expected {}, found {}", 194 tcx.def_path_str(values.expected), 195 tcx.def_path_str(values.found) 196 ) 197 }), 198 ExistentialMismatch(ref values) => report_maybe_different( 199 f, 200 &format!("trait `{}`", values.expected), 201 &format!("trait `{}`", values.found), 202 ), 203 ConstMismatch(ref values) => { 204 write!(f, "expected `{}`, found `{}`", values.expected, values.found) 205 } 206 IntrinsicCast => write!(f, "cannot coerce intrinsics to function pointers"), 207 TargetFeatureCast(_) => write!( 208 f, 209 "cannot coerce functions with `#[target_feature]` to safe function pointers" 210 ), 211 ObjectUnsafeCoercion(_) => write!(f, "coercion to object-unsafe trait object"), 212 } 213 } 214 } 215 216 impl<'tcx> TypeError<'tcx> { must_include_note(&self) -> bool217 pub fn must_include_note(&self) -> bool { 218 use self::TypeError::*; 219 match self { 220 CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | ConstnessMismatch(_) 221 | PolarityMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_) 222 | ArgumentSorts(..) | Sorts(_) | IntMismatch(_) | FloatMismatch(_) 223 | VariadicMismatch(_) | TargetFeatureCast(_) => false, 224 225 Mutability 226 | ArgumentMutability(_) 227 | TupleSize(_) 228 | ArgCount 229 | FieldMisMatch(..) 230 | RegionsDoesNotOutlive(..) 231 | RegionsInsufficientlyPolymorphic(..) 232 | RegionsOverlyPolymorphic(..) 233 | RegionsPlaceholderMismatch 234 | Traits(_) 235 | ProjectionMismatched(_) 236 | ExistentialMismatch(_) 237 | ConstMismatch(_) 238 | IntrinsicCast 239 | ObjectUnsafeCoercion(_) => true, 240 } 241 } 242 } 243 244 impl<'tcx> ty::TyS<'tcx> { sort_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str>245 pub fn sort_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> { 246 match *self.kind() { 247 ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => { 248 format!("`{}`", self).into() 249 } 250 ty::Tuple(ref tys) if tys.is_empty() => format!("`{}`", self).into(), 251 252 ty::Adt(def, _) => format!("{} `{}`", def.descr(), tcx.def_path_str(def.did)).into(), 253 ty::Foreign(def_id) => format!("extern type `{}`", tcx.def_path_str(def_id)).into(), 254 ty::Array(t, n) => { 255 if t.is_simple_ty() { 256 return format!("array `{}`", self).into(); 257 } 258 259 let n = tcx.lift(n).unwrap(); 260 if let ty::ConstKind::Value(v) = n.val { 261 if let Some(n) = v.try_to_machine_usize(tcx) { 262 return format!("array of {} element{}", n, pluralize!(n)).into(); 263 } 264 } 265 "array".into() 266 } 267 ty::Slice(ty) if ty.is_simple_ty() => format!("slice `{}`", self).into(), 268 ty::Slice(_) => "slice".into(), 269 ty::RawPtr(_) => "*-ptr".into(), 270 ty::Ref(_, ty, mutbl) => { 271 let tymut = ty::TypeAndMut { ty, mutbl }; 272 let tymut_string = tymut.to_string(); 273 if tymut_string != "_" 274 && (ty.is_simple_text() || tymut_string.len() < "mutable reference".len()) 275 { 276 format!("`&{}`", tymut_string).into() 277 } else { 278 // Unknown type name, it's long or has type arguments 279 match mutbl { 280 hir::Mutability::Mut => "mutable reference", 281 _ => "reference", 282 } 283 .into() 284 } 285 } 286 ty::FnDef(..) => "fn item".into(), 287 ty::FnPtr(_) => "fn pointer".into(), 288 ty::Dynamic(ref inner, ..) if let Some(principal) = inner.principal() => { 289 format!("trait object `dyn {}`", tcx.def_path_str(principal.def_id())).into() 290 } 291 ty::Dynamic(..) => "trait object".into(), 292 ty::Closure(..) => "closure".into(), 293 ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(), 294 ty::GeneratorWitness(..) => "generator witness".into(), 295 ty::Tuple(..) => "tuple".into(), 296 ty::Infer(ty::TyVar(_)) => "inferred type".into(), 297 ty::Infer(ty::IntVar(_)) => "integer".into(), 298 ty::Infer(ty::FloatVar(_)) => "floating-point number".into(), 299 ty::Placeholder(..) => "placeholder type".into(), 300 ty::Bound(..) => "bound type".into(), 301 ty::Infer(ty::FreshTy(_)) => "fresh type".into(), 302 ty::Infer(ty::FreshIntTy(_)) => "fresh integral type".into(), 303 ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(), 304 ty::Projection(_) => "associated type".into(), 305 ty::Param(p) => format!("type parameter `{}`", p).into(), 306 ty::Opaque(..) => "opaque type".into(), 307 ty::Error(_) => "type error".into(), 308 } 309 } 310 prefix_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str>311 pub fn prefix_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> { 312 match *self.kind() { 313 ty::Infer(_) 314 | ty::Error(_) 315 | ty::Bool 316 | ty::Char 317 | ty::Int(_) 318 | ty::Uint(_) 319 | ty::Float(_) 320 | ty::Str 321 | ty::Never => "type".into(), 322 ty::Tuple(ref tys) if tys.is_empty() => "unit type".into(), 323 ty::Adt(def, _) => def.descr().into(), 324 ty::Foreign(_) => "extern type".into(), 325 ty::Array(..) => "array".into(), 326 ty::Slice(_) => "slice".into(), 327 ty::RawPtr(_) => "raw pointer".into(), 328 ty::Ref(.., mutbl) => match mutbl { 329 hir::Mutability::Mut => "mutable reference", 330 _ => "reference", 331 } 332 .into(), 333 ty::FnDef(..) => "fn item".into(), 334 ty::FnPtr(_) => "fn pointer".into(), 335 ty::Dynamic(..) => "trait object".into(), 336 ty::Closure(..) => "closure".into(), 337 ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(), 338 ty::GeneratorWitness(..) => "generator witness".into(), 339 ty::Tuple(..) => "tuple".into(), 340 ty::Placeholder(..) => "higher-ranked type".into(), 341 ty::Bound(..) => "bound type variable".into(), 342 ty::Projection(_) => "associated type".into(), 343 ty::Param(_) => "type parameter".into(), 344 ty::Opaque(..) => "opaque type".into(), 345 } 346 } 347 } 348 349 impl<'tcx> TyCtxt<'tcx> { note_and_explain_type_err( self, db: &mut DiagnosticBuilder<'_>, err: &TypeError<'tcx>, cause: &ObligationCause<'tcx>, sp: Span, body_owner_def_id: DefId, )350 pub fn note_and_explain_type_err( 351 self, 352 db: &mut DiagnosticBuilder<'_>, 353 err: &TypeError<'tcx>, 354 cause: &ObligationCause<'tcx>, 355 sp: Span, 356 body_owner_def_id: DefId, 357 ) { 358 use self::TypeError::*; 359 debug!("note_and_explain_type_err err={:?} cause={:?}", err, cause); 360 match err { 361 ArgumentSorts(values, _) | Sorts(values) => { 362 match (values.expected.kind(), values.found.kind()) { 363 (ty::Closure(..), ty::Closure(..)) => { 364 db.note("no two closures, even if identical, have the same type"); 365 db.help("consider boxing your closure and/or using it as a trait object"); 366 } 367 (ty::Opaque(..), ty::Opaque(..)) => { 368 // Issue #63167 369 db.note("distinct uses of `impl Trait` result in different opaque types"); 370 } 371 (ty::Float(_), ty::Infer(ty::IntVar(_))) 372 if let Ok( 373 // Issue #53280 374 snippet, 375 ) = self.sess.source_map().span_to_snippet(sp) => 376 { 377 if snippet.chars().all(|c| c.is_digit(10) || c == '-' || c == '_') { 378 db.span_suggestion( 379 sp, 380 "use a float literal", 381 format!("{}.0", snippet), 382 MachineApplicable, 383 ); 384 } 385 } 386 (ty::Param(expected), ty::Param(found)) => { 387 let generics = self.generics_of(body_owner_def_id); 388 let e_span = self.def_span(generics.type_param(expected, self).def_id); 389 if !sp.contains(e_span) { 390 db.span_label(e_span, "expected type parameter"); 391 } 392 let f_span = self.def_span(generics.type_param(found, self).def_id); 393 if !sp.contains(f_span) { 394 db.span_label(f_span, "found type parameter"); 395 } 396 db.note( 397 "a type parameter was expected, but a different one was found; \ 398 you might be missing a type parameter or trait bound", 399 ); 400 db.note( 401 "for more information, visit \ 402 https://doc.rust-lang.org/book/ch10-02-traits.html\ 403 #traits-as-parameters", 404 ); 405 } 406 (ty::Projection(_), ty::Projection(_)) => { 407 db.note("an associated type was expected, but a different one was found"); 408 } 409 (ty::Param(p), ty::Projection(proj)) | (ty::Projection(proj), ty::Param(p)) => { 410 let generics = self.generics_of(body_owner_def_id); 411 let p_span = self.def_span(generics.type_param(p, self).def_id); 412 if !sp.contains(p_span) { 413 db.span_label(p_span, "this type parameter"); 414 } 415 let hir = self.hir(); 416 let mut note = true; 417 if let Some(generics) = generics 418 .type_param(p, self) 419 .def_id 420 .as_local() 421 .map(|id| hir.local_def_id_to_hir_id(id)) 422 .and_then(|id| self.hir().find(self.hir().get_parent_node(id))) 423 .as_ref() 424 .and_then(|node| node.generics()) 425 { 426 // Synthesize the associated type restriction `Add<Output = Expected>`. 427 // FIXME: extract this logic for use in other diagnostics. 428 let (trait_ref, assoc_substs) = proj.trait_ref_and_own_substs(self); 429 let path = 430 self.def_path_str_with_substs(trait_ref.def_id, trait_ref.substs); 431 let item_name = self.item_name(proj.item_def_id); 432 let item_args = self.format_generic_args(assoc_substs); 433 434 let path = if path.ends_with('>') { 435 format!( 436 "{}, {}{} = {}>", 437 &path[..path.len() - 1], 438 item_name, 439 item_args, 440 p 441 ) 442 } else { 443 format!("{}<{}{} = {}>", path, item_name, item_args, p) 444 }; 445 note = !suggest_constraining_type_param( 446 self, 447 generics, 448 db, 449 &format!("{}", proj.self_ty()), 450 &path, 451 None, 452 ); 453 } 454 if note { 455 db.note("you might be missing a type parameter or trait bound"); 456 } 457 } 458 (ty::Param(p), ty::Dynamic(..) | ty::Opaque(..)) 459 | (ty::Dynamic(..) | ty::Opaque(..), ty::Param(p)) => { 460 let generics = self.generics_of(body_owner_def_id); 461 let p_span = self.def_span(generics.type_param(p, self).def_id); 462 if !sp.contains(p_span) { 463 db.span_label(p_span, "this type parameter"); 464 } 465 db.help("type parameters must be constrained to match other types"); 466 if self.sess.teach(&db.get_code().unwrap()) { 467 db.help( 468 "given a type parameter `T` and a method `foo`: 469 ``` 470 trait Trait<T> { fn foo(&self) -> T; } 471 ``` 472 the only ways to implement method `foo` are: 473 - constrain `T` with an explicit type: 474 ``` 475 impl Trait<String> for X { 476 fn foo(&self) -> String { String::new() } 477 } 478 ``` 479 - add a trait bound to `T` and call a method on that trait that returns `Self`: 480 ``` 481 impl<T: std::default::Default> Trait<T> for X { 482 fn foo(&self) -> T { <T as std::default::Default>::default() } 483 } 484 ``` 485 - change `foo` to return an argument of type `T`: 486 ``` 487 impl<T> Trait<T> for X { 488 fn foo(&self, x: T) -> T { x } 489 } 490 ```", 491 ); 492 } 493 db.note( 494 "for more information, visit \ 495 https://doc.rust-lang.org/book/ch10-02-traits.html\ 496 #traits-as-parameters", 497 ); 498 } 499 (ty::Param(p), ty::Closure(..) | ty::Generator(..)) => { 500 let generics = self.generics_of(body_owner_def_id); 501 let p_span = self.def_span(generics.type_param(p, self).def_id); 502 if !sp.contains(p_span) { 503 db.span_label(p_span, "this type parameter"); 504 } 505 db.help(&format!( 506 "every closure has a distinct type and so could not always match the \ 507 caller-chosen type of parameter `{}`", 508 p 509 )); 510 } 511 (ty::Param(p), _) | (_, ty::Param(p)) => { 512 let generics = self.generics_of(body_owner_def_id); 513 let p_span = self.def_span(generics.type_param(p, self).def_id); 514 if !sp.contains(p_span) { 515 db.span_label(p_span, "this type parameter"); 516 } 517 } 518 (ty::Projection(proj_ty), _) => { 519 self.expected_projection( 520 db, 521 proj_ty, 522 values, 523 body_owner_def_id, 524 &cause.code, 525 ); 526 } 527 (_, ty::Projection(proj_ty)) => { 528 let msg = format!( 529 "consider constraining the associated type `{}` to `{}`", 530 values.found, values.expected, 531 ); 532 if !(self.suggest_constraining_opaque_associated_type( 533 db, 534 &msg, 535 proj_ty, 536 values.expected, 537 ) || self.suggest_constraint( 538 db, 539 &msg, 540 body_owner_def_id, 541 proj_ty, 542 values.expected, 543 )) { 544 db.help(&msg); 545 db.note( 546 "for more information, visit \ 547 https://doc.rust-lang.org/book/ch19-03-advanced-traits.html", 548 ); 549 } 550 } 551 _ => {} 552 } 553 debug!( 554 "note_and_explain_type_err expected={:?} ({:?}) found={:?} ({:?})", 555 values.expected, 556 values.expected.kind(), 557 values.found, 558 values.found.kind(), 559 ); 560 } 561 CyclicTy(ty) => { 562 // Watch out for various cases of cyclic types and try to explain. 563 if ty.is_closure() || ty.is_generator() { 564 db.note( 565 "closures cannot capture themselves or take themselves as argument;\n\ 566 this error may be the result of a recent compiler bug-fix,\n\ 567 see issue #46062 <https://github.com/rust-lang/rust/issues/46062>\n\ 568 for more information", 569 ); 570 } 571 } 572 TargetFeatureCast(def_id) => { 573 let attrs = self.get_attrs(*def_id); 574 let target_spans = attrs 575 .iter() 576 .filter(|attr| attr.has_name(sym::target_feature)) 577 .map(|attr| attr.span); 578 db.note( 579 "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers" 580 ); 581 db.span_labels(target_spans, "`#[target_feature]` added here"); 582 } 583 _ => {} 584 } 585 } 586 suggest_constraint( self, db: &mut DiagnosticBuilder<'_>, msg: &str, body_owner_def_id: DefId, proj_ty: &ty::ProjectionTy<'tcx>, ty: Ty<'tcx>, ) -> bool587 fn suggest_constraint( 588 self, 589 db: &mut DiagnosticBuilder<'_>, 590 msg: &str, 591 body_owner_def_id: DefId, 592 proj_ty: &ty::ProjectionTy<'tcx>, 593 ty: Ty<'tcx>, 594 ) -> bool { 595 let assoc = self.associated_item(proj_ty.item_def_id); 596 let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self); 597 if let Some(item) = self.hir().get_if_local(body_owner_def_id) { 598 if let Some(hir_generics) = item.generics() { 599 // Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`. 600 // This will also work for `impl Trait`. 601 let def_id = if let ty::Param(param_ty) = proj_ty.self_ty().kind() { 602 let generics = self.generics_of(body_owner_def_id); 603 generics.type_param(param_ty, self).def_id 604 } else { 605 return false; 606 }; 607 608 // First look in the `where` clause, as this might be 609 // `fn foo<T>(x: T) where T: Trait`. 610 for predicate in hir_generics.where_clause.predicates { 611 if let hir::WherePredicate::BoundPredicate(pred) = predicate { 612 if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = 613 pred.bounded_ty.kind 614 { 615 if path.res.opt_def_id() == Some(def_id) { 616 // This predicate is binding type param `A` in `<A as T>::Foo` to 617 // something, potentially `T`. 618 } else { 619 continue; 620 } 621 } else { 622 continue; 623 } 624 625 if self.constrain_generic_bound_associated_type_structured_suggestion( 626 db, 627 &trait_ref, 628 pred.bounds, 629 &assoc, 630 assoc_substs, 631 ty, 632 msg, 633 false, 634 ) { 635 return true; 636 } 637 } 638 } 639 for param in hir_generics.params { 640 if self.hir().opt_local_def_id(param.hir_id).map(|id| id.to_def_id()) 641 == Some(def_id) 642 { 643 // This is type param `A` in `<A as T>::Foo`. 644 return self.constrain_generic_bound_associated_type_structured_suggestion( 645 db, 646 &trait_ref, 647 param.bounds, 648 &assoc, 649 assoc_substs, 650 ty, 651 msg, 652 false, 653 ); 654 } 655 } 656 } 657 } 658 false 659 } 660 661 /// An associated type was expected and a different type was found. 662 /// 663 /// We perform a few different checks to see what we can suggest: 664 /// 665 /// - In the current item, look for associated functions that return the expected type and 666 /// suggest calling them. (Not a structured suggestion.) 667 /// - If any of the item's generic bounds can be constrained, we suggest constraining the 668 /// associated type to the found type. 669 /// - If the associated type has a default type and was expected inside of a `trait`, we 670 /// mention that this is disallowed. 671 /// - If all other things fail, and the error is not because of a mismatch between the `trait` 672 /// and the `impl`, we provide a generic `help` to constrain the assoc type or call an assoc 673 /// fn that returns the type. expected_projection( self, db: &mut DiagnosticBuilder<'_>, proj_ty: &ty::ProjectionTy<'tcx>, values: &ExpectedFound<Ty<'tcx>>, body_owner_def_id: DefId, cause_code: &ObligationCauseCode<'_>, )674 fn expected_projection( 675 self, 676 db: &mut DiagnosticBuilder<'_>, 677 proj_ty: &ty::ProjectionTy<'tcx>, 678 values: &ExpectedFound<Ty<'tcx>>, 679 body_owner_def_id: DefId, 680 cause_code: &ObligationCauseCode<'_>, 681 ) { 682 let msg = format!( 683 "consider constraining the associated type `{}` to `{}`", 684 values.expected, values.found 685 ); 686 let body_owner = self.hir().get_if_local(body_owner_def_id); 687 let current_method_ident = body_owner.and_then(|n| n.ident()).map(|i| i.name); 688 689 // We don't want to suggest calling an assoc fn in a scope where that isn't feasible. 690 let callable_scope = matches!( 691 body_owner, 692 Some( 693 hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. }) 694 | hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. }) 695 | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }), 696 ) 697 ); 698 let impl_comparison = matches!( 699 cause_code, 700 ObligationCauseCode::CompareImplMethodObligation { .. } 701 | ObligationCauseCode::CompareImplTypeObligation { .. } 702 | ObligationCauseCode::CompareImplConstObligation 703 ); 704 let assoc = self.associated_item(proj_ty.item_def_id); 705 if !callable_scope || impl_comparison { 706 // We do not want to suggest calling functions when the reason of the 707 // type error is a comparison of an `impl` with its `trait` or when the 708 // scope is outside of a `Body`. 709 } else { 710 // If we find a suitable associated function that returns the expected type, we don't 711 // want the more general suggestion later in this method about "consider constraining 712 // the associated type or calling a method that returns the associated type". 713 let point_at_assoc_fn = self.point_at_methods_that_satisfy_associated_type( 714 db, 715 assoc.container.id(), 716 current_method_ident, 717 proj_ty.item_def_id, 718 values.expected, 719 ); 720 // Possibly suggest constraining the associated type to conform to the 721 // found type. 722 if self.suggest_constraint(db, &msg, body_owner_def_id, proj_ty, values.found) 723 || point_at_assoc_fn 724 { 725 return; 726 } 727 } 728 729 self.suggest_constraining_opaque_associated_type(db, &msg, proj_ty, values.found); 730 731 if self.point_at_associated_type(db, body_owner_def_id, values.found) { 732 return; 733 } 734 735 if !impl_comparison { 736 // Generic suggestion when we can't be more specific. 737 if callable_scope { 738 db.help(&format!("{} or calling a method that returns `{}`", msg, values.expected)); 739 } else { 740 db.help(&msg); 741 } 742 db.note( 743 "for more information, visit \ 744 https://doc.rust-lang.org/book/ch19-03-advanced-traits.html", 745 ); 746 } 747 if self.sess.teach(&db.get_code().unwrap()) { 748 db.help( 749 "given an associated type `T` and a method `foo`: 750 ``` 751 trait Trait { 752 type T; 753 fn foo(&self) -> Self::T; 754 } 755 ``` 756 the only way of implementing method `foo` is to constrain `T` with an explicit associated type: 757 ``` 758 impl Trait for X { 759 type T = String; 760 fn foo(&self) -> Self::T { String::new() } 761 } 762 ```", 763 ); 764 } 765 } 766 767 /// When the expected `impl Trait` is not defined in the current item, it will come from 768 /// a return type. This can occur when dealing with `TryStream` (#71035). suggest_constraining_opaque_associated_type( self, db: &mut DiagnosticBuilder<'_>, msg: &str, proj_ty: &ty::ProjectionTy<'tcx>, ty: Ty<'tcx>, ) -> bool769 fn suggest_constraining_opaque_associated_type( 770 self, 771 db: &mut DiagnosticBuilder<'_>, 772 msg: &str, 773 proj_ty: &ty::ProjectionTy<'tcx>, 774 ty: Ty<'tcx>, 775 ) -> bool { 776 let assoc = self.associated_item(proj_ty.item_def_id); 777 if let ty::Opaque(def_id, _) = *proj_ty.self_ty().kind() { 778 let opaque_local_def_id = def_id.as_local(); 779 let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id { 780 let hir = self.hir(); 781 let opaque_hir_id = hir.local_def_id_to_hir_id(opaque_local_def_id); 782 match &hir.expect_item(opaque_hir_id).kind { 783 hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty, 784 _ => bug!("The HirId comes from a `ty::Opaque`"), 785 } 786 } else { 787 return false; 788 }; 789 790 let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self); 791 792 self.constrain_generic_bound_associated_type_structured_suggestion( 793 db, 794 &trait_ref, 795 opaque_hir_ty.bounds, 796 assoc, 797 assoc_substs, 798 ty, 799 msg, 800 true, 801 ) 802 } else { 803 false 804 } 805 } 806 point_at_methods_that_satisfy_associated_type( self, db: &mut DiagnosticBuilder<'_>, assoc_container_id: DefId, current_method_ident: Option<Symbol>, proj_ty_item_def_id: DefId, expected: Ty<'tcx>, ) -> bool807 fn point_at_methods_that_satisfy_associated_type( 808 self, 809 db: &mut DiagnosticBuilder<'_>, 810 assoc_container_id: DefId, 811 current_method_ident: Option<Symbol>, 812 proj_ty_item_def_id: DefId, 813 expected: Ty<'tcx>, 814 ) -> bool { 815 let items = self.associated_items(assoc_container_id); 816 // Find all the methods in the trait that could be called to construct the 817 // expected associated type. 818 // FIXME: consider suggesting the use of associated `const`s. 819 let methods: Vec<(Span, String)> = items 820 .items 821 .iter() 822 .filter(|(name, item)| { 823 ty::AssocKind::Fn == item.kind && Some(**name) != current_method_ident 824 }) 825 .filter_map(|(_, item)| { 826 let method = self.fn_sig(item.def_id); 827 match *method.output().skip_binder().kind() { 828 ty::Projection(ty::ProjectionTy { item_def_id, .. }) 829 if item_def_id == proj_ty_item_def_id => 830 { 831 Some(( 832 self.sess.source_map().guess_head_span(self.def_span(item.def_id)), 833 format!("consider calling `{}`", self.def_path_str(item.def_id)), 834 )) 835 } 836 _ => None, 837 } 838 }) 839 .collect(); 840 if !methods.is_empty() { 841 // Use a single `help:` to show all the methods in the trait that can 842 // be used to construct the expected associated type. 843 let mut span: MultiSpan = 844 methods.iter().map(|(sp, _)| *sp).collect::<Vec<Span>>().into(); 845 let msg = format!( 846 "{some} method{s} {are} available that return{r} `{ty}`", 847 some = if methods.len() == 1 { "a" } else { "some" }, 848 s = pluralize!(methods.len()), 849 are = if methods.len() == 1 { "is" } else { "are" }, 850 r = if methods.len() == 1 { "s" } else { "" }, 851 ty = expected 852 ); 853 for (sp, label) in methods.into_iter() { 854 span.push_span_label(sp, label); 855 } 856 db.span_help(span, &msg); 857 return true; 858 } 859 false 860 } 861 point_at_associated_type( self, db: &mut DiagnosticBuilder<'_>, body_owner_def_id: DefId, found: Ty<'tcx>, ) -> bool862 fn point_at_associated_type( 863 self, 864 db: &mut DiagnosticBuilder<'_>, 865 body_owner_def_id: DefId, 866 found: Ty<'tcx>, 867 ) -> bool { 868 let hir_id = 869 match body_owner_def_id.as_local().map(|id| self.hir().local_def_id_to_hir_id(id)) { 870 Some(hir_id) => hir_id, 871 None => return false, 872 }; 873 // When `body_owner` is an `impl` or `trait` item, look in its associated types for 874 // `expected` and point at it. 875 let parent_id = self.hir().get_parent_item(hir_id); 876 let item = self.hir().find(parent_id); 877 debug!("expected_projection parent item {:?}", item); 878 match item { 879 Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., items), .. })) => { 880 // FIXME: account for `#![feature(specialization)]` 881 for item in &items[..] { 882 match item.kind { 883 hir::AssocItemKind::Type => { 884 // FIXME: account for returning some type in a trait fn impl that has 885 // an assoc type as a return type (#72076). 886 if let hir::Defaultness::Default { has_value: true } = item.defaultness 887 { 888 if self.type_of(item.id.def_id) == found { 889 db.span_label( 890 item.span, 891 "associated type defaults can't be assumed inside the \ 892 trait defining them", 893 ); 894 return true; 895 } 896 } 897 } 898 _ => {} 899 } 900 } 901 } 902 Some(hir::Node::Item(hir::Item { 903 kind: hir::ItemKind::Impl(hir::Impl { items, .. }), 904 .. 905 })) => { 906 for item in &items[..] { 907 if let hir::AssocItemKind::Type = item.kind { 908 if self.type_of(item.id.def_id) == found { 909 db.span_label(item.span, "expected this associated type"); 910 return true; 911 } 912 } 913 } 914 } 915 _ => {} 916 } 917 false 918 } 919 920 /// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref` 921 /// requirement, provide a structured suggestion to constrain it to a given type `ty`. 922 /// 923 /// `is_bound_surely_present` indicates whether we know the bound we're looking for is 924 /// inside `bounds`. If that's the case then we can consider `bounds` containing only one 925 /// trait bound as the one we're looking for. This can help in cases where the associated 926 /// type is defined on a supertrait of the one present in the bounds. constrain_generic_bound_associated_type_structured_suggestion( self, db: &mut DiagnosticBuilder<'_>, trait_ref: &ty::TraitRef<'tcx>, bounds: hir::GenericBounds<'_>, assoc: &ty::AssocItem, assoc_substs: &[ty::GenericArg<'tcx>], ty: Ty<'tcx>, msg: &str, is_bound_surely_present: bool, ) -> bool927 fn constrain_generic_bound_associated_type_structured_suggestion( 928 self, 929 db: &mut DiagnosticBuilder<'_>, 930 trait_ref: &ty::TraitRef<'tcx>, 931 bounds: hir::GenericBounds<'_>, 932 assoc: &ty::AssocItem, 933 assoc_substs: &[ty::GenericArg<'tcx>], 934 ty: Ty<'tcx>, 935 msg: &str, 936 is_bound_surely_present: bool, 937 ) -> bool { 938 // FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting. 939 940 let trait_bounds = bounds.iter().filter_map(|bound| match bound { 941 hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::None) => Some(ptr), 942 _ => None, 943 }); 944 945 let matching_trait_bounds = trait_bounds 946 .clone() 947 .filter(|ptr| ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id)) 948 .collect::<Vec<_>>(); 949 950 let span = match &matching_trait_bounds[..] { 951 &[ptr] => ptr.span, 952 &[] if is_bound_surely_present => match &trait_bounds.collect::<Vec<_>>()[..] { 953 &[ptr] => ptr.span, 954 _ => return false, 955 }, 956 _ => return false, 957 }; 958 959 self.constrain_associated_type_structured_suggestion(db, span, assoc, assoc_substs, ty, msg) 960 } 961 962 /// Given a span corresponding to a bound, provide a structured suggestion to set an 963 /// associated type to a given type `ty`. constrain_associated_type_structured_suggestion( self, db: &mut DiagnosticBuilder<'_>, span: Span, assoc: &ty::AssocItem, assoc_substs: &[ty::GenericArg<'tcx>], ty: Ty<'tcx>, msg: &str, ) -> bool964 fn constrain_associated_type_structured_suggestion( 965 self, 966 db: &mut DiagnosticBuilder<'_>, 967 span: Span, 968 assoc: &ty::AssocItem, 969 assoc_substs: &[ty::GenericArg<'tcx>], 970 ty: Ty<'tcx>, 971 msg: &str, 972 ) -> bool { 973 if let Ok(has_params) = 974 self.sess.source_map().span_to_snippet(span).map(|snippet| snippet.ends_with('>')) 975 { 976 let (span, sugg) = if has_params { 977 let pos = span.hi() - BytePos(1); 978 let span = Span::new(pos, pos, span.ctxt(), span.parent()); 979 (span, format!(", {} = {}", assoc.ident, ty)) 980 } else { 981 let item_args = self.format_generic_args(assoc_substs); 982 (span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident, item_args, ty)) 983 }; 984 db.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect); 985 return true; 986 } 987 false 988 } 989 format_generic_args(self, args: &[ty::GenericArg<'tcx>]) -> String990 fn format_generic_args(self, args: &[ty::GenericArg<'tcx>]) -> String { 991 let mut item_args = String::new(); 992 FmtPrinter::new(self, &mut item_args, hir::def::Namespace::TypeNS) 993 .path_generic_args(Ok, args) 994 .expect("could not write to `String`."); 995 item_args 996 } 997 } 998