|
10 | 10 |
|
11 | 11 |
|
12 | 12 | use check::FnCtxt;
|
13 |
| -use rustc::ty::Ty; |
14 |
| -use rustc::infer::{InferOk}; |
| 13 | +use rustc::infer::InferOk; |
15 | 14 | use rustc::traits::ObligationCause;
|
16 | 15 |
|
17 | 16 | use syntax::ast;
|
18 | 17 | use syntax_pos::{self, Span};
|
19 | 18 | use rustc::hir;
|
20 | 19 | use rustc::hir::def::Def;
|
21 |
| -use rustc::ty::{self, AssociatedItem}; |
| 20 | +use rustc::ty::{self, Ty, AssociatedItem}; |
22 | 21 | use errors::DiagnosticBuilder;
|
23 | 22 |
|
24 | 23 | use super::method::probe;
|
@@ -80,18 +79,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
80 | 79 | if let Err(e) = self.try_coerce(expr, checked_ty, self.diverges.get(), expected) {
|
81 | 80 | let cause = self.misc(expr.span);
|
82 | 81 | let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
|
83 |
| - let mode = probe::Mode::MethodCall; |
84 |
| - let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP, |
85 |
| - mode, |
86 |
| - expected, |
87 |
| - checked_ty, |
88 |
| - ast::DUMMY_NODE_ID); |
89 | 82 | let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);
|
90 |
| - if suggestions.len() > 0 { |
91 |
| - err.help(&format!("here are some functions which \ |
92 |
| - might fulfill your needs:\n{}", |
93 |
| - self.get_best_match(&suggestions).join("\n"))); |
94 |
| - }; |
| 83 | + if let Some(suggestion) = self.check_ref(expr, |
| 84 | + checked_ty, |
| 85 | + expected) { |
| 86 | + err.help(&suggestion); |
| 87 | + } else { |
| 88 | + let mode = probe::Mode::MethodCall; |
| 89 | + let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP, |
| 90 | + mode, |
| 91 | + expected, |
| 92 | + checked_ty, |
| 93 | + ast::DUMMY_NODE_ID); |
| 94 | + if suggestions.len() > 0 { |
| 95 | + err.help(&format!("here are some functions which \ |
| 96 | + might fulfill your needs:\n{}", |
| 97 | + self.get_best_match(&suggestions).join("\n"))); |
| 98 | + } |
| 99 | + } |
95 | 100 | err.emit();
|
96 | 101 | }
|
97 | 102 | }
|
@@ -140,4 +145,60 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
140 | 145 | _ => false,
|
141 | 146 | }
|
142 | 147 | }
|
| 148 | + |
| 149 | + /// This function is used to determine potential "simple" improvements or users' errors and |
| 150 | + /// provide them useful help. For example: |
| 151 | + /// |
| 152 | + /// ``` |
| 153 | + /// fn some_fn(s: &str) {} |
| 154 | + /// |
| 155 | + /// let x = "hey!".to_owned(); |
| 156 | + /// some_fn(x); // error |
| 157 | + /// ``` |
| 158 | + /// |
| 159 | + /// No need to find every potential function which could make a coercion to transform a |
| 160 | + /// `String` into a `&str` since a `&` would do the trick! |
| 161 | + /// |
| 162 | + /// In addition of this check, it also checks between references mutability state. If the |
| 163 | + /// expected is mutable but the provided isn't, maybe we could just say "Hey, try with |
| 164 | + /// `&mut`!". |
| 165 | + fn check_ref(&self, |
| 166 | + expr: &hir::Expr, |
| 167 | + checked_ty: Ty<'tcx>, |
| 168 | + expected: Ty<'tcx>) |
| 169 | + -> Option<String> { |
| 170 | + match (&expected.sty, &checked_ty.sty) { |
| 171 | + (&ty::TyRef(_, _), &ty::TyRef(_, _)) => None, |
| 172 | + (&ty::TyRef(_, mutability), _) => { |
| 173 | + // Check if it can work when put into a ref. For example: |
| 174 | + // |
| 175 | + // ``` |
| 176 | + // fn bar(x: &mut i32) {} |
| 177 | + // |
| 178 | + // let x = 0u32; |
| 179 | + // bar(&x); // error, expected &mut |
| 180 | + // ``` |
| 181 | + let ref_ty = match mutability.mutbl { |
| 182 | + hir::Mutability::MutMutable => self.tcx.mk_mut_ref( |
| 183 | + self.tcx.mk_region(ty::ReStatic), |
| 184 | + checked_ty), |
| 185 | + hir::Mutability::MutImmutable => self.tcx.mk_imm_ref( |
| 186 | + self.tcx.mk_region(ty::ReStatic), |
| 187 | + checked_ty), |
| 188 | + }; |
| 189 | + if self.can_coerce(ref_ty, expected) { |
| 190 | + if let Ok(src) = self.tcx.sess.codemap().span_to_snippet(expr.span) { |
| 191 | + return Some(format!("try with `{}{}`", |
| 192 | + match mutability.mutbl { |
| 193 | + hir::Mutability::MutMutable => "&mut ", |
| 194 | + hir::Mutability::MutImmutable => "&", |
| 195 | + }, |
| 196 | + &src)); |
| 197 | + } |
| 198 | + } |
| 199 | + None |
| 200 | + } |
| 201 | + _ => None, |
| 202 | + } |
| 203 | + } |
143 | 204 | }
|
0 commit comments