|
1 | 1 | use crate::check::FnCtxt;
|
2 | 2 | use rustc::infer::InferOk;
|
3 |
| -use rustc::traits::{ObligationCause, ObligationCauseCode}; |
| 3 | +use rustc::traits::{self, ObligationCause, ObligationCauseCode}; |
4 | 4 |
|
5 | 5 | use syntax::util::parser::PREC_POSTFIX;
|
6 | 6 | use syntax_pos::Span;
|
@@ -463,7 +463,37 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
463 | 463 | }
|
464 | 464 | }
|
465 | 465 | }
|
466 |
| - _ => {} |
| 466 | + _ => { |
| 467 | + // If neither type is a reference, then check for `Deref` implementations by |
| 468 | + // constructing a predicate to prove: `<T as Deref>::Output == U` |
| 469 | + let deref_trait = self.tcx.lang_items().deref_trait().unwrap(); |
| 470 | + let item_def_id = self.tcx.associated_items(deref_trait).next().unwrap().def_id; |
| 471 | + let predicate = ty::Predicate::Projection(ty::Binder::bind(ty::ProjectionPredicate { |
| 472 | + // `<T as Deref>::Output` |
| 473 | + projection_ty: ty::ProjectionTy { |
| 474 | + // `T` |
| 475 | + substs: self.tcx.mk_substs_trait( |
| 476 | + checked_ty, |
| 477 | + self.fresh_substs_for_item(sp, item_def_id), |
| 478 | + ), |
| 479 | + // `Deref::Output` |
| 480 | + item_def_id, |
| 481 | + }, |
| 482 | + // `U` |
| 483 | + ty: expected, |
| 484 | + })); |
| 485 | + let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate); |
| 486 | + if self.infcx.predicate_may_hold(&obligation) { |
| 487 | + if let (Ok(code), true) = (cm.span_to_snippet(sp), sp == expr.span) { |
| 488 | + let msg = if is_struct_pat_shorthand_field { |
| 489 | + format!("{}: *{}", code, code) |
| 490 | + } else { |
| 491 | + format!("*{}", code) |
| 492 | + }; |
| 493 | + return Some((sp, "consider dereferencing the type", msg)); |
| 494 | + } |
| 495 | + } |
| 496 | + } |
467 | 497 | }
|
468 | 498 | None
|
469 | 499 | }
|
|
0 commit comments