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