]>
Commit | Line | Data |
---|---|---|
d9579d0f | 1 | //! Give useful errors and suggestions to users when an item can't be |
85aaf69f SL |
2 | //! found or is otherwise invalid. |
3 | ||
9fa01778 | 4 | use crate::check::FnCtxt; |
74b04a01 | 5 | use rustc_data_structures::fx::{FxHashMap, FxHashSet}; |
dfeec247 XL |
6 | use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; |
7 | use rustc_hir as hir; | |
74b04a01 | 8 | use rustc_hir::def::{DefKind, Namespace, Res}; |
c295e0f8 | 9 | use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX}; |
3dfed10e | 10 | use rustc_hir::lang_items::LangItem; |
dfeec247 | 11 | use rustc_hir::{ExprKind, Node, QPath}; |
74b04a01 | 12 | use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; |
fc512014 | 13 | use rustc_middle::ty::fast_reject::simplify_type; |
ba9703b0 | 14 | use rustc_middle::ty::print::with_crate_prefix; |
c295e0f8 | 15 | use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; |
fc512014 | 16 | use rustc_span::lev_distance; |
3dfed10e | 17 | use rustc_span::symbol::{kw, sym, Ident}; |
3c0e092e | 18 | use rustc_span::{source_map, FileName, MultiSpan, Span, Symbol}; |
ba9703b0 | 19 | use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; |
3c0e092e XL |
20 | use rustc_trait_selection::traits::{ |
21 | FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, | |
22 | }; | |
85aaf69f | 23 | |
85aaf69f | 24 | use std::cmp::Ordering; |
6a06907d | 25 | use std::iter; |
85aaf69f | 26 | |
d9579d0f | 27 | use super::probe::Mode; |
dfeec247 | 28 | use super::{CandidateSource, MethodError, NoMatchData}; |
85aaf69f | 29 | |
dc9dc135 | 30 | impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
48663c56 | 31 | fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool { |
a7813a04 | 32 | let tcx = self.tcx; |
1b1a35ee | 33 | match ty.kind() { |
0731742a XL |
34 | // Not all of these (e.g., unsafe fns) implement `FnOnce`, |
35 | // so we look for these beforehand. | |
dfeec247 | 36 | ty::Closure(..) | ty::FnDef(..) | ty::FnPtr(_) => true, |
0731742a | 37 | // If it's not a simple function, look for things which implement `FnOnce`. |
a7813a04 | 38 | _ => { |
3dfed10e | 39 | let fn_once = match tcx.lang_items().require(LangItem::FnOnce) { |
3157f602 | 40 | Ok(fn_once) => fn_once, |
c30ab7b3 | 41 | Err(..) => return false, |
3157f602 | 42 | }; |
a7813a04 | 43 | |
c30ab7b3 SL |
44 | self.autoderef(span, ty).any(|(ty, _)| { |
45 | self.probe(|_| { | |
dfeec247 XL |
46 | let fn_once_substs = tcx.mk_substs_trait( |
47 | ty, | |
48 | &[self | |
49 | .next_ty_var(TypeVariableOrigin { | |
50 | kind: TypeVariableOriginKind::MiscVariable, | |
51 | span, | |
52 | }) | |
53 | .into()], | |
54 | ); | |
c30ab7b3 | 55 | let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs); |
c295e0f8 | 56 | let poly_trait_ref = ty::Binder::dummy(trait_ref); |
dfeec247 XL |
57 | let obligation = Obligation::misc( |
58 | span, | |
59 | self.body_id, | |
60 | self.param_env, | |
f9f354fc | 61 | poly_trait_ref.without_const().to_predicate(tcx), |
dfeec247 | 62 | ); |
83c7162d | 63 | self.predicate_may_hold(&obligation) |
c30ab7b3 SL |
64 | }) |
65 | }) | |
54a0048b SL |
66 | } |
67 | } | |
68 | } | |
3157f602 | 69 | |
cdc7bbd5 | 70 | pub fn report_method_error( |
532ac7d7 | 71 | &self, |
94222f64 | 72 | mut span: Span, |
532ac7d7 | 73 | rcvr_ty: Ty<'tcx>, |
f9f354fc | 74 | item_name: Ident, |
cdc7bbd5 | 75 | source: SelfSource<'tcx>, |
532ac7d7 | 76 | error: MethodError<'tcx>, |
dfeec247 | 77 | args: Option<&'tcx [hir::Expr<'tcx>]>, |
e1599b0c | 78 | ) -> Option<DiagnosticBuilder<'_>> { |
0731742a | 79 | // Avoid suggestions when we don't know what's going on. |
a7813a04 | 80 | if rcvr_ty.references_error() { |
e1599b0c | 81 | return None; |
a7813a04 | 82 | } |
85aaf69f | 83 | |
dfeec247 XL |
84 | let report_candidates = |span: Span, |
85 | err: &mut DiagnosticBuilder<'_>, | |
86 | mut sources: Vec<CandidateSource>, | |
87 | sugg_span: Span| { | |
a7813a04 XL |
88 | sources.sort(); |
89 | sources.dedup(); | |
90 | // Dynamic limit to avoid hiding just one candidate, which is silly. | |
91 | let limit = if sources.len() == 5 { 5 } else { 4 }; | |
92 | ||
93 | for (idx, source) in sources.iter().take(limit).enumerate() { | |
94 | match *source { | |
95 | CandidateSource::ImplSource(impl_did) => { | |
96 | // Provide the best span we can. Use the item, if local to crate, else | |
97 | // the impl, if local to crate (item may be defaulted), else nothing. | |
dfeec247 | 98 | let item = match self |
74b04a01 | 99 | .associated_item(impl_did, item_name, Namespace::ValueNS) |
dfeec247 XL |
100 | .or_else(|| { |
101 | let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?; | |
102 | self.associated_item( | |
103 | impl_trait_ref.def_id, | |
104 | item_name, | |
74b04a01 | 105 | Namespace::ValueNS, |
dfeec247 XL |
106 | ) |
107 | }) { | |
48663c56 XL |
108 | Some(item) => item, |
109 | None => continue, | |
110 | }; | |
dfeec247 XL |
111 | let note_span = self |
112 | .tcx | |
113 | .hir() | |
114 | .span_if_local(item.def_id) | |
115 | .or_else(|| self.tcx.hir().span_if_local(impl_did)); | |
a7813a04 | 116 | |
ba9703b0 | 117 | let impl_ty = self.tcx.at(span).type_of(impl_did); |
a7813a04 XL |
118 | |
119 | let insertion = match self.tcx.impl_trait_ref(impl_did) { | |
8faf50e0 | 120 | None => String::new(), |
dfeec247 XL |
121 | Some(trait_ref) => format!( |
122 | " of the trait `{}`", | |
123 | self.tcx.def_path_str(trait_ref.def_id) | |
124 | ), | |
a7813a04 XL |
125 | }; |
126 | ||
dfeec247 XL |
127 | let (note_str, idx) = if sources.len() > 1 { |
128 | ( | |
129 | format!( | |
130 | "candidate #{} is defined in an impl{} for the type `{}`", | |
94b46f34 XL |
131 | idx + 1, |
132 | insertion, | |
dfeec247 XL |
133 | impl_ty, |
134 | ), | |
135 | Some(idx + 1), | |
136 | ) | |
94b46f34 | 137 | } else { |
dfeec247 XL |
138 | ( |
139 | format!( | |
140 | "the candidate is defined in an impl{} for the type `{}`", | |
141 | insertion, impl_ty, | |
142 | ), | |
143 | None, | |
144 | ) | |
94b46f34 | 145 | }; |
a7813a04 XL |
146 | if let Some(note_span) = note_span { |
147 | // We have a span pointing to the method. Show note with snippet. | |
dfeec247 | 148 | err.span_note( |
ba9703b0 | 149 | self.tcx.sess.source_map().guess_head_span(note_span), |
dfeec247 XL |
150 | ¬e_str, |
151 | ); | |
a7813a04 XL |
152 | } else { |
153 | err.note(¬e_str); | |
154 | } | |
416331ca | 155 | if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) { |
dfeec247 XL |
156 | let path = self.tcx.def_path_str(trait_ref.def_id); |
157 | ||
158 | let ty = match item.kind { | |
f035d41b | 159 | ty::AssocKind::Const | ty::AssocKind::Type => rcvr_ty, |
ba9703b0 | 160 | ty::AssocKind::Fn => self |
dfeec247 XL |
161 | .tcx |
162 | .fn_sig(item.def_id) | |
163 | .inputs() | |
164 | .skip_binder() | |
165 | .get(0) | |
166 | .filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr()) | |
74b04a01 | 167 | .copied() |
dfeec247 XL |
168 | .unwrap_or(rcvr_ty), |
169 | }; | |
170 | print_disambiguation_help( | |
171 | item_name, | |
172 | args, | |
173 | err, | |
174 | path, | |
175 | ty, | |
176 | item.kind, | |
ba9703b0 | 177 | item.def_id, |
dfeec247 XL |
178 | sugg_span, |
179 | idx, | |
180 | self.tcx.sess.source_map(), | |
c295e0f8 | 181 | item.fn_has_self_parameter, |
dfeec247 | 182 | ); |
416331ca | 183 | } |
a7813a04 XL |
184 | } |
185 | CandidateSource::TraitSource(trait_did) => { | |
dfeec247 | 186 | let item = |
74b04a01 | 187 | match self.associated_item(trait_did, item_name, Namespace::ValueNS) { |
dfeec247 XL |
188 | Some(item) => item, |
189 | None => continue, | |
190 | }; | |
ba9703b0 XL |
191 | let item_span = self |
192 | .tcx | |
193 | .sess | |
194 | .source_map() | |
195 | .guess_head_span(self.tcx.def_span(item.def_id)); | |
dfeec247 XL |
196 | let idx = if sources.len() > 1 { |
197 | let msg = &format!( | |
198 | "candidate #{} is defined in the trait `{}`", | |
199 | idx + 1, | |
200 | self.tcx.def_path_str(trait_did) | |
201 | ); | |
202 | err.span_note(item_span, msg); | |
203 | Some(idx + 1) | |
94b46f34 | 204 | } else { |
dfeec247 XL |
205 | let msg = &format!( |
206 | "the candidate is defined in the trait `{}`", | |
207 | self.tcx.def_path_str(trait_did) | |
208 | ); | |
209 | err.span_note(item_span, msg); | |
210 | None | |
211 | }; | |
212 | let path = self.tcx.def_path_str(trait_did); | |
213 | print_disambiguation_help( | |
214 | item_name, | |
215 | args, | |
216 | err, | |
217 | path, | |
218 | rcvr_ty, | |
219 | item.kind, | |
ba9703b0 | 220 | item.def_id, |
dfeec247 XL |
221 | sugg_span, |
222 | idx, | |
223 | self.tcx.sess.source_map(), | |
c295e0f8 | 224 | item.fn_has_self_parameter, |
dfeec247 | 225 | ); |
9cc50fc6 | 226 | } |
54a0048b SL |
227 | } |
228 | } | |
a7813a04 XL |
229 | if sources.len() > limit { |
230 | err.note(&format!("and {} others", sources.len() - limit)); | |
231 | } | |
232 | }; | |
62682a34 | 233 | |
dfeec247 XL |
234 | let sugg_span = if let SelfSource::MethodCall(expr) = source { |
235 | // Given `foo.bar(baz)`, `expr` is `bar`, but we want to point to the whole thing. | |
236 | self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id)).span | |
237 | } else { | |
238 | span | |
239 | }; | |
240 | ||
a7813a04 | 241 | match error { |
ff7c6d11 XL |
242 | MethodError::NoMatch(NoMatchData { |
243 | static_candidates: static_sources, | |
244 | unsatisfied_predicates, | |
245 | out_of_scope_traits, | |
246 | lev_candidate, | |
247 | mode, | |
ff7c6d11 | 248 | }) => { |
a7813a04 XL |
249 | let tcx = self.tcx; |
250 | ||
fc512014 | 251 | let actual = self.resolve_vars_if_possible(rcvr_ty); |
0731742a | 252 | let ty_str = self.ty_to_string(actual); |
ff7c6d11 | 253 | let is_method = mode == Mode::MethodCall; |
94b46f34 | 254 | let item_kind = if is_method { |
ff7c6d11 XL |
255 | "method" |
256 | } else if actual.is_enum() { | |
48663c56 | 257 | "variant or associated item" |
ff7c6d11 XL |
258 | } else { |
259 | match (item_name.as_str().chars().next(), actual.is_fresh_ty()) { | |
dfeec247 | 260 | (Some(name), false) if name.is_lowercase() => "function or associated item", |
ff7c6d11 | 261 | (Some(_), false) => "associated item", |
dfeec247 | 262 | (Some(_), true) | (None, false) => "variant or associated item", |
ff7c6d11 XL |
263 | (None, true) => "variant", |
264 | } | |
265 | }; | |
7cac9316 | 266 | let mut err = if !actual.references_error() { |
2c00a5a8 | 267 | // Suggest clamping down the type if the method that is being attempted to |
e74abb32 | 268 | // be used exists at all, and the type is an ambiguous numeric type |
2c00a5a8 | 269 | // ({integer}/{float}). |
dfeec247 | 270 | let mut candidates = all_traits(self.tcx).into_iter().filter_map(|info| { |
74b04a01 | 271 | self.associated_item(info.def_id, item_name, Namespace::ValueNS) |
dfeec247 | 272 | }); |
ba9703b0 XL |
273 | // There are methods that are defined on the primitive types and won't be |
274 | // found when exploring `all_traits`, but we also need them to be acurate on | |
275 | // our suggestions (#47759). | |
276 | let fund_assoc = |opt_def_id: Option<DefId>| { | |
277 | opt_def_id | |
278 | .and_then(|id| self.associated_item(id, item_name, Namespace::ValueNS)) | |
279 | .is_some() | |
280 | }; | |
281 | let lang_items = tcx.lang_items(); | |
282 | let found_candidate = candidates.next().is_some() | |
283 | || fund_assoc(lang_items.i8_impl()) | |
284 | || fund_assoc(lang_items.i16_impl()) | |
285 | || fund_assoc(lang_items.i32_impl()) | |
286 | || fund_assoc(lang_items.i64_impl()) | |
287 | || fund_assoc(lang_items.i128_impl()) | |
288 | || fund_assoc(lang_items.u8_impl()) | |
289 | || fund_assoc(lang_items.u16_impl()) | |
290 | || fund_assoc(lang_items.u32_impl()) | |
291 | || fund_assoc(lang_items.u64_impl()) | |
292 | || fund_assoc(lang_items.u128_impl()) | |
293 | || fund_assoc(lang_items.f32_impl()) | |
294 | || fund_assoc(lang_items.f32_runtime_impl()) | |
295 | || fund_assoc(lang_items.f64_impl()) | |
296 | || fund_assoc(lang_items.f64_runtime_impl()); | |
297 | if let (true, false, SelfSource::MethodCall(expr), true) = ( | |
dfeec247 XL |
298 | actual.is_numeric(), |
299 | actual.has_concrete_skeleton(), | |
300 | source, | |
ba9703b0 | 301 | found_candidate, |
dfeec247 | 302 | ) { |
2c00a5a8 XL |
303 | let mut err = struct_span_err!( |
304 | tcx.sess, | |
305 | span, | |
306 | E0689, | |
307 | "can't call {} `{}` on ambiguous numeric type `{}`", | |
94b46f34 | 308 | item_kind, |
2c00a5a8 | 309 | item_name, |
0731742a | 310 | ty_str |
2c00a5a8 | 311 | ); |
dfeec247 | 312 | let concrete_type = if actual.is_integral() { "i32" } else { "f32" }; |
e74abb32 | 313 | match expr.kind { |
0731742a XL |
314 | ExprKind::Lit(ref lit) => { |
315 | // numeric literal | |
dfeec247 XL |
316 | let snippet = tcx |
317 | .sess | |
318 | .source_map() | |
319 | .span_to_snippet(lit.span) | |
0bf4aa26 | 320 | .unwrap_or_else(|_| "<numeric literal>".to_owned()); |
2c00a5a8 | 321 | |
3c0e092e XL |
322 | // If this is a floating point literal that ends with '.', |
323 | // get rid of it to stop this from becoming a member access. | |
324 | let snippet = snippet.strip_suffix('.').unwrap_or(&snippet); | |
325 | ||
9fa01778 XL |
326 | err.span_suggestion( |
327 | lit.span, | |
dfeec247 | 328 | &format!( |
cdc7bbd5 XL |
329 | "you must specify a concrete type for this numeric value, \ |
330 | like `{}`", | |
dfeec247 XL |
331 | concrete_type |
332 | ), | |
3c0e092e | 333 | format!("{snippet}_{concrete_type}"), |
9fa01778 | 334 | Applicability::MaybeIncorrect, |
0bf4aa26 | 335 | ); |
2c00a5a8 | 336 | } |
c295e0f8 | 337 | ExprKind::Path(QPath::Resolved(_, path)) => { |
0731742a | 338 | // local binding |
c295e0f8 XL |
339 | if let hir::def::Res::Local(hir_id) = path.res { |
340 | let span = tcx.hir().span(hir_id); | |
341 | let snippet = tcx.sess.source_map().span_to_snippet(span); | |
342 | let filename = tcx.sess.source_map().span_to_filename(span); | |
343 | ||
344 | let parent_node = | |
345 | self.tcx.hir().get(self.tcx.hir().get_parent_node(hir_id)); | |
346 | let msg = format!( | |
347 | "you must specify a type for this binding, like `{}`", | |
348 | concrete_type, | |
349 | ); | |
350 | ||
351 | match (filename, parent_node, snippet) { | |
352 | ( | |
353 | FileName::Real(_), | |
354 | Node::Local(hir::Local { | |
355 | source: hir::LocalSource::Normal, | |
356 | ty, | |
357 | .. | |
358 | }), | |
359 | Ok(ref snippet), | |
360 | ) => { | |
361 | err.span_suggestion( | |
362 | // account for `let x: _ = 42;` | |
363 | // ^^^^ | |
364 | span.to(ty | |
365 | .as_ref() | |
366 | .map(|ty| ty.span) | |
367 | .unwrap_or(span)), | |
368 | &msg, | |
369 | format!("{}: {}", snippet, concrete_type), | |
370 | Applicability::MaybeIncorrect, | |
371 | ); | |
372 | } | |
373 | _ => { | |
374 | err.span_label(span, msg); | |
8faf50e0 | 375 | } |
2c00a5a8 XL |
376 | } |
377 | } | |
378 | } | |
379 | _ => {} | |
380 | } | |
381 | err.emit(); | |
e1599b0c | 382 | return None; |
2c00a5a8 | 383 | } else { |
532ac7d7 | 384 | span = item_name.span; |
17df50a5 XL |
385 | |
386 | // Don't show generic arguments when the method can't be found in any implementation (#81576). | |
387 | let mut ty_str_reported = ty_str.clone(); | |
c295e0f8 | 388 | if let ty::Adt(_, generics) = actual.kind() { |
17df50a5 XL |
389 | if generics.len() > 0 { |
390 | let mut autoderef = self.autoderef(span, actual); | |
391 | let candidate_found = autoderef.any(|(ty, _)| { | |
c295e0f8 | 392 | if let ty::Adt(adt_deref, _) = ty.kind() { |
17df50a5 XL |
393 | self.tcx |
394 | .inherent_impls(adt_deref.did) | |
395 | .iter() | |
396 | .filter_map(|def_id| { | |
397 | self.associated_item( | |
398 | *def_id, | |
399 | item_name, | |
400 | Namespace::ValueNS, | |
401 | ) | |
402 | }) | |
403 | .count() | |
404 | >= 1 | |
405 | } else { | |
406 | false | |
407 | } | |
408 | }); | |
409 | let has_deref = autoderef.step_count() > 0; | |
410 | if !candidate_found | |
411 | && !has_deref | |
412 | && unsatisfied_predicates.is_empty() | |
413 | { | |
414 | if let Some((path_string, _)) = ty_str.split_once('<') { | |
415 | ty_str_reported = path_string.to_string(); | |
416 | } | |
417 | } | |
418 | } | |
419 | } | |
420 | ||
0531ce1d | 421 | let mut err = struct_span_err!( |
2c00a5a8 | 422 | tcx.sess, |
532ac7d7 | 423 | span, |
2c00a5a8 | 424 | E0599, |
dfeec247 | 425 | "no {} named `{}` found for {} `{}` in the current scope", |
94b46f34 | 426 | item_kind, |
2c00a5a8 | 427 | item_name, |
6a06907d | 428 | actual.prefix_string(self.tcx), |
17df50a5 | 429 | ty_str_reported, |
0531ce1d | 430 | ); |
1b1a35ee XL |
431 | if let Mode::MethodCall = mode { |
432 | if let SelfSource::MethodCall(call) = source { | |
433 | self.suggest_await_before_method( | |
434 | &mut err, item_name, actual, call, span, | |
435 | ); | |
436 | } | |
437 | } | |
dfeec247 | 438 | if let Some(span) = |
c295e0f8 | 439 | tcx.resolutions(()).confused_type_with_std_module.get(&span) |
48663c56 XL |
440 | { |
441 | if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*span) { | |
442 | err.span_suggestion( | |
443 | *span, | |
444 | "you are looking for the module in `std`, \ | |
445 | not the primitive type", | |
446 | format!("std::{}", snippet), | |
447 | Applicability::MachineApplicable, | |
448 | ); | |
449 | } | |
0531ce1d | 450 | } |
1b1a35ee | 451 | if let ty::RawPtr(_) = &actual.kind() { |
dfeec247 XL |
452 | err.note( |
453 | "try using `<*const T>::as_ref()` to get a reference to the \ | |
dc9dc135 | 454 | type behind the pointer: https://doc.rust-lang.org/std/\ |
dfeec247 XL |
455 | primitive.pointer.html#method.as_ref", |
456 | ); | |
457 | err.note( | |
458 | "using `<*const T>::as_ref()` on a pointer \ | |
416331ca | 459 | which is unaligned or points to invalid \ |
dfeec247 XL |
460 | or uninitialized memory is undefined behavior", |
461 | ); | |
dc9dc135 | 462 | } |
0531ce1d | 463 | err |
2c00a5a8 | 464 | } |
7cac9316 | 465 | } else { |
ff7c6d11 | 466 | tcx.sess.diagnostic().struct_dummy() |
7cac9316 | 467 | }; |
5bcae85e | 468 | |
94b46f34 | 469 | if let Some(def) = actual.ty_adt_def() { |
0731742a | 470 | if let Some(full_sp) = tcx.hir().span_if_local(def.did) { |
ba9703b0 | 471 | let def_sp = tcx.sess.source_map().guess_head_span(full_sp); |
dfeec247 XL |
472 | err.span_label( |
473 | def_sp, | |
474 | format!( | |
475 | "{} `{}` not found {}", | |
476 | item_kind, | |
477 | item_name, | |
478 | if def.is_enum() && !is_method { "here" } else { "for this" } | |
479 | ), | |
480 | ); | |
ff7c6d11 XL |
481 | } |
482 | } | |
483 | ||
5869c6ff XL |
484 | let mut label_span_not_found = || { |
485 | if unsatisfied_predicates.is_empty() { | |
486 | err.span_label(span, format!("{item_kind} not found in `{ty_str}`")); | |
3c0e092e XL |
487 | let is_string_or_ref_str = match actual.kind() { |
488 | ty::Ref(_, ty, _) => { | |
489 | ty.is_str() | |
490 | || matches!( | |
491 | ty.kind(), | |
492 | ty::Adt(adt, _) if self.tcx.is_diagnostic_item(sym::String, adt.did) | |
493 | ) | |
494 | } | |
495 | ty::Adt(adt, _) => self.tcx.is_diagnostic_item(sym::String, adt.did), | |
496 | _ => false, | |
497 | }; | |
498 | if is_string_or_ref_str && item_name.name == sym::iter { | |
499 | err.span_suggestion_verbose( | |
500 | item_name.span, | |
501 | "because of the in-memory representation of `&str`, to obtain \ | |
502 | an `Iterator` over each of its codepoint use method `chars`", | |
503 | String::from("chars"), | |
504 | Applicability::MachineApplicable, | |
505 | ); | |
506 | } | |
c295e0f8 | 507 | if let ty::Adt(adt, _) = rcvr_ty.kind() { |
17df50a5 XL |
508 | let mut inherent_impls_candidate = self |
509 | .tcx | |
510 | .inherent_impls(adt.did) | |
511 | .iter() | |
512 | .copied() | |
513 | .filter(|def_id| { | |
514 | if let Some(assoc) = | |
515 | self.associated_item(*def_id, item_name, Namespace::ValueNS) | |
516 | { | |
517 | // Check for both mode is the same so we avoid suggesting | |
518 | // incorrect associated item. | |
519 | match (mode, assoc.fn_has_self_parameter, source) { | |
520 | (Mode::MethodCall, true, SelfSource::MethodCall(_)) => { | |
521 | // We check that the suggest type is actually | |
522 | // different from the received one | |
523 | // So we avoid suggestion method with Box<Self> | |
524 | // for instance | |
525 | self.tcx.at(span).type_of(*def_id) != actual | |
526 | && self.tcx.at(span).type_of(*def_id) != rcvr_ty | |
527 | } | |
528 | (Mode::Path, false, _) => true, | |
529 | _ => false, | |
530 | } | |
531 | } else { | |
532 | false | |
533 | } | |
534 | }) | |
535 | .collect::<Vec<_>>(); | |
c295e0f8 | 536 | if !inherent_impls_candidate.is_empty() { |
17df50a5 XL |
537 | inherent_impls_candidate.sort(); |
538 | inherent_impls_candidate.dedup(); | |
539 | ||
540 | // number of type to shows at most. | |
541 | let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 }; | |
542 | let type_candidates = inherent_impls_candidate | |
543 | .iter() | |
544 | .take(limit) | |
545 | .map(|impl_item| { | |
546 | format!("- `{}`", self.tcx.at(span).type_of(*impl_item)) | |
547 | }) | |
548 | .collect::<Vec<_>>() | |
549 | .join("\n"); | |
550 | let additional_types = if inherent_impls_candidate.len() > limit { | |
551 | format!( | |
552 | "\nand {} more types", | |
553 | inherent_impls_candidate.len() - limit | |
554 | ) | |
555 | } else { | |
556 | "".to_string() | |
557 | }; | |
558 | err.note(&format!( | |
559 | "the {item_kind} was found for\n{}{}", | |
560 | type_candidates, additional_types | |
561 | )); | |
562 | } | |
563 | } | |
5869c6ff XL |
564 | } else { |
565 | err.span_label(span, format!("{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds")); | |
566 | } | |
5869c6ff XL |
567 | }; |
568 | ||
5bcae85e | 569 | // If the method name is the name of a field with a function or closure type, |
0731742a XL |
570 | // give a helping note that it has to be called as `(x.f)(...)`. |
571 | if let SelfSource::MethodCall(expr) = source { | |
dfeec247 | 572 | let field_receiver = |
1b1a35ee | 573 | self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() { |
532ac7d7 | 574 | ty::Adt(def, substs) if !def.is_enum() => { |
83c7162d | 575 | let variant = &def.non_enum_variant(); |
532ac7d7 | 576 | self.tcx.find_field_index(item_name, variant).map(|index| { |
83c7162d | 577 | let field = &variant.fields[index]; |
9e0c209e | 578 | let field_ty = field.ty(tcx, substs); |
532ac7d7 XL |
579 | (field, field_ty) |
580 | }) | |
581 | } | |
582 | _ => None, | |
583 | }); | |
584 | ||
585 | if let Some((field, field_ty)) = field_receiver { | |
ba9703b0 | 586 | let scope = self.tcx.parent_module(self.body_id).to_def_id(); |
532ac7d7 XL |
587 | let is_accessible = field.vis.is_accessible_from(scope, self.tcx); |
588 | ||
589 | if is_accessible { | |
c295e0f8 | 590 | if self.is_fn_ty(field_ty, span) { |
532ac7d7 XL |
591 | let expr_span = expr.span.to(item_name.span); |
592 | err.multipart_suggestion( | |
593 | &format!( | |
594 | "to call the function stored in `{}`, \ | |
595 | surround the field access with parentheses", | |
596 | item_name, | |
597 | ), | |
598 | vec![ | |
599 | (expr_span.shrink_to_lo(), '('.to_string()), | |
600 | (expr_span.shrink_to_hi(), ')'.to_string()), | |
601 | ], | |
602 | Applicability::MachineApplicable, | |
603 | ); | |
604 | } else { | |
dfeec247 XL |
605 | let call_expr = self |
606 | .tcx | |
607 | .hir() | |
608 | .expect_expr(self.tcx.hir().get_parent_node(expr.hir_id)); | |
532ac7d7 | 609 | |
48663c56 XL |
610 | if let Some(span) = call_expr.span.trim_start(item_name.span) { |
611 | err.span_suggestion( | |
612 | span, | |
613 | "remove the arguments", | |
614 | String::new(), | |
615 | Applicability::MaybeIncorrect, | |
616 | ); | |
617 | } | |
5bcae85e | 618 | } |
a7813a04 | 619 | } |
532ac7d7 | 620 | |
dfeec247 | 621 | let field_kind = if is_accessible { "field" } else { "private field" }; |
532ac7d7 | 622 | err.span_label(item_name.span, format!("{}, not a method", field_kind)); |
e1599b0c | 623 | } else if lev_candidate.is_none() && static_sources.is_empty() { |
5869c6ff | 624 | label_span_not_found(); |
54a0048b | 625 | } |
ff7c6d11 | 626 | } else { |
5869c6ff | 627 | label_span_not_found(); |
54a0048b | 628 | } |
92a42be0 | 629 | |
c295e0f8 | 630 | if self.is_fn_ty(rcvr_ty, span) { |
6a06907d XL |
631 | fn report_function<T: std::fmt::Display>( |
632 | err: &mut DiagnosticBuilder<'_>, | |
633 | name: T, | |
634 | ) { | |
635 | err.note( | |
636 | &format!("`{}` is a function, perhaps you wish to call it", name,), | |
637 | ); | |
54a0048b | 638 | } |
a7813a04 | 639 | |
0731742a | 640 | if let SelfSource::MethodCall(expr) = source { |
b7449926 | 641 | if let Ok(expr_string) = tcx.sess.source_map().span_to_snippet(expr.span) { |
6a06907d | 642 | report_function(&mut err, expr_string); |
c295e0f8 | 643 | } else if let ExprKind::Path(QPath::Resolved(_, path)) = expr.kind { |
a7813a04 | 644 | if let Some(segment) = path.segments.last() { |
6a06907d | 645 | report_function(&mut err, segment.ident); |
a7813a04 | 646 | } |
62682a34 SL |
647 | } |
648 | } | |
c34b1796 | 649 | } |
85aaf69f | 650 | |
a7813a04 | 651 | if !static_sources.is_empty() { |
dfeec247 XL |
652 | err.note( |
653 | "found the following associated functions; to be used as methods, \ | |
74b04a01 | 654 | functions must have a `self` parameter", |
dfeec247 | 655 | ); |
94b46f34 XL |
656 | err.span_label(span, "this is an associated function, not a method"); |
657 | } | |
658 | if static_sources.len() == 1 { | |
dfeec247 XL |
659 | let ty_str = if let Some(CandidateSource::ImplSource(impl_did)) = |
660 | static_sources.get(0) | |
661 | { | |
e74abb32 XL |
662 | // When the "method" is resolved through dereferencing, we really want the |
663 | // original type that has the associated function for accurate suggestions. | |
664 | // (#61411) | |
ba9703b0 | 665 | let ty = tcx.at(span).type_of(*impl_did); |
1b1a35ee | 666 | match (&ty.peel_refs().kind(), &actual.peel_refs().kind()) { |
e74abb32 XL |
667 | (ty::Adt(def, _), ty::Adt(def_actual, _)) if def == def_actual => { |
668 | // Use `actual` as it will have more `substs` filled in. | |
669 | self.ty_to_value_string(actual.peel_refs()) | |
670 | } | |
671 | _ => self.ty_to_value_string(ty.peel_refs()), | |
672 | } | |
673 | } else { | |
674 | self.ty_to_value_string(actual.peel_refs()) | |
675 | }; | |
0731742a | 676 | if let SelfSource::MethodCall(expr) = source { |
e74abb32 XL |
677 | err.span_suggestion( |
678 | expr.span.to(span), | |
679 | "use associated function syntax instead", | |
680 | format!("{}::{}", ty_str, item_name), | |
681 | Applicability::MachineApplicable, | |
682 | ); | |
94b46f34 | 683 | } else { |
dfeec247 | 684 | err.help(&format!("try with `{}::{}`", ty_str, item_name,)); |
94b46f34 XL |
685 | } |
686 | ||
dfeec247 | 687 | report_candidates(span, &mut err, static_sources, sugg_span); |
94b46f34 | 688 | } else if static_sources.len() > 1 { |
dfeec247 | 689 | report_candidates(span, &mut err, static_sources, sugg_span); |
a7813a04 | 690 | } |
85aaf69f | 691 | |
74b04a01 | 692 | let mut restrict_type_params = false; |
cdc7bbd5 | 693 | let mut unsatisfied_bounds = false; |
a7813a04 | 694 | if !unsatisfied_predicates.is_empty() { |
ba9703b0 XL |
695 | let def_span = |def_id| { |
696 | self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id)) | |
697 | }; | |
74b04a01 XL |
698 | let mut type_params = FxHashMap::default(); |
699 | let mut bound_spans = vec![]; | |
3dfed10e | 700 | |
74b04a01 | 701 | let mut collect_type_param_suggestions = |
3dfed10e XL |
702 | |self_ty: Ty<'tcx>, parent_pred: &ty::Predicate<'tcx>, obligation: &str| { |
703 | // We don't care about regions here, so it's fine to skip the binder here. | |
94222f64 | 704 | if let (ty::Param(_), ty::PredicateKind::Trait(p)) = |
5869c6ff | 705 | (self_ty.kind(), parent_pred.kind().skip_binder()) |
74b04a01 | 706 | { |
3c0e092e XL |
707 | let node = match p.trait_ref.self_ty().kind() { |
708 | ty::Param(_) => { | |
709 | // Account for `fn` items like in `issue-35677.rs` to | |
710 | // suggest restricting its type params. | |
711 | let did = self.tcx.hir().body_owner_def_id(hir::BodyId { | |
712 | hir_id: self.body_id, | |
713 | }); | |
714 | Some( | |
715 | self.tcx | |
716 | .hir() | |
717 | .get(self.tcx.hir().local_def_id_to_hir_id(did)), | |
718 | ) | |
719 | } | |
720 | ty::Adt(def, _) => def.did.as_local().map(|def_id| { | |
3dfed10e XL |
721 | self.tcx |
722 | .hir() | |
723 | .get(self.tcx.hir().local_def_id_to_hir_id(def_id)) | |
3c0e092e XL |
724 | }), |
725 | _ => None, | |
726 | }; | |
727 | if let Some(hir::Node::Item(hir::Item { kind, .. })) = node { | |
728 | if let Some(g) = kind.generics() { | |
729 | let key = match g.where_clause.predicates { | |
730 | [.., pred] => (pred.span().shrink_to_hi(), false), | |
731 | [] => ( | |
732 | g.where_clause.span_for_predicates_or_empty_place(), | |
733 | true, | |
734 | ), | |
735 | }; | |
736 | type_params | |
737 | .entry(key) | |
738 | .or_insert_with(FxHashSet::default) | |
739 | .insert(obligation.to_owned()); | |
74b04a01 XL |
740 | } |
741 | } | |
742 | } | |
743 | }; | |
744 | let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| { | |
745 | let msg = format!( | |
746 | "doesn't satisfy `{}`", | |
747 | if obligation.len() > 50 { quiet } else { obligation } | |
748 | ); | |
1b1a35ee | 749 | match &self_ty.kind() { |
74b04a01 XL |
750 | // Point at the type that couldn't satisfy the bound. |
751 | ty::Adt(def, _) => bound_spans.push((def_span(def.did), msg)), | |
752 | // Point at the trait object that couldn't satisfy the bound. | |
753 | ty::Dynamic(preds, _) => { | |
fc512014 XL |
754 | for pred in preds.iter() { |
755 | match pred.skip_binder() { | |
74b04a01 XL |
756 | ty::ExistentialPredicate::Trait(tr) => { |
757 | bound_spans.push((def_span(tr.def_id), msg.clone())) | |
758 | } | |
759 | ty::ExistentialPredicate::Projection(_) | |
760 | | ty::ExistentialPredicate::AutoTrait(_) => {} | |
761 | } | |
762 | } | |
763 | } | |
764 | // Point at the closure that couldn't satisfy the bound. | |
765 | ty::Closure(def_id, _) => bound_spans | |
766 | .push((def_span(*def_id), format!("doesn't satisfy `{}`", quiet))), | |
767 | _ => {} | |
768 | } | |
769 | }; | |
f9f354fc | 770 | let mut format_pred = |pred: ty::Predicate<'tcx>| { |
5869c6ff | 771 | let bound_predicate = pred.kind(); |
29967ef6 | 772 | match bound_predicate.skip_binder() { |
5869c6ff | 773 | ty::PredicateKind::Projection(pred) => { |
29967ef6 | 774 | let pred = bound_predicate.rebind(pred); |
74b04a01 | 775 | // `<Foo as Iterator>::Item = String`. |
6a06907d XL |
776 | let projection_ty = pred.skip_binder().projection_ty; |
777 | ||
778 | let substs_with_infer_self = tcx.mk_substs( | |
c295e0f8 | 779 | iter::once(tcx.mk_ty_var(ty::TyVid::from_u32(0)).into()) |
6a06907d | 780 | .chain(projection_ty.substs.iter().skip(1)), |
74b04a01 | 781 | ); |
6a06907d XL |
782 | |
783 | let quiet_projection_ty = ty::ProjectionTy { | |
784 | substs: substs_with_infer_self, | |
785 | item_def_id: projection_ty.item_def_id, | |
786 | }; | |
787 | ||
788 | let ty = pred.skip_binder().ty; | |
789 | ||
790 | let obligation = format!("{} = {}", projection_ty, ty); | |
791 | let quiet = format!("{} = {}", quiet_projection_ty, ty); | |
792 | ||
793 | bound_span_label(projection_ty.self_ty(), &obligation, &quiet); | |
794 | Some((obligation, projection_ty.self_ty())) | |
74b04a01 | 795 | } |
94222f64 | 796 | ty::PredicateKind::Trait(poly_trait_ref) => { |
29967ef6 | 797 | let p = poly_trait_ref.trait_ref; |
74b04a01 XL |
798 | let self_ty = p.self_ty(); |
799 | let path = p.print_only_trait_path(); | |
800 | let obligation = format!("{}: {}", self_ty, path); | |
801 | let quiet = format!("_: {}", path); | |
802 | bound_span_label(self_ty, &obligation, &quiet); | |
803 | Some((obligation, self_ty)) | |
804 | } | |
805 | _ => None, | |
806 | } | |
807 | }; | |
3c0e092e XL |
808 | |
809 | // Find all the requirements that come from a local `impl` block. | |
810 | let mut skip_list: FxHashSet<_> = Default::default(); | |
811 | let mut spanned_predicates: FxHashMap<MultiSpan, _> = Default::default(); | |
812 | for (data, p, parent_p) in unsatisfied_predicates | |
813 | .iter() | |
814 | .filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c))) | |
815 | .filter_map(|(p, parent, c)| match c.code { | |
816 | ObligationCauseCode::ImplDerivedObligation(ref data) => { | |
817 | Some((data, p, parent)) | |
818 | } | |
819 | _ => None, | |
820 | }) | |
821 | { | |
822 | let parent_trait_ref = data.parent_trait_ref; | |
823 | let parent_def_id = parent_trait_ref.def_id(); | |
824 | let path = parent_trait_ref.print_only_trait_path(); | |
825 | let tr_self_ty = parent_trait_ref.skip_binder().self_ty(); | |
826 | let mut candidates = vec![]; | |
827 | self.tcx.for_each_relevant_impl( | |
828 | parent_def_id, | |
829 | parent_trait_ref.self_ty().skip_binder(), | |
830 | |impl_def_id| match self.tcx.hir().get_if_local(impl_def_id) { | |
831 | Some(Node::Item(hir::Item { | |
832 | kind: hir::ItemKind::Impl(hir::Impl { .. }), | |
833 | .. | |
834 | })) => { | |
835 | candidates.push(impl_def_id); | |
836 | } | |
837 | _ => {} | |
838 | }, | |
839 | ); | |
840 | if let [def_id] = &candidates[..] { | |
841 | match self.tcx.hir().get_if_local(*def_id) { | |
842 | Some(Node::Item(hir::Item { | |
843 | kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }), | |
844 | .. | |
845 | })) => { | |
846 | if let Some(pred) = parent_p { | |
847 | // Done to add the "doesn't satisfy" `span_label`. | |
848 | let _ = format_pred(*pred); | |
849 | } | |
850 | skip_list.insert(p); | |
851 | let mut spans = Vec::with_capacity(2); | |
852 | if let Some(trait_ref) = of_trait { | |
853 | spans.push(trait_ref.path.span); | |
854 | } | |
855 | spans.push(self_ty.span); | |
856 | let entry = spanned_predicates.entry(spans.into()); | |
857 | entry | |
858 | .or_insert_with(|| (path, tr_self_ty, Vec::new())) | |
859 | .2 | |
860 | .push(p); | |
861 | } | |
862 | _ => {} | |
863 | } | |
864 | } | |
865 | } | |
866 | for (span, (path, self_ty, preds)) in spanned_predicates { | |
867 | err.span_note( | |
868 | span, | |
869 | &format!( | |
870 | "the following trait bounds were not satisfied because of the \ | |
871 | requirements of the implementation of `{}` for `{}`:\n{}", | |
872 | path, | |
873 | self_ty, | |
874 | preds | |
875 | .into_iter() | |
876 | // .map(|pred| format!("{:?}", pred)) | |
877 | .filter_map(|pred| format_pred(*pred)) | |
878 | .map(|(p, _)| format!("`{}`", p)) | |
879 | .collect::<Vec<_>>() | |
880 | .join("\n"), | |
881 | ), | |
882 | ); | |
883 | } | |
884 | ||
885 | // The requirements that didn't have an `impl` span to show. | |
dfeec247 XL |
886 | let mut bound_list = unsatisfied_predicates |
887 | .iter() | |
3c0e092e XL |
888 | .filter(|(pred, _, _parent_pred)| !skip_list.contains(&pred)) |
889 | .filter_map(|(pred, parent_pred, _cause)| { | |
890 | format_pred(*pred).map(|(p, self_ty)| { | |
891 | collect_type_param_suggestions(self_ty, pred, &p); | |
892 | match parent_pred { | |
fc512014 | 893 | None => format!("`{}`", &p), |
3c0e092e XL |
894 | Some(parent_pred) => match format_pred(*parent_pred) { |
895 | None => format!("`{}`", &p), | |
896 | Some((parent_p, _)) => { | |
897 | collect_type_param_suggestions( | |
898 | self_ty, | |
899 | parent_pred, | |
900 | &p, | |
901 | ); | |
902 | format!("`{}`\nwhich is required by `{}`", p, parent_p) | |
903 | } | |
904 | }, | |
905 | } | |
74b04a01 XL |
906 | }) |
907 | }) | |
908 | .enumerate() | |
909 | .collect::<Vec<(usize, String)>>(); | |
3c0e092e | 910 | |
74b04a01 XL |
911 | for ((span, empty_where), obligations) in type_params.into_iter() { |
912 | restrict_type_params = true; | |
3dfed10e XL |
913 | // #74886: Sort here so that the output is always the same. |
914 | let mut obligations = obligations.into_iter().collect::<Vec<_>>(); | |
915 | obligations.sort(); | |
74b04a01 XL |
916 | err.span_suggestion_verbose( |
917 | span, | |
918 | &format!( | |
919 | "consider restricting the type parameter{s} to satisfy the \ | |
920 | trait bound{s}", | |
921 | s = pluralize!(obligations.len()) | |
922 | ), | |
923 | format!( | |
924 | "{} {}", | |
925 | if empty_where { " where" } else { "," }, | |
3dfed10e | 926 | obligations.join(", ") |
74b04a01 XL |
927 | ), |
928 | Applicability::MaybeIncorrect, | |
929 | ); | |
930 | } | |
931 | ||
c295e0f8 | 932 | bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically. |
74b04a01 XL |
933 | bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677 |
934 | bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order. | |
935 | bound_spans.sort(); | |
936 | bound_spans.dedup(); | |
937 | for (span, msg) in bound_spans.into_iter() { | |
938 | err.span_label(span, &msg); | |
939 | } | |
3c0e092e | 940 | if !bound_list.is_empty() || !skip_list.is_empty() { |
74b04a01 XL |
941 | let bound_list = bound_list |
942 | .into_iter() | |
943 | .map(|(_, path)| path) | |
944 | .collect::<Vec<_>>() | |
945 | .join("\n"); | |
6a06907d | 946 | let actual_prefix = actual.prefix_string(self.tcx); |
5869c6ff XL |
947 | err.set_primary_message(&format!( |
948 | "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, but its trait bounds were not satisfied" | |
949 | )); | |
3c0e092e XL |
950 | if !bound_list.is_empty() { |
951 | err.note(&format!( | |
952 | "the following trait bounds were not satisfied:\n{bound_list}" | |
953 | )); | |
954 | } | |
c295e0f8 XL |
955 | self.suggest_derive(&mut err, &unsatisfied_predicates); |
956 | ||
cdc7bbd5 | 957 | unsatisfied_bounds = true; |
74b04a01 | 958 | } |
a7813a04 | 959 | } |
62682a34 | 960 | |
74b04a01 | 961 | if actual.is_numeric() && actual.is_fresh() || restrict_type_params { |
2c00a5a8 | 962 | } else { |
dfeec247 XL |
963 | self.suggest_traits_to_import( |
964 | &mut err, | |
965 | span, | |
966 | rcvr_ty, | |
967 | item_name, | |
968 | source, | |
969 | out_of_scope_traits, | |
74b04a01 | 970 | &unsatisfied_predicates, |
cdc7bbd5 | 971 | unsatisfied_bounds, |
dfeec247 | 972 | ); |
2c00a5a8 | 973 | } |
ea8adc8c | 974 | |
5869c6ff XL |
975 | // Don't emit a suggestion if we found an actual method |
976 | // that had unsatisfied trait bounds | |
977 | if unsatisfied_predicates.is_empty() && actual.is_enum() { | |
48663c56 XL |
978 | let adt_def = actual.ty_adt_def().expect("enum is not an ADT"); |
979 | if let Some(suggestion) = lev_distance::find_best_match_for_name( | |
fc512014 | 980 | &adt_def.variants.iter().map(|s| s.ident.name).collect::<Vec<_>>(), |
3dfed10e | 981 | item_name.name, |
48663c56 XL |
982 | None, |
983 | ) { | |
984 | err.span_suggestion( | |
985 | span, | |
986 | "there is a variant with a similar name", | |
987 | suggestion.to_string(), | |
988 | Applicability::MaybeIncorrect, | |
989 | ); | |
990 | } | |
991 | } | |
992 | ||
e74abb32 XL |
993 | let mut fallback_span = true; |
994 | let msg = "remove this method call"; | |
3dfed10e | 995 | if item_name.name == sym::as_str && actual.peel_refs().is_str() { |
e74abb32 | 996 | if let SelfSource::MethodCall(expr) = source { |
dfeec247 XL |
997 | let call_expr = |
998 | self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id)); | |
e74abb32 XL |
999 | if let Some(span) = call_expr.span.trim_start(expr.span) { |
1000 | err.span_suggestion( | |
1001 | span, | |
1002 | msg, | |
1003 | String::new(), | |
1004 | Applicability::MachineApplicable, | |
1005 | ); | |
1006 | fallback_span = false; | |
1007 | } | |
1008 | } | |
1009 | if fallback_span { | |
1010 | err.span_label(span, msg); | |
1011 | } | |
1012 | } else if let Some(lev_candidate) = lev_candidate { | |
5869c6ff XL |
1013 | // Don't emit a suggestion if we found an actual method |
1014 | // that had unsatisfied trait bounds | |
1015 | if unsatisfied_predicates.is_empty() { | |
1016 | let def_kind = lev_candidate.kind.as_def_kind(); | |
1017 | err.span_suggestion( | |
1018 | span, | |
1019 | &format!( | |
1020 | "there is {} {} with a similar name", | |
1021 | def_kind.article(), | |
1022 | def_kind.descr(lev_candidate.def_id), | |
1023 | ), | |
1024 | lev_candidate.ident.to_string(), | |
1025 | Applicability::MaybeIncorrect, | |
1026 | ); | |
1027 | } | |
ea8adc8c | 1028 | } |
48663c56 | 1029 | |
e1599b0c | 1030 | return Some(err); |
a7813a04 | 1031 | } |
85aaf69f | 1032 | |
a7813a04 | 1033 | MethodError::Ambiguity(sources) => { |
dfeec247 XL |
1034 | let mut err = struct_span_err!( |
1035 | self.sess(), | |
ba9703b0 | 1036 | item_name.span, |
dfeec247 XL |
1037 | E0034, |
1038 | "multiple applicable items in scope" | |
1039 | ); | |
ba9703b0 | 1040 | err.span_label(item_name.span, format!("multiple `{}` found", item_name)); |
85aaf69f | 1041 | |
dfeec247 | 1042 | report_candidates(span, &mut err, sources, sugg_span); |
a7813a04 XL |
1043 | err.emit(); |
1044 | } | |
85aaf69f | 1045 | |
416331ca | 1046 | MethodError::PrivateMatch(kind, def_id, out_of_scope_traits) => { |
ba9703b0 | 1047 | let kind = kind.descr(def_id); |
dfeec247 XL |
1048 | let mut err = struct_span_err!( |
1049 | self.tcx.sess, | |
ba9703b0 | 1050 | item_name.span, |
dfeec247 XL |
1051 | E0624, |
1052 | "{} `{}` is private", | |
ba9703b0 | 1053 | kind, |
dfeec247 XL |
1054 | item_name |
1055 | ); | |
ba9703b0 | 1056 | err.span_label(item_name.span, &format!("private {}", kind)); |
136023e0 XL |
1057 | let sp = self |
1058 | .tcx | |
1059 | .hir() | |
1060 | .span_if_local(def_id) | |
1061 | .unwrap_or_else(|| self.tcx.def_span(def_id)); | |
1062 | err.span_label(sp, &format!("private {} defined here", kind)); | |
3b2f2976 XL |
1063 | self.suggest_valid_traits(&mut err, out_of_scope_traits); |
1064 | err.emit(); | |
a7813a04 | 1065 | } |
3b2f2976 | 1066 | |
74b04a01 | 1067 | MethodError::IllegalSizedBound(candidates, needs_mut, bound_span) => { |
3b2f2976 XL |
1068 | let msg = format!("the `{}` method cannot be invoked on a trait object", item_name); |
1069 | let mut err = self.sess().struct_span_err(span, &msg); | |
74b04a01 | 1070 | err.span_label(bound_span, "this has a `Sized` requirement"); |
3b2f2976 | 1071 | if !candidates.is_empty() { |
e74abb32 XL |
1072 | let help = format!( |
1073 | "{an}other candidate{s} {were} found in the following trait{s}, perhaps \ | |
1074 | add a `use` for {one_of_them}:", | |
dfeec247 | 1075 | an = if candidates.len() == 1 { "an" } else { "" }, |
60c5eb7d | 1076 | s = pluralize!(candidates.len()), |
e74abb32 | 1077 | were = if candidates.len() == 1 { "was" } else { "were" }, |
dfeec247 | 1078 | one_of_them = if candidates.len() == 1 { "it" } else { "one_of_them" }, |
e74abb32 | 1079 | ); |
3b2f2976 XL |
1080 | self.suggest_use_candidates(&mut err, help, candidates); |
1081 | } | |
1b1a35ee | 1082 | if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind() { |
e74abb32 | 1083 | if needs_mut { |
dfeec247 XL |
1084 | let trait_type = self.tcx.mk_ref( |
1085 | region, | |
1086 | ty::TypeAndMut { ty: t_type, mutbl: mutability.invert() }, | |
1087 | ); | |
e74abb32 XL |
1088 | err.note(&format!("you need `{}` instead of `{}`", trait_type, rcvr_ty)); |
1089 | } | |
1090 | } | |
3b2f2976 XL |
1091 | err.emit(); |
1092 | } | |
ea8adc8c | 1093 | |
dfeec247 | 1094 | MethodError::BadReturnType => bug!("no return type expectations but got BadReturnType"), |
3b2f2976 | 1095 | } |
e1599b0c | 1096 | None |
3b2f2976 XL |
1097 | } |
1098 | ||
c295e0f8 XL |
1099 | crate fn note_unmet_impls_on_type( |
1100 | &self, | |
1101 | err: &mut rustc_errors::DiagnosticBuilder<'_>, | |
1102 | errors: Vec<FulfillmentError<'tcx>>, | |
1103 | ) { | |
1104 | let all_local_types_needing_impls = | |
1105 | errors.iter().all(|e| match e.obligation.predicate.kind().skip_binder() { | |
1106 | ty::PredicateKind::Trait(pred) => match pred.self_ty().kind() { | |
1107 | ty::Adt(def, _) => def.did.is_local(), | |
1108 | _ => false, | |
1109 | }, | |
1110 | _ => false, | |
1111 | }); | |
1112 | let mut preds: Vec<_> = errors | |
1113 | .iter() | |
1114 | .filter_map(|e| match e.obligation.predicate.kind().skip_binder() { | |
1115 | ty::PredicateKind::Trait(pred) => Some(pred), | |
1116 | _ => None, | |
1117 | }) | |
1118 | .collect(); | |
1119 | preds.sort_by_key(|pred| (pred.def_id(), pred.self_ty())); | |
1120 | let def_ids = preds | |
1121 | .iter() | |
1122 | .filter_map(|pred| match pred.self_ty().kind() { | |
1123 | ty::Adt(def, _) => Some(def.did), | |
1124 | _ => None, | |
1125 | }) | |
1126 | .collect::<FxHashSet<_>>(); | |
1127 | let sm = self.tcx.sess.source_map(); | |
1128 | let mut spans: MultiSpan = def_ids | |
1129 | .iter() | |
1130 | .filter_map(|def_id| { | |
1131 | let span = self.tcx.def_span(*def_id); | |
1132 | if span.is_dummy() { None } else { Some(sm.guess_head_span(span)) } | |
1133 | }) | |
1134 | .collect::<Vec<_>>() | |
1135 | .into(); | |
1136 | ||
1137 | for pred in &preds { | |
1138 | match pred.self_ty().kind() { | |
1139 | ty::Adt(def, _) => { | |
1140 | spans.push_span_label( | |
1141 | sm.guess_head_span(self.tcx.def_span(def.did)), | |
1142 | format!("must implement `{}`", pred.trait_ref.print_only_trait_path()), | |
1143 | ); | |
1144 | } | |
1145 | _ => {} | |
1146 | } | |
1147 | } | |
1148 | ||
1149 | if all_local_types_needing_impls && spans.primary_span().is_some() { | |
1150 | let msg = if preds.len() == 1 { | |
1151 | format!( | |
1152 | "an implementation of `{}` might be missing for `{}`", | |
1153 | preds[0].trait_ref.print_only_trait_path(), | |
1154 | preds[0].self_ty() | |
1155 | ) | |
1156 | } else { | |
1157 | format!( | |
1158 | "the following type{} would have to `impl` {} required trait{} for this \ | |
1159 | operation to be valid", | |
1160 | pluralize!(def_ids.len()), | |
1161 | if def_ids.len() == 1 { "its" } else { "their" }, | |
1162 | pluralize!(preds.len()), | |
1163 | ) | |
1164 | }; | |
1165 | err.span_note(spans, &msg); | |
1166 | } | |
1167 | ||
3c0e092e XL |
1168 | let preds: Vec<_> = errors |
1169 | .iter() | |
1170 | .map(|e| (e.obligation.predicate, None, Some(e.obligation.cause.clone()))) | |
1171 | .collect(); | |
c295e0f8 XL |
1172 | self.suggest_derive(err, &preds); |
1173 | } | |
1174 | ||
1175 | fn suggest_derive( | |
1176 | &self, | |
1177 | err: &mut DiagnosticBuilder<'_>, | |
3c0e092e XL |
1178 | unsatisfied_predicates: &Vec<( |
1179 | ty::Predicate<'tcx>, | |
1180 | Option<ty::Predicate<'tcx>>, | |
1181 | Option<ObligationCause<'tcx>>, | |
1182 | )>, | |
c295e0f8 XL |
1183 | ) { |
1184 | let mut derives = Vec::<(String, Span, String)>::new(); | |
1185 | let mut traits = Vec::<Span>::new(); | |
3c0e092e | 1186 | for (pred, _, _) in unsatisfied_predicates { |
c295e0f8 XL |
1187 | let trait_pred = match pred.kind().skip_binder() { |
1188 | ty::PredicateKind::Trait(trait_pred) => trait_pred, | |
1189 | _ => continue, | |
1190 | }; | |
1191 | let adt = match trait_pred.self_ty().ty_adt_def() { | |
1192 | Some(adt) if adt.did.is_local() => adt, | |
1193 | _ => continue, | |
1194 | }; | |
1195 | let can_derive = match self.tcx.get_diagnostic_name(trait_pred.def_id()) { | |
1196 | Some(sym::Default) => !adt.is_enum(), | |
1197 | Some( | |
1198 | sym::Eq | |
1199 | | sym::PartialEq | |
1200 | | sym::Ord | |
1201 | | sym::PartialOrd | |
1202 | | sym::Clone | |
1203 | | sym::Copy | |
1204 | | sym::Hash | |
1205 | | sym::Debug, | |
1206 | ) => true, | |
1207 | _ => false, | |
1208 | }; | |
1209 | if can_derive { | |
1210 | derives.push(( | |
1211 | format!("{}", trait_pred.self_ty()), | |
1212 | self.tcx.def_span(adt.did), | |
1213 | format!("{}", trait_pred.trait_ref.print_only_trait_name()), | |
1214 | )); | |
1215 | } else { | |
1216 | traits.push(self.tcx.def_span(trait_pred.def_id())); | |
1217 | } | |
1218 | } | |
1219 | derives.sort(); | |
1220 | let derives_grouped = derives.into_iter().fold( | |
1221 | Vec::<(String, Span, String)>::new(), | |
1222 | |mut acc, (self_name, self_span, trait_name)| { | |
1223 | if let Some((acc_self_name, _, ref mut traits)) = acc.last_mut() { | |
1224 | if acc_self_name == &self_name { | |
1225 | traits.push_str(format!(", {}", trait_name).as_str()); | |
1226 | return acc; | |
1227 | } | |
1228 | } | |
1229 | acc.push((self_name, self_span, trait_name)); | |
1230 | acc | |
1231 | }, | |
1232 | ); | |
1233 | traits.sort(); | |
1234 | traits.dedup(); | |
1235 | ||
1236 | let len = traits.len(); | |
1237 | if len > 0 { | |
1238 | let span: MultiSpan = traits.into(); | |
1239 | err.span_note( | |
1240 | span, | |
1241 | &format!("the following trait{} must be implemented", pluralize!(len),), | |
1242 | ); | |
1243 | } | |
1244 | ||
1245 | for (self_name, self_span, traits) in &derives_grouped { | |
1246 | err.span_suggestion_verbose( | |
1247 | self_span.shrink_to_lo(), | |
1248 | &format!("consider annotating `{}` with `#[derive({})]`", self_name, traits), | |
1249 | format!("#[derive({})]\n", traits), | |
1250 | Applicability::MaybeIncorrect, | |
1251 | ); | |
1252 | } | |
1253 | } | |
1254 | ||
e74abb32 XL |
1255 | /// Print out the type for use in value namespace. |
1256 | fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String { | |
1b1a35ee | 1257 | match ty.kind() { |
e74abb32 XL |
1258 | ty::Adt(def, substs) => format!("{}", ty::Instance::new(def.did, substs)), |
1259 | _ => self.ty_to_string(ty), | |
1260 | } | |
1261 | } | |
1262 | ||
1b1a35ee XL |
1263 | fn suggest_await_before_method( |
1264 | &self, | |
1265 | err: &mut DiagnosticBuilder<'_>, | |
1266 | item_name: Ident, | |
1267 | ty: Ty<'tcx>, | |
1268 | call: &hir::Expr<'_>, | |
1269 | span: Span, | |
1270 | ) { | |
29967ef6 | 1271 | let output_ty = match self.infcx.get_impl_future_output_ty(ty) { |
fc512014 | 1272 | Some(output_ty) => self.resolve_vars_if_possible(output_ty), |
29967ef6 XL |
1273 | _ => return, |
1274 | }; | |
1275 | let method_exists = self.method_exists(item_name, output_ty, call.hir_id, true); | |
1276 | debug!("suggest_await_before_method: is_method_exist={}", method_exists); | |
1277 | if method_exists { | |
1278 | err.span_suggestion_verbose( | |
1279 | span.shrink_to_lo(), | |
1280 | "consider `await`ing on the `Future` and calling the method on its `Output`", | |
1281 | "await.".to_string(), | |
1282 | Applicability::MaybeIncorrect, | |
1283 | ); | |
1b1a35ee XL |
1284 | } |
1285 | } | |
1286 | ||
dfeec247 XL |
1287 | fn suggest_use_candidates( |
1288 | &self, | |
1289 | err: &mut DiagnosticBuilder<'_>, | |
1290 | mut msg: String, | |
1291 | candidates: Vec<DefId>, | |
1292 | ) { | |
74b04a01 | 1293 | let module_did = self.tcx.parent_module(self.body_id); |
c295e0f8 | 1294 | let (span, found_use) = find_use_placement(self.tcx, module_did); |
ff7c6d11 XL |
1295 | if let Some(span) = span { |
1296 | let path_strings = candidates.iter().map(|did| { | |
0731742a | 1297 | // Produce an additional newline to separate the new use statement |
ff7c6d11 | 1298 | // from the directly following item. |
dfeec247 | 1299 | let additional_newline = if found_use { "" } else { "\n" }; |
0bf4aa26 XL |
1300 | format!( |
1301 | "use {};\n{}", | |
532ac7d7 | 1302 | with_crate_prefix(|| self.tcx.def_path_str(*did)), |
0bf4aa26 XL |
1303 | additional_newline |
1304 | ) | |
a1dfa0c6 | 1305 | }); |
ff7c6d11 | 1306 | |
9fa01778 | 1307 | err.span_suggestions(span, &msg, path_strings, Applicability::MaybeIncorrect); |
ff7c6d11 XL |
1308 | } else { |
1309 | let limit = if candidates.len() == 5 { 5 } else { 4 }; | |
1310 | for (i, trait_did) in candidates.iter().take(limit).enumerate() { | |
94b46f34 | 1311 | if candidates.len() > 1 { |
dfeec247 XL |
1312 | msg.push_str(&format!( |
1313 | "\ncandidate #{}: `use {};`", | |
1314 | i + 1, | |
1315 | with_crate_prefix(|| self.tcx.def_path_str(*trait_did)) | |
1316 | )); | |
94b46f34 | 1317 | } else { |
dfeec247 XL |
1318 | msg.push_str(&format!( |
1319 | "\n`use {};`", | |
1320 | with_crate_prefix(|| self.tcx.def_path_str(*trait_did)) | |
1321 | )); | |
94b46f34 | 1322 | } |
ff7c6d11 XL |
1323 | } |
1324 | if candidates.len() > limit { | |
1325 | msg.push_str(&format!("\nand {} others", candidates.len() - limit)); | |
1326 | } | |
1327 | err.note(&msg[..]); | |
3b2f2976 | 1328 | } |
3b2f2976 XL |
1329 | } |
1330 | ||
e74abb32 XL |
1331 | fn suggest_valid_traits( |
1332 | &self, | |
1333 | err: &mut DiagnosticBuilder<'_>, | |
1334 | valid_out_of_scope_traits: Vec<DefId>, | |
1335 | ) -> bool { | |
3b2f2976 XL |
1336 | if !valid_out_of_scope_traits.is_empty() { |
1337 | let mut candidates = valid_out_of_scope_traits; | |
1338 | candidates.sort(); | |
1339 | candidates.dedup(); | |
3c0e092e XL |
1340 | |
1341 | // `TryFrom` and `FromIterator` have no methods | |
1342 | let edition_fix = candidates | |
1343 | .iter() | |
1344 | .find(|did| self.tcx.is_diagnostic_item(sym::TryInto, **did)) | |
1345 | .copied(); | |
1346 | ||
3b2f2976 | 1347 | err.help("items from traits can only be used if the trait is in scope"); |
e74abb32 XL |
1348 | let msg = format!( |
1349 | "the following {traits_are} implemented but not in scope; \ | |
1350 | perhaps add a `use` for {one_of_them}:", | |
dfeec247 XL |
1351 | traits_are = if candidates.len() == 1 { "trait is" } else { "traits are" }, |
1352 | one_of_them = if candidates.len() == 1 { "it" } else { "one of them" }, | |
e74abb32 | 1353 | ); |
3b2f2976 XL |
1354 | |
1355 | self.suggest_use_candidates(err, msg, candidates); | |
3c0e092e XL |
1356 | if let Some(did) = edition_fix { |
1357 | err.note(&format!( | |
1358 | "'{}' is included in the prelude starting in Edition 2021", | |
1359 | with_crate_prefix(|| self.tcx.def_path_str(did)) | |
1360 | )); | |
1361 | } | |
1362 | ||
3b2f2976 XL |
1363 | true |
1364 | } else { | |
1365 | false | |
54a0048b | 1366 | } |
85aaf69f SL |
1367 | } |
1368 | ||
cdc7bbd5 | 1369 | fn suggest_traits_to_import( |
416331ca XL |
1370 | &self, |
1371 | err: &mut DiagnosticBuilder<'_>, | |
1372 | span: Span, | |
1373 | rcvr_ty: Ty<'tcx>, | |
f9f354fc | 1374 | item_name: Ident, |
cdc7bbd5 | 1375 | source: SelfSource<'tcx>, |
416331ca | 1376 | valid_out_of_scope_traits: Vec<DefId>, |
3c0e092e XL |
1377 | unsatisfied_predicates: &[( |
1378 | ty::Predicate<'tcx>, | |
1379 | Option<ty::Predicate<'tcx>>, | |
1380 | Option<ObligationCause<'tcx>>, | |
1381 | )], | |
cdc7bbd5 | 1382 | unsatisfied_bounds: bool, |
416331ca | 1383 | ) { |
cdc7bbd5 XL |
1384 | let mut alt_rcvr_sugg = false; |
1385 | if let (SelfSource::MethodCall(rcvr), false) = (source, unsatisfied_bounds) { | |
1386 | debug!(?span, ?item_name, ?rcvr_ty, ?rcvr); | |
1387 | let skippable = [ | |
1388 | self.tcx.lang_items().clone_trait(), | |
1389 | self.tcx.lang_items().deref_trait(), | |
1390 | self.tcx.lang_items().deref_mut_trait(), | |
1391 | self.tcx.lang_items().drop_trait(), | |
3c0e092e | 1392 | self.tcx.get_diagnostic_item(sym::AsRef), |
cdc7bbd5 XL |
1393 | ]; |
1394 | // Try alternative arbitrary self types that could fulfill this call. | |
1395 | // FIXME: probe for all types that *could* be arbitrary self-types, not | |
1396 | // just this list. | |
1397 | for (rcvr_ty, post) in &[ | |
1398 | (rcvr_ty, ""), | |
1399 | (self.tcx.mk_mut_ref(&ty::ReErased, rcvr_ty), "&mut "), | |
1400 | (self.tcx.mk_imm_ref(&ty::ReErased, rcvr_ty), "&"), | |
1401 | ] { | |
1402 | if let Ok(pick) = self.lookup_probe( | |
1403 | span, | |
1404 | item_name, | |
1405 | rcvr_ty, | |
1406 | rcvr, | |
1407 | crate::check::method::probe::ProbeScope::AllTraits, | |
1408 | ) { | |
1409 | // If the method is defined for the receiver we have, it likely wasn't `use`d. | |
1410 | // We point at the method, but we just skip the rest of the check for arbitrary | |
1411 | // self types and rely on the suggestion to `use` the trait from | |
1412 | // `suggest_valid_traits`. | |
1413 | let did = Some(pick.item.container.id()); | |
1414 | let skip = skippable.contains(&did); | |
1415 | if pick.autoderefs == 0 && !skip { | |
1416 | err.span_label( | |
1417 | pick.item.ident.span, | |
1418 | &format!("the method is available for `{}` here", rcvr_ty), | |
1419 | ); | |
1420 | } | |
1421 | break; | |
1422 | } | |
1423 | for (rcvr_ty, pre) in &[ | |
1424 | (self.tcx.mk_lang_item(rcvr_ty, LangItem::OwnedBox), "Box::new"), | |
1425 | (self.tcx.mk_lang_item(rcvr_ty, LangItem::Pin), "Pin::new"), | |
1426 | (self.tcx.mk_diagnostic_item(rcvr_ty, sym::Arc), "Arc::new"), | |
1427 | (self.tcx.mk_diagnostic_item(rcvr_ty, sym::Rc), "Rc::new"), | |
1428 | ] { | |
1429 | if let Some(new_rcvr_t) = *rcvr_ty { | |
1430 | if let Ok(pick) = self.lookup_probe( | |
1431 | span, | |
1432 | item_name, | |
1433 | new_rcvr_t, | |
1434 | rcvr, | |
1435 | crate::check::method::probe::ProbeScope::AllTraits, | |
1436 | ) { | |
1437 | debug!("try_alt_rcvr: pick candidate {:?}", pick); | |
1438 | let did = Some(pick.item.container.id()); | |
1439 | // We don't want to suggest a container type when the missing | |
1440 | // method is `.clone()` or `.deref()` otherwise we'd suggest | |
1441 | // `Arc::new(foo).clone()`, which is far from what the user wants. | |
3c0e092e XL |
1442 | // Explicitly ignore the `Pin::as_ref()` method as `Pin` does not |
1443 | // implement the `AsRef` trait. | |
1444 | let skip = skippable.contains(&did) | |
1445 | || (("Pin::new" == *pre) | |
1446 | && (Symbol::intern("as_ref") == item_name.name)); | |
cdc7bbd5 XL |
1447 | // Make sure the method is defined for the *actual* receiver: we don't |
1448 | // want to treat `Box<Self>` as a receiver if it only works because of | |
1449 | // an autoderef to `&self` | |
1450 | if pick.autoderefs == 0 && !skip { | |
1451 | err.span_label( | |
1452 | pick.item.ident.span, | |
1453 | &format!("the method is available for `{}` here", new_rcvr_t), | |
1454 | ); | |
1455 | err.multipart_suggestion( | |
1456 | "consider wrapping the receiver expression with the \ | |
1457 | appropriate type", | |
1458 | vec![ | |
1459 | (rcvr.span.shrink_to_lo(), format!("{}({}", pre, post)), | |
1460 | (rcvr.span.shrink_to_hi(), ")".to_string()), | |
1461 | ], | |
1462 | Applicability::MaybeIncorrect, | |
1463 | ); | |
1464 | // We don't care about the other suggestions. | |
1465 | alt_rcvr_sugg = true; | |
1466 | } | |
1467 | } | |
1468 | } | |
1469 | } | |
1470 | } | |
1471 | } | |
3b2f2976 | 1472 | if self.suggest_valid_traits(err, valid_out_of_scope_traits) { |
c30ab7b3 | 1473 | return; |
85aaf69f | 1474 | } |
85aaf69f | 1475 | |
0731742a | 1476 | let type_is_local = self.type_derefs_to_local(span, rcvr_ty, source); |
a7813a04 | 1477 | |
74b04a01 | 1478 | let mut arbitrary_rcvr = vec![]; |
0731742a | 1479 | // There are no traits implemented, so lets suggest some traits to |
a7813a04 XL |
1480 | // implement, by finding ones that have the item name, and are |
1481 | // legal to implement. | |
8bb4bdeb | 1482 | let mut candidates = all_traits(self.tcx) |
83c7162d | 1483 | .into_iter() |
3dfed10e XL |
1484 | // Don't issue suggestions for unstable traits since they're |
1485 | // unlikely to be implementable anyway | |
1486 | .filter(|info| match self.tcx.lookup_stability(info.def_id) { | |
1487 | Some(attr) => attr.level.is_stable(), | |
1488 | None => true, | |
1489 | }) | |
a7813a04 | 1490 | .filter(|info| { |
0731742a | 1491 | // We approximate the coherence rules to only suggest |
a7813a04 | 1492 | // traits that are legal to implement by requiring that |
0731742a | 1493 | // either the type or trait is local. Multi-dispatch means |
a7813a04 XL |
1494 | // this isn't perfect (that is, there are cases when |
1495 | // implementing a trait would be legal but is rejected | |
1496 | // here). | |
3c0e092e | 1497 | unsatisfied_predicates.iter().all(|(p, _, _)| { |
5869c6ff | 1498 | match p.kind().skip_binder() { |
3dfed10e XL |
1499 | // Hide traits if they are present in predicates as they can be fixed without |
1500 | // having to implement them. | |
94222f64 | 1501 | ty::PredicateKind::Trait(t) => t.def_id() == info.def_id, |
5869c6ff | 1502 | ty::PredicateKind::Projection(p) => { |
3dfed10e XL |
1503 | p.projection_ty.item_def_id == info.def_id |
1504 | } | |
1505 | _ => false, | |
1506 | } | |
74b04a01 | 1507 | }) && (type_is_local || info.def_id.is_local()) |
dfeec247 | 1508 | && self |
74b04a01 | 1509 | .associated_item(info.def_id, item_name, Namespace::ValueNS) |
2c00a5a8 | 1510 | .filter(|item| { |
ba9703b0 | 1511 | if let ty::AssocKind::Fn = item.kind { |
f9f354fc XL |
1512 | let id = item |
1513 | .def_id | |
1514 | .as_local() | |
3dfed10e | 1515 | .map(|def_id| self.tcx.hir().local_def_id_to_hir_id(def_id)); |
74b04a01 | 1516 | if let Some(hir::Node::TraitItem(hir::TraitItem { |
ba9703b0 | 1517 | kind: hir::TraitItemKind::Fn(fn_sig, method), |
74b04a01 XL |
1518 | .. |
1519 | })) = id.map(|id| self.tcx.hir().get(id)) | |
1520 | { | |
1521 | let self_first_arg = match method { | |
ba9703b0 | 1522 | hir::TraitFn::Required([ident, ..]) => { |
74b04a01 XL |
1523 | ident.name == kw::SelfLower |
1524 | } | |
ba9703b0 | 1525 | hir::TraitFn::Provided(body_id) => { |
f9f354fc XL |
1526 | self.tcx.hir().body(*body_id).params.first().map_or( |
1527 | false, | |
1528 | |param| { | |
1529 | matches!( | |
1530 | param.pat.kind, | |
1531 | hir::PatKind::Binding(_, _, ident, _) | |
1532 | if ident.name == kw::SelfLower | |
1533 | ) | |
1534 | }, | |
1535 | ) | |
74b04a01 XL |
1536 | } |
1537 | _ => false, | |
1538 | }; | |
1539 | ||
1540 | if !fn_sig.decl.implicit_self.has_implicit_self() | |
1541 | && self_first_arg | |
1542 | { | |
1543 | if let Some(ty) = fn_sig.decl.inputs.get(0) { | |
1544 | arbitrary_rcvr.push(ty.span); | |
1545 | } | |
1546 | return false; | |
1547 | } | |
1548 | } | |
1549 | } | |
2c00a5a8 | 1550 | // We only want to suggest public or local traits (#45781). |
3c0e092e | 1551 | item.vis.is_public() || info.def_id.is_local() |
2c00a5a8 XL |
1552 | }) |
1553 | .is_some() | |
a7813a04 XL |
1554 | }) |
1555 | .collect::<Vec<_>>(); | |
74b04a01 XL |
1556 | for span in &arbitrary_rcvr { |
1557 | err.span_label( | |
1558 | *span, | |
1559 | "the method might not be found because of this arbitrary self type", | |
1560 | ); | |
1561 | } | |
cdc7bbd5 XL |
1562 | if alt_rcvr_sugg { |
1563 | return; | |
1564 | } | |
a7813a04 XL |
1565 | |
1566 | if !candidates.is_empty() { | |
0731742a | 1567 | // Sort from most relevant to least relevant. |
a7813a04 XL |
1568 | candidates.sort_by(|a, b| a.cmp(b).reverse()); |
1569 | candidates.dedup(); | |
1570 | ||
1b1a35ee | 1571 | let param_type = match rcvr_ty.kind() { |
416331ca | 1572 | ty::Param(param) => Some(param), |
1b1a35ee | 1573 | ty::Ref(_, ty, _) => match ty.kind() { |
416331ca XL |
1574 | ty::Param(param) => Some(param), |
1575 | _ => None, | |
dfeec247 | 1576 | }, |
416331ca XL |
1577 | _ => None, |
1578 | }; | |
1579 | err.help(if param_type.is_some() { | |
1580 | "items from traits can only be used if the type parameter is bounded by the trait" | |
1581 | } else { | |
1582 | "items from traits can only be used if the trait is implemented and in scope" | |
1583 | }); | |
fc512014 | 1584 | let candidates_len = candidates.len(); |
dfeec247 XL |
1585 | let message = |action| { |
1586 | format!( | |
1587 | "the following {traits_define} an item `{name}`, perhaps you need to {action} \ | |
74b04a01 | 1588 | {one_of_them}:", |
dfeec247 | 1589 | traits_define = |
fc512014 | 1590 | if candidates_len == 1 { "trait defines" } else { "traits define" }, |
dfeec247 | 1591 | action = action, |
fc512014 | 1592 | one_of_them = if candidates_len == 1 { "it" } else { "one of them" }, |
dfeec247 XL |
1593 | name = item_name, |
1594 | ) | |
1595 | }; | |
416331ca | 1596 | // Obtain the span for `param` and use it for a structured suggestion. |
c295e0f8 | 1597 | if let (Some(param), Some(table)) = (param_type, self.in_progress_typeck_results) { |
ba9703b0 | 1598 | let table_owner = table.borrow().hir_owner; |
f035d41b XL |
1599 | let generics = self.tcx.generics_of(table_owner.to_def_id()); |
1600 | let type_param = generics.type_param(param, self.tcx); | |
1601 | let hir = &self.tcx.hir(); | |
1602 | if let Some(def_id) = type_param.def_id.as_local() { | |
3dfed10e | 1603 | let id = hir.local_def_id_to_hir_id(def_id); |
f035d41b XL |
1604 | // Get the `hir::Param` to verify whether it already has any bounds. |
1605 | // We do this to avoid suggesting code that ends up as `T: FooBar`, | |
1606 | // instead we suggest `T: Foo + Bar` in that case. | |
1607 | match hir.get(id) { | |
c295e0f8 | 1608 | Node::GenericParam(param) => { |
f035d41b XL |
1609 | let mut impl_trait = false; |
1610 | let has_bounds = | |
3c0e092e | 1611 | if let hir::GenericParamKind::Type { synthetic: true, .. } = |
f035d41b | 1612 | ¶m.kind |
dfeec247 | 1613 | { |
e1599b0c XL |
1614 | // We've found `fn foo(x: impl Trait)` instead of |
1615 | // `fn foo<T>(x: T)`. We want to suggest the correct | |
1616 | // `fn foo(x: impl Trait + TraitBound)` instead of | |
1617 | // `fn foo<T: TraitBound>(x: T)`. (#63706) | |
1618 | impl_trait = true; | |
e74abb32 XL |
1619 | param.bounds.get(1) |
1620 | } else { | |
1621 | param.bounds.get(0) | |
1622 | }; | |
f035d41b XL |
1623 | let sp = hir.span(id); |
1624 | let sp = if let Some(first_bound) = has_bounds { | |
1625 | // `sp` only covers `T`, change it so that it covers | |
1626 | // `T:` when appropriate | |
1627 | sp.until(first_bound.span()) | |
1628 | } else { | |
1629 | sp | |
1630 | }; | |
1631 | let trait_def_ids: FxHashSet<DefId> = param | |
1632 | .bounds | |
1633 | .iter() | |
6a06907d | 1634 | .filter_map(|bound| bound.trait_ref()?.trait_def_id()) |
f035d41b XL |
1635 | .collect(); |
1636 | if !candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) { | |
e74abb32 XL |
1637 | err.span_suggestions( |
1638 | sp, | |
f035d41b XL |
1639 | &message(format!( |
1640 | "restrict type parameter `{}` with", | |
1641 | param.name.ident(), | |
1642 | )), | |
dfeec247 | 1643 | candidates.iter().map(|t| { |
f035d41b XL |
1644 | format!( |
1645 | "{}{} {}{}", | |
1646 | param.name.ident(), | |
1647 | if impl_trait { " +" } else { ":" }, | |
1648 | self.tcx.def_path_str(t.def_id), | |
1649 | if has_bounds.is_some() { " + " } else { "" }, | |
1650 | ) | |
dfeec247 | 1651 | }), |
e74abb32 XL |
1652 | Applicability::MaybeIncorrect, |
1653 | ); | |
e1599b0c | 1654 | } |
fc512014 | 1655 | return; |
f035d41b XL |
1656 | } |
1657 | Node::Item(hir::Item { | |
1658 | kind: hir::ItemKind::Trait(.., bounds, _), | |
1659 | ident, | |
1660 | .. | |
1661 | }) => { | |
1662 | let (sp, sep, article) = if bounds.is_empty() { | |
1663 | (ident.span.shrink_to_hi(), ":", "a") | |
1664 | } else { | |
1665 | (bounds.last().unwrap().span().shrink_to_hi(), " +", "another") | |
1666 | }; | |
1667 | err.span_suggestions( | |
1668 | sp, | |
1669 | &message(format!("add {} supertrait for", article)), | |
1670 | candidates.iter().map(|t| { | |
1671 | format!("{} {}", sep, self.tcx.def_path_str(t.def_id),) | |
1672 | }), | |
1673 | Applicability::MaybeIncorrect, | |
1674 | ); | |
fc512014 | 1675 | return; |
416331ca | 1676 | } |
f035d41b | 1677 | _ => {} |
416331ca | 1678 | } |
f035d41b | 1679 | } |
416331ca XL |
1680 | } |
1681 | ||
fc512014 XL |
1682 | let (potential_candidates, explicitly_negative) = if param_type.is_some() { |
1683 | // FIXME: Even though negative bounds are not implemented, we could maybe handle | |
1684 | // cases where a positive bound implies a negative impl. | |
1685 | (candidates, Vec::new()) | |
1686 | } else if let Some(simp_rcvr_ty) = simplify_type(self.tcx, rcvr_ty, true) { | |
1687 | let mut potential_candidates = Vec::new(); | |
1688 | let mut explicitly_negative = Vec::new(); | |
1689 | for candidate in candidates { | |
1690 | // Check if there's a negative impl of `candidate` for `rcvr_ty` | |
1691 | if self | |
1692 | .tcx | |
1693 | .all_impls(candidate.def_id) | |
1694 | .filter(|imp_did| { | |
1695 | self.tcx.impl_polarity(*imp_did) == ty::ImplPolarity::Negative | |
1696 | }) | |
1697 | .any(|imp_did| { | |
1698 | let imp = self.tcx.impl_trait_ref(imp_did).unwrap(); | |
1699 | let imp_simp = simplify_type(self.tcx, imp.self_ty(), true); | |
5869c6ff | 1700 | imp_simp.map_or(false, |s| s == simp_rcvr_ty) |
fc512014 XL |
1701 | }) |
1702 | { | |
1703 | explicitly_negative.push(candidate); | |
1704 | } else { | |
1705 | potential_candidates.push(candidate); | |
74b04a01 XL |
1706 | } |
1707 | } | |
fc512014 XL |
1708 | (potential_candidates, explicitly_negative) |
1709 | } else { | |
1710 | // We don't know enough about `recv_ty` to make proper suggestions. | |
1711 | (candidates, Vec::new()) | |
1712 | }; | |
1713 | ||
1714 | let action = if let Some(param) = param_type { | |
1715 | format!("restrict type parameter `{}` with", param) | |
1716 | } else { | |
1717 | // FIXME: it might only need to be imported into scope, not implemented. | |
1718 | "implement".to_string() | |
1719 | }; | |
1720 | match &potential_candidates[..] { | |
1721 | [] => {} | |
1722 | [trait_info] if trait_info.def_id.is_local() => { | |
1723 | let span = self.tcx.hir().span_if_local(trait_info.def_id).unwrap(); | |
1724 | err.span_note( | |
1725 | self.tcx.sess.source_map().guess_head_span(span), | |
1726 | &format!( | |
1727 | "`{}` defines an item `{}`, perhaps you need to {} it", | |
1728 | self.tcx.def_path_str(trait_info.def_id), | |
1729 | item_name, | |
1730 | action | |
1731 | ), | |
1732 | ); | |
1733 | } | |
1734 | trait_infos => { | |
74b04a01 | 1735 | let mut msg = message(action); |
fc512014 | 1736 | for (i, trait_info) in trait_infos.iter().enumerate() { |
74b04a01 XL |
1737 | msg.push_str(&format!( |
1738 | "\ncandidate #{}: `{}`", | |
1739 | i + 1, | |
1740 | self.tcx.def_path_str(trait_info.def_id), | |
1741 | )); | |
1742 | } | |
fc512014 XL |
1743 | err.note(&msg); |
1744 | } | |
1745 | } | |
1746 | match &explicitly_negative[..] { | |
1747 | [] => {} | |
1748 | [trait_info] => { | |
1749 | let msg = format!( | |
1750 | "the trait `{}` defines an item `{}`, but is explicitely unimplemented", | |
1751 | self.tcx.def_path_str(trait_info.def_id), | |
1752 | item_name | |
1753 | ); | |
1754 | err.note(&msg); | |
1755 | } | |
1756 | trait_infos => { | |
1757 | let mut msg = format!( | |
1758 | "the following traits define an item `{}`, but are explicitely unimplemented:", | |
1759 | item_name | |
1760 | ); | |
1761 | for trait_info in trait_infos { | |
1762 | msg.push_str(&format!("\n{}", self.tcx.def_path_str(trait_info.def_id))); | |
1763 | } | |
1764 | err.note(&msg); | |
416331ca | 1765 | } |
a7813a04 | 1766 | } |
85aaf69f | 1767 | } |
85aaf69f SL |
1768 | } |
1769 | ||
a7813a04 XL |
1770 | /// Checks whether there is a local type somewhere in the chain of |
1771 | /// autoderefs of `rcvr_ty`. | |
cdc7bbd5 XL |
1772 | fn type_derefs_to_local( |
1773 | &self, | |
1774 | span: Span, | |
1775 | rcvr_ty: Ty<'tcx>, | |
1776 | source: SelfSource<'tcx>, | |
1777 | ) -> bool { | |
9fa01778 | 1778 | fn is_local(ty: Ty<'_>) -> bool { |
1b1a35ee | 1779 | match ty.kind() { |
b7449926 XL |
1780 | ty::Adt(def, _) => def.did.is_local(), |
1781 | ty::Foreign(did) => did.is_local(), | |
c295e0f8 | 1782 | ty::Dynamic(tr, ..) => tr.principal().map_or(false, |d| d.def_id().is_local()), |
b7449926 | 1783 | ty::Param(_) => true, |
a7813a04 | 1784 | |
0731742a XL |
1785 | // Everything else (primitive types, etc.) is effectively |
1786 | // non-local (there are "edge" cases, e.g., `(LocalType,)`, but | |
a7813a04 XL |
1787 | // the noise from these sort of types is usually just really |
1788 | // annoying, rather than any sort of help). | |
c30ab7b3 | 1789 | _ => false, |
a7813a04 | 1790 | } |
85aaf69f | 1791 | } |
85aaf69f | 1792 | |
a7813a04 XL |
1793 | // This occurs for UFCS desugaring of `T::method`, where there is no |
1794 | // receiver expression for the method call, and thus no autoderef. | |
0731742a | 1795 | if let SelfSource::QPath(_) = source { |
e74abb32 | 1796 | return is_local(self.resolve_vars_with_obligations(rcvr_ty)); |
c34b1796 | 1797 | } |
c34b1796 | 1798 | |
3157f602 | 1799 | self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty)) |
c34b1796 | 1800 | } |
85aaf69f SL |
1801 | } |
1802 | ||
cdc7bbd5 | 1803 | #[derive(Copy, Clone, Debug)] |
0731742a | 1804 | pub enum SelfSource<'a> { |
dfeec247 XL |
1805 | QPath(&'a hir::Ty<'a>), |
1806 | MethodCall(&'a hir::Expr<'a> /* rcvr */), | |
0731742a XL |
1807 | } |
1808 | ||
c34b1796 | 1809 | #[derive(Copy, Clone)] |
85aaf69f | 1810 | pub struct TraitInfo { |
e9174d1e | 1811 | pub def_id: DefId, |
85aaf69f SL |
1812 | } |
1813 | ||
85aaf69f SL |
1814 | impl PartialEq for TraitInfo { |
1815 | fn eq(&self, other: &TraitInfo) -> bool { | |
1816 | self.cmp(other) == Ordering::Equal | |
1817 | } | |
1818 | } | |
1819 | impl Eq for TraitInfo {} | |
1820 | impl PartialOrd for TraitInfo { | |
c30ab7b3 SL |
1821 | fn partial_cmp(&self, other: &TraitInfo) -> Option<Ordering> { |
1822 | Some(self.cmp(other)) | |
1823 | } | |
85aaf69f SL |
1824 | } |
1825 | impl Ord for TraitInfo { | |
1826 | fn cmp(&self, other: &TraitInfo) -> Ordering { | |
0731742a XL |
1827 | // Local crates are more important than remote ones (local: |
1828 | // `cnum == 0`), and otherwise we throw in the defid for totality. | |
85aaf69f | 1829 | |
b039eaaf SL |
1830 | let lhs = (other.def_id.krate, other.def_id); |
1831 | let rhs = (self.def_id.krate, self.def_id); | |
85aaf69f SL |
1832 | lhs.cmp(&rhs) |
1833 | } | |
1834 | } | |
1835 | ||
9fa01778 | 1836 | /// Retrieves all traits in this crate and any dependent crates. |
416331ca | 1837 | pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> { |
17df50a5 | 1838 | tcx.all_traits(()).iter().map(|&def_id| TraitInfo { def_id }).collect() |
83c7162d XL |
1839 | } |
1840 | ||
9fa01778 | 1841 | /// Computes all traits in this crate and any dependent crates. |
17df50a5 | 1842 | fn compute_all_traits(tcx: TyCtxt<'_>, (): ()) -> &[DefId] { |
0731742a | 1843 | use hir::itemlikevisit; |
85aaf69f | 1844 | |
0731742a | 1845 | let mut traits = vec![]; |
85aaf69f | 1846 | |
0731742a | 1847 | // Crate-local: |
476ff2be | 1848 | |
6a06907d | 1849 | struct Visitor<'a> { |
0731742a XL |
1850 | traits: &'a mut Vec<DefId>, |
1851 | } | |
32a655c1 | 1852 | |
6a06907d | 1853 | impl<'v, 'a> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a> { |
dfeec247 | 1854 | fn visit_item(&mut self, i: &'v hir::Item<'v>) { |
e74abb32 | 1855 | match i.kind { |
dfeec247 | 1856 | hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) => { |
6a06907d | 1857 | self.traits.push(i.def_id.to_def_id()); |
532ac7d7 | 1858 | } |
dfeec247 | 1859 | _ => (), |
476ff2be | 1860 | } |
85aaf69f | 1861 | } |
0731742a | 1862 | |
dfeec247 | 1863 | fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {} |
0731742a | 1864 | |
dfeec247 | 1865 | fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {} |
fc512014 XL |
1866 | |
1867 | fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {} | |
0731742a XL |
1868 | } |
1869 | ||
c295e0f8 | 1870 | tcx.hir().visit_all_item_likes(&mut Visitor { traits: &mut traits }); |
0731742a XL |
1871 | |
1872 | // Cross-crate: | |
1873 | ||
1874 | let mut external_mods = FxHashSet::default(); | |
dc9dc135 XL |
1875 | fn handle_external_res( |
1876 | tcx: TyCtxt<'_>, | |
1877 | traits: &mut Vec<DefId>, | |
1878 | external_mods: &mut FxHashSet<DefId>, | |
c295e0f8 | 1879 | res: Res<!>, |
dc9dc135 | 1880 | ) { |
48663c56 | 1881 | match res { |
ba9703b0 | 1882 | Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) => { |
0731742a XL |
1883 | traits.push(def_id); |
1884 | } | |
48663c56 | 1885 | Res::Def(DefKind::Mod, def_id) => { |
0731742a XL |
1886 | if !external_mods.insert(def_id) { |
1887 | return; | |
85aaf69f | 1888 | } |
0731742a | 1889 | for child in tcx.item_children(def_id).iter() { |
48663c56 | 1890 | handle_external_res(tcx, traits, external_mods, child.res) |
85aaf69f | 1891 | } |
85aaf69f | 1892 | } |
0731742a | 1893 | _ => {} |
85aaf69f | 1894 | } |
0731742a | 1895 | } |
136023e0 | 1896 | for &cnum in tcx.crates(()).iter() { |
dfeec247 | 1897 | let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX }; |
48663c56 | 1898 | handle_external_res(tcx, &mut traits, &mut external_mods, Res::Def(DefKind::Mod, def_id)); |
0731742a | 1899 | } |
85aaf69f | 1900 | |
17df50a5 | 1901 | tcx.arena.alloc_from_iter(traits) |
85aaf69f SL |
1902 | } |
1903 | ||
f035d41b | 1904 | pub fn provide(providers: &mut ty::query::Providers) { |
17df50a5 | 1905 | providers.all_traits = compute_all_traits; |
85aaf69f | 1906 | } |
ff7c6d11 | 1907 | |
c295e0f8 XL |
1908 | fn find_use_placement<'tcx>(tcx: TyCtxt<'tcx>, target_module: LocalDefId) -> (Option<Span>, bool) { |
1909 | let mut span = None; | |
1910 | let mut found_use = false; | |
1911 | let (module, _, _) = tcx.hir().get_module(target_module); | |
1912 | ||
1913 | // Find a `use` statement. | |
1914 | for &item_id in module.item_ids { | |
1915 | let item = tcx.hir().item(item_id); | |
1916 | match item.kind { | |
1917 | hir::ItemKind::Use(..) => { | |
1918 | // Don't suggest placing a `use` before the prelude | |
1919 | // import or other generated ones. | |
1920 | if !item.span.from_expansion() { | |
1921 | span = Some(item.span.shrink_to_lo()); | |
1922 | found_use = true; | |
1923 | break; | |
dfeec247 | 1924 | } |
c295e0f8 XL |
1925 | } |
1926 | // Don't place `use` before `extern crate`... | |
1927 | hir::ItemKind::ExternCrate(_) => {} | |
1928 | // ...but do place them before the first other item. | |
1929 | _ => { | |
1930 | if span.map_or(true, |span| item.span < span) { | |
1931 | if !item.span.from_expansion() { | |
1932 | span = Some(item.span.shrink_to_lo()); | |
1933 | // Don't insert between attributes and an item. | |
1934 | let attrs = tcx.hir().attrs(item.hir_id()); | |
1935 | // Find the first attribute on the item. | |
1936 | // FIXME: This is broken for active attributes. | |
1937 | for attr in attrs { | |
1938 | if !attr.span.is_dummy() && span.map_or(true, |span| attr.span < span) { | |
1939 | span = Some(attr.span.shrink_to_lo()); | |
ff7c6d11 XL |
1940 | } |
1941 | } | |
1942 | } | |
dfeec247 | 1943 | } |
ff7c6d11 XL |
1944 | } |
1945 | } | |
1946 | } | |
0731742a | 1947 | |
c295e0f8 | 1948 | (span, found_use) |
ff7c6d11 | 1949 | } |
dfeec247 XL |
1950 | |
1951 | fn print_disambiguation_help( | |
f9f354fc | 1952 | item_name: Ident, |
dfeec247 XL |
1953 | args: Option<&'tcx [hir::Expr<'tcx>]>, |
1954 | err: &mut DiagnosticBuilder<'_>, | |
1955 | trait_name: String, | |
1956 | rcvr_ty: Ty<'_>, | |
1957 | kind: ty::AssocKind, | |
ba9703b0 | 1958 | def_id: DefId, |
dfeec247 XL |
1959 | span: Span, |
1960 | candidate: Option<usize>, | |
1961 | source_map: &source_map::SourceMap, | |
c295e0f8 | 1962 | fn_has_self_parameter: bool, |
dfeec247 XL |
1963 | ) { |
1964 | let mut applicability = Applicability::MachineApplicable; | |
94222f64 XL |
1965 | let (span, sugg) = if let (ty::AssocKind::Fn, Some(args)) = (kind, args) { |
1966 | let args = format!( | |
dfeec247 XL |
1967 | "({}{})", |
1968 | if rcvr_ty.is_region_ptr() { | |
1969 | if rcvr_ty.is_mutable_ptr() { "&mut " } else { "&" } | |
1970 | } else { | |
1971 | "" | |
1972 | }, | |
1973 | args.iter() | |
1974 | .map(|arg| source_map.span_to_snippet(arg.span).unwrap_or_else(|_| { | |
1975 | applicability = Applicability::HasPlaceholders; | |
1976 | "_".to_owned() | |
1977 | })) | |
1978 | .collect::<Vec<_>>() | |
1979 | .join(", "), | |
94222f64 | 1980 | ); |
c295e0f8 XL |
1981 | let trait_name = if !fn_has_self_parameter { |
1982 | format!("<{} as {}>", rcvr_ty, trait_name) | |
1983 | } else { | |
1984 | trait_name | |
1985 | }; | |
94222f64 | 1986 | (span, format!("{}::{}{}", trait_name, item_name, args)) |
dfeec247 | 1987 | } else { |
c295e0f8 | 1988 | (span.with_hi(item_name.span.lo()), format!("<{} as {}>::", rcvr_ty, trait_name)) |
dfeec247 | 1989 | }; |
94222f64 | 1990 | err.span_suggestion_verbose( |
dfeec247 XL |
1991 | span, |
1992 | &format!( | |
1993 | "disambiguate the {} for {}", | |
ba9703b0 | 1994 | kind.as_def_kind().descr(def_id), |
dfeec247 XL |
1995 | if let Some(candidate) = candidate { |
1996 | format!("candidate #{}", candidate) | |
1997 | } else { | |
1998 | "the candidate".to_string() | |
1999 | }, | |
2000 | ), | |
2001 | sugg, | |
2002 | applicability, | |
2003 | ); | |
2004 | } |