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