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