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