]>
Commit | Line | Data |
---|---|---|
ba9703b0 XL |
1 | pub mod on_unimplemented; |
2 | pub mod suggestions; | |
3 | ||
4 | use super::{ | |
cdc7bbd5 XL |
5 | EvaluationResult, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, |
6 | Obligation, ObligationCause, ObligationCauseCode, OnUnimplementedDirective, | |
7 | OnUnimplementedNote, OutputTypeParameterMismatch, Overflow, PredicateObligation, | |
8 | SelectionContext, SelectionError, TraitNotObjectSafe, | |
ba9703b0 XL |
9 | }; |
10 | ||
11 | use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode}; | |
12 | use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; | |
13 | use crate::infer::{self, InferCtxt, TyCtxtInferExt}; | |
14 | use rustc_data_structures::fx::FxHashMap; | |
15 | use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorReported}; | |
16 | use rustc_hir as hir; | |
17df50a5 | 17 | use rustc_hir::def_id::DefId; |
f035d41b | 18 | use rustc_hir::intravisit::Visitor; |
94222f64 XL |
19 | use rustc_hir::GenericParam; |
20 | use rustc_hir::Item; | |
f9f354fc | 21 | use rustc_hir::Node; |
c295e0f8 | 22 | use rustc_middle::thir::abstract_const::NotConstEvaluatable; |
ba9703b0 | 23 | use rustc_middle::ty::error::ExpectedFound; |
ba9703b0 | 24 | use rustc_middle::ty::fold::TypeFolder; |
ba9703b0 | 25 | use rustc_middle::ty::{ |
5099ac24 | 26 | self, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, |
ba9703b0 XL |
27 | }; |
28 | use rustc_session::DiagnosticMessageId; | |
3dfed10e | 29 | use rustc_span::symbol::{kw, sym}; |
f035d41b | 30 | use rustc_span::{ExpnKind, MultiSpan, Span, DUMMY_SP}; |
ba9703b0 | 31 | use std::fmt; |
cdc7bbd5 | 32 | use std::iter; |
ba9703b0 XL |
33 | |
34 | use crate::traits::query::evaluate_obligation::InferCtxtExt as _; | |
35 | use crate::traits::query::normalize::AtExt as _; | |
3c0e092e | 36 | use crate::traits::specialize::to_pretty_impl_header; |
ba9703b0 XL |
37 | use on_unimplemented::InferCtxtExt as _; |
38 | use suggestions::InferCtxtExt as _; | |
39 | ||
40 | pub use rustc_infer::traits::error_reporting::*; | |
41 | ||
5099ac24 FG |
42 | // When outputting impl candidates, prefer showing those that are more similar. |
43 | // | |
44 | // We also compare candidates after skipping lifetimes, which has a lower | |
45 | // priority than exact matches. | |
46 | #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] | |
47 | pub enum CandidateSimilarity { | |
48 | Exact { ignoring_lifetimes: bool }, | |
49 | Fuzzy { ignoring_lifetimes: bool }, | |
50 | } | |
51 | ||
52 | #[derive(Debug, Clone, Copy)] | |
53 | pub struct ImplCandidate<'tcx> { | |
54 | pub trait_ref: ty::TraitRef<'tcx>, | |
55 | pub similarity: CandidateSimilarity, | |
56 | } | |
57 | ||
ba9703b0 XL |
58 | pub trait InferCtxtExt<'tcx> { |
59 | fn report_fulfillment_errors( | |
60 | &self, | |
61 | errors: &[FulfillmentError<'tcx>], | |
62 | body_id: Option<hir::BodyId>, | |
63 | fallback_has_occurred: bool, | |
64 | ); | |
65 | ||
66 | fn report_overflow_error<T>( | |
67 | &self, | |
68 | obligation: &Obligation<'tcx, T>, | |
69 | suggest_increasing_limit: bool, | |
70 | ) -> ! | |
71 | where | |
72 | T: fmt::Display + TypeFoldable<'tcx>; | |
73 | ||
74 | fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> !; | |
75 | ||
136023e0 XL |
76 | /// The `root_obligation` parameter should be the `root_obligation` field |
77 | /// from a `FulfillmentError`. If no `FulfillmentError` is available, | |
78 | /// then it should be the same as `obligation`. | |
ba9703b0 XL |
79 | fn report_selection_error( |
80 | &self, | |
136023e0 XL |
81 | obligation: PredicateObligation<'tcx>, |
82 | root_obligation: &PredicateObligation<'tcx>, | |
ba9703b0 XL |
83 | error: &SelectionError<'tcx>, |
84 | fallback_has_occurred: bool, | |
ba9703b0 XL |
85 | ); |
86 | ||
87 | /// Given some node representing a fn-like thing in the HIR map, | |
88 | /// returns a span and `ArgKind` information that describes the | |
89 | /// arguments it expects. This can be supplied to | |
90 | /// `report_arg_count_mismatch`. | |
91 | fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec<ArgKind>)>; | |
92 | ||
93 | /// Reports an error when the number of arguments needed by a | |
94 | /// trait match doesn't match the number that the expression | |
95 | /// provides. | |
96 | fn report_arg_count_mismatch( | |
97 | &self, | |
98 | span: Span, | |
99 | found_span: Option<Span>, | |
100 | expected_args: Vec<ArgKind>, | |
101 | found_args: Vec<ArgKind>, | |
102 | is_closure: bool, | |
103 | ) -> DiagnosticBuilder<'tcx>; | |
104 | } | |
105 | ||
106 | impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { | |
107 | fn report_fulfillment_errors( | |
108 | &self, | |
109 | errors: &[FulfillmentError<'tcx>], | |
110 | body_id: Option<hir::BodyId>, | |
111 | fallback_has_occurred: bool, | |
112 | ) { | |
113 | #[derive(Debug)] | |
114 | struct ErrorDescriptor<'tcx> { | |
115 | predicate: ty::Predicate<'tcx>, | |
116 | index: Option<usize>, // None if this is an old error | |
117 | } | |
118 | ||
119 | let mut error_map: FxHashMap<_, Vec<_>> = self | |
120 | .reported_trait_errors | |
121 | .borrow() | |
122 | .iter() | |
123 | .map(|(&span, predicates)| { | |
124 | ( | |
125 | span, | |
126 | predicates | |
127 | .iter() | |
128 | .map(|&predicate| ErrorDescriptor { predicate, index: None }) | |
129 | .collect(), | |
130 | ) | |
131 | }) | |
132 | .collect(); | |
133 | ||
134 | for (index, error) in errors.iter().enumerate() { | |
135 | // We want to ignore desugarings here: spans are equivalent even | |
136 | // if one is the result of a desugaring and the other is not. | |
137 | let mut span = error.obligation.cause.span; | |
138 | let expn_data = span.ctxt().outer_expn_data(); | |
139 | if let ExpnKind::Desugaring(_) = expn_data.kind { | |
140 | span = expn_data.call_site; | |
141 | } | |
142 | ||
143 | error_map.entry(span).or_default().push(ErrorDescriptor { | |
144 | predicate: error.obligation.predicate, | |
145 | index: Some(index), | |
146 | }); | |
147 | ||
148 | self.reported_trait_errors | |
149 | .borrow_mut() | |
150 | .entry(span) | |
151 | .or_default() | |
152 | .push(error.obligation.predicate); | |
153 | } | |
154 | ||
155 | // We do this in 2 passes because we want to display errors in order, though | |
156 | // maybe it *is* better to sort errors by span or something. | |
157 | let mut is_suppressed = vec![false; errors.len()]; | |
158 | for (_, error_set) in error_map.iter() { | |
159 | // We want to suppress "duplicate" errors with the same span. | |
160 | for error in error_set { | |
161 | if let Some(index) = error.index { | |
162 | // Suppress errors that are either: | |
163 | // 1) strictly implied by another error. | |
164 | // 2) implied by an error with a smaller index. | |
165 | for error2 in error_set { | |
166 | if error2.index.map_or(false, |index2| is_suppressed[index2]) { | |
167 | // Avoid errors being suppressed by already-suppressed | |
168 | // errors, to prevent all errors from being suppressed | |
169 | // at once. | |
170 | continue; | |
171 | } | |
172 | ||
f9f354fc | 173 | if self.error_implies(error2.predicate, error.predicate) |
ba9703b0 | 174 | && !(error2.index >= error.index |
f9f354fc | 175 | && self.error_implies(error.predicate, error2.predicate)) |
ba9703b0 XL |
176 | { |
177 | info!("skipping {:?} (implied by {:?})", error, error2); | |
178 | is_suppressed[index] = true; | |
179 | break; | |
180 | } | |
181 | } | |
182 | } | |
183 | } | |
184 | } | |
185 | ||
cdc7bbd5 | 186 | for (error, suppressed) in iter::zip(errors, is_suppressed) { |
ba9703b0 XL |
187 | if !suppressed { |
188 | self.report_fulfillment_error(error, body_id, fallback_has_occurred); | |
189 | } | |
190 | } | |
191 | } | |
192 | ||
193 | /// Reports that an overflow has occurred and halts compilation. We | |
194 | /// halt compilation unconditionally because it is important that | |
195 | /// overflows never be masked -- they basically represent computations | |
196 | /// whose result could not be truly determined and thus we can't say | |
197 | /// if the program type checks or not -- and they are unusual | |
198 | /// occurrences in any case. | |
199 | fn report_overflow_error<T>( | |
200 | &self, | |
201 | obligation: &Obligation<'tcx, T>, | |
202 | suggest_increasing_limit: bool, | |
203 | ) -> ! | |
204 | where | |
205 | T: fmt::Display + TypeFoldable<'tcx>, | |
206 | { | |
fc512014 | 207 | let predicate = self.resolve_vars_if_possible(obligation.predicate.clone()); |
ba9703b0 XL |
208 | let mut err = struct_span_err!( |
209 | self.tcx.sess, | |
210 | obligation.cause.span, | |
211 | E0275, | |
212 | "overflow evaluating the requirement `{}`", | |
213 | predicate | |
214 | ); | |
215 | ||
216 | if suggest_increasing_limit { | |
217 | self.suggest_new_overflow_limit(&mut err); | |
218 | } | |
219 | ||
220 | self.note_obligation_cause_code( | |
221 | &mut err, | |
222 | &obligation.predicate, | |
5099ac24 | 223 | obligation.param_env, |
a2a8927a | 224 | obligation.cause.code(), |
ba9703b0 | 225 | &mut vec![], |
fc512014 | 226 | &mut Default::default(), |
ba9703b0 XL |
227 | ); |
228 | ||
229 | err.emit(); | |
230 | self.tcx.sess.abort_if_errors(); | |
231 | bug!(); | |
232 | } | |
233 | ||
234 | /// Reports that a cycle was detected which led to overflow and halts | |
235 | /// compilation. This is equivalent to `report_overflow_error` except | |
236 | /// that we can give a more helpful error message (and, in particular, | |
237 | /// we do not suggest increasing the overflow limit, which is not | |
238 | /// going to help). | |
239 | fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! { | |
fc512014 | 240 | let cycle = self.resolve_vars_if_possible(cycle.to_owned()); |
ba9703b0 XL |
241 | assert!(!cycle.is_empty()); |
242 | ||
243 | debug!("report_overflow_error_cycle: cycle={:?}", cycle); | |
244 | ||
94222f64 XL |
245 | // The 'deepest' obligation is most likely to have a useful |
246 | // cause 'backtrace' | |
247 | self.report_overflow_error(cycle.iter().max_by_key(|p| p.recursion_depth).unwrap(), false); | |
ba9703b0 XL |
248 | } |
249 | ||
250 | fn report_selection_error( | |
251 | &self, | |
136023e0 XL |
252 | mut obligation: PredicateObligation<'tcx>, |
253 | root_obligation: &PredicateObligation<'tcx>, | |
ba9703b0 XL |
254 | error: &SelectionError<'tcx>, |
255 | fallback_has_occurred: bool, | |
ba9703b0 XL |
256 | ) { |
257 | let tcx = self.tcx; | |
136023e0 | 258 | let mut span = obligation.cause.span; |
ba9703b0 XL |
259 | |
260 | let mut err = match *error { | |
3c0e092e XL |
261 | SelectionError::Ambiguous(ref impls) => { |
262 | let mut err = self.tcx.sess.struct_span_err( | |
263 | obligation.cause.span, | |
264 | &format!("multiple applicable `impl`s for `{}`", obligation.predicate), | |
265 | ); | |
266 | self.annotate_source_of_ambiguity(&mut err, impls, obligation.predicate); | |
267 | err.emit(); | |
268 | return; | |
269 | } | |
ba9703b0 | 270 | SelectionError::Unimplemented => { |
94222f64 XL |
271 | // If this obligation was generated as a result of well-formedness checking, see if we |
272 | // can get a better error message by performing HIR-based well-formedness checking. | |
136023e0 | 273 | if let ObligationCauseCode::WellFormed(Some(wf_loc)) = |
a2a8927a | 274 | root_obligation.cause.code().peel_derives() |
136023e0 | 275 | { |
c295e0f8 XL |
276 | if let Some(cause) = self |
277 | .tcx | |
278 | .diagnostic_hir_wf_check((tcx.erase_regions(obligation.predicate), *wf_loc)) | |
279 | { | |
5099ac24 | 280 | obligation.cause = cause.clone(); |
136023e0 XL |
281 | span = obligation.cause.span; |
282 | } | |
283 | } | |
ba9703b0 | 284 | if let ObligationCauseCode::CompareImplMethodObligation { |
ba9703b0 XL |
285 | impl_item_def_id, |
286 | trait_item_def_id, | |
287 | } | |
288 | | ObligationCauseCode::CompareImplTypeObligation { | |
ba9703b0 XL |
289 | impl_item_def_id, |
290 | trait_item_def_id, | |
a2a8927a | 291 | } = *obligation.cause.code() |
ba9703b0 XL |
292 | { |
293 | self.report_extra_impl_obligation( | |
294 | span, | |
ba9703b0 XL |
295 | impl_item_def_id, |
296 | trait_item_def_id, | |
297 | &format!("`{}`", obligation.predicate), | |
298 | ) | |
299 | .emit(); | |
300 | return; | |
301 | } | |
3dfed10e | 302 | |
5869c6ff | 303 | let bound_predicate = obligation.predicate.kind(); |
29967ef6 | 304 | match bound_predicate.skip_binder() { |
94222f64 | 305 | ty::PredicateKind::Trait(trait_predicate) => { |
29967ef6 | 306 | let trait_predicate = bound_predicate.rebind(trait_predicate); |
5099ac24 FG |
307 | let mut trait_predicate = self.resolve_vars_if_possible(trait_predicate); |
308 | ||
309 | trait_predicate.remap_constness_diag(obligation.param_env); | |
310 | let predicate_is_const = ty::BoundConstness::ConstIfConst | |
311 | == trait_predicate.skip_binder().constness; | |
ba9703b0 XL |
312 | |
313 | if self.tcx.sess.has_errors() && trait_predicate.references_error() { | |
314 | return; | |
315 | } | |
316 | let trait_ref = trait_predicate.to_poly_trait_ref(); | |
317 | let (post_message, pre_message, type_def) = self | |
a2a8927a | 318 | .get_parent_trait_ref(obligation.cause.code()) |
ba9703b0 XL |
319 | .map(|(t, s)| { |
320 | ( | |
321 | format!(" in `{}`", t), | |
322 | format!("within `{}`, ", t), | |
323 | s.map(|s| (format!("within this `{}`", t), s)), | |
324 | ) | |
325 | }) | |
326 | .unwrap_or_default(); | |
327 | ||
5099ac24 FG |
328 | let OnUnimplementedNote { |
329 | message, | |
330 | label, | |
331 | note, | |
332 | enclosing_scope, | |
333 | append_const_msg, | |
334 | } = self.on_unimplemented_note(trait_ref, &obligation); | |
ba9703b0 | 335 | let have_alt_message = message.is_some() || label.is_some(); |
5869c6ff | 336 | let is_try_conversion = self.is_try_conversion(span, trait_ref.def_id()); |
f9f354fc XL |
337 | let is_unsize = |
338 | { Some(trait_ref.def_id()) == self.tcx.lang_items().unsize_trait() }; | |
5099ac24 | 339 | let (message, note, append_const_msg) = if is_try_conversion { |
ba9703b0 XL |
340 | ( |
341 | Some(format!( | |
342 | "`?` couldn't convert the error to `{}`", | |
f035d41b | 343 | trait_ref.skip_binder().self_ty(), |
ba9703b0 XL |
344 | )), |
345 | Some( | |
346 | "the question mark operation (`?`) implicitly performs a \ | |
347 | conversion on the error value using the `From` trait" | |
348 | .to_owned(), | |
349 | ), | |
5099ac24 | 350 | Some(None), |
ba9703b0 XL |
351 | ) |
352 | } else { | |
5099ac24 | 353 | (message, note, append_const_msg) |
ba9703b0 XL |
354 | }; |
355 | ||
356 | let mut err = struct_span_err!( | |
357 | self.tcx.sess, | |
358 | span, | |
359 | E0277, | |
360 | "{}", | |
5099ac24 FG |
361 | message |
362 | .and_then(|cannot_do_this| { | |
363 | match (predicate_is_const, append_const_msg) { | |
364 | // do nothing if predicate is not const | |
365 | (false, _) => Some(cannot_do_this), | |
366 | // suggested using default post message | |
367 | (true, Some(None)) => { | |
368 | Some(format!("{cannot_do_this} in const contexts")) | |
369 | } | |
370 | // overriden post message | |
371 | (true, Some(Some(post_message))) => { | |
372 | Some(format!("{cannot_do_this}{post_message}")) | |
373 | } | |
374 | // fallback to generic message | |
375 | (true, None) => None, | |
376 | } | |
377 | }) | |
378 | .unwrap_or_else(|| format!( | |
379 | "the trait bound `{}` is not satisfied{}", | |
380 | trait_predicate, post_message, | |
381 | )) | |
ba9703b0 XL |
382 | ); |
383 | ||
5869c6ff | 384 | if is_try_conversion { |
3dfed10e XL |
385 | let none_error = self |
386 | .tcx | |
387 | .get_diagnostic_item(sym::none_error) | |
388 | .map(|def_id| tcx.type_of(def_id)); | |
389 | let should_convert_option_to_result = | |
390 | Some(trait_ref.skip_binder().substs.type_at(1)) == none_error; | |
391 | let should_convert_result_to_option = | |
392 | Some(trait_ref.self_ty().skip_binder()) == none_error; | |
f9f354fc XL |
393 | if should_convert_option_to_result { |
394 | err.span_suggestion_verbose( | |
395 | span.shrink_to_lo(), | |
396 | "consider converting the `Option<T>` into a `Result<T, _>` \ | |
397 | using `Option::ok_or` or `Option::ok_or_else`", | |
398 | ".ok_or_else(|| /* error value */)".to_string(), | |
399 | Applicability::HasPlaceholders, | |
400 | ); | |
401 | } else if should_convert_result_to_option { | |
402 | err.span_suggestion_verbose( | |
403 | span.shrink_to_lo(), | |
404 | "consider converting the `Result<T, _>` into an `Option<T>` \ | |
405 | using `Result::ok`", | |
406 | ".ok()".to_string(), | |
407 | Applicability::MachineApplicable, | |
408 | ); | |
409 | } | |
136023e0 | 410 | if let Some(ret_span) = self.return_type_span(&obligation) { |
f9f354fc XL |
411 | err.span_label( |
412 | ret_span, | |
f035d41b XL |
413 | &format!( |
414 | "expected `{}` because of this", | |
415 | trait_ref.skip_binder().self_ty() | |
416 | ), | |
f9f354fc XL |
417 | ); |
418 | } | |
ba9703b0 XL |
419 | } |
420 | ||
a2a8927a XL |
421 | let explanation = if let ObligationCauseCode::MainFunctionType = |
422 | obligation.cause.code() | |
423 | { | |
424 | "consider using `()`, or a `Result`".to_owned() | |
425 | } else { | |
426 | format!( | |
427 | "{}the trait `{}` is not implemented for `{}`", | |
428 | pre_message, | |
5099ac24 | 429 | trait_predicate.print_modifiers_and_trait_path(), |
a2a8927a XL |
430 | trait_ref.skip_binder().self_ty(), |
431 | ) | |
432 | }; | |
ba9703b0 XL |
433 | |
434 | if self.suggest_add_reference_to_arg( | |
435 | &obligation, | |
436 | &mut err, | |
5099ac24 | 437 | trait_predicate, |
ba9703b0 XL |
438 | have_alt_message, |
439 | ) { | |
136023e0 | 440 | self.note_obligation_cause(&mut err, &obligation); |
ba9703b0 XL |
441 | err.emit(); |
442 | return; | |
443 | } | |
444 | if let Some(ref s) = label { | |
445 | // If it has a custom `#[rustc_on_unimplemented]` | |
446 | // error message, let's display it as the label! | |
447 | err.span_label(span, s.as_str()); | |
1b1a35ee | 448 | if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) { |
3dfed10e XL |
449 | // When the self type is a type param We don't need to "the trait |
450 | // `std::marker::Sized` is not implemented for `T`" as we will point | |
451 | // at the type param with a label to suggest constraining it. | |
452 | err.help(&explanation); | |
453 | } | |
ba9703b0 XL |
454 | } else { |
455 | err.span_label(span, explanation); | |
456 | } | |
5099ac24 FG |
457 | |
458 | if trait_predicate.is_const_if_const() && obligation.param_env.is_const() { | |
459 | let non_const_predicate = trait_ref.without_const(); | |
460 | let non_const_obligation = Obligation { | |
461 | cause: obligation.cause.clone(), | |
462 | param_env: obligation.param_env.without_const(), | |
463 | predicate: non_const_predicate.to_predicate(tcx), | |
464 | recursion_depth: obligation.recursion_depth, | |
465 | }; | |
466 | if self.predicate_may_hold(&non_const_obligation) { | |
467 | err.span_note( | |
468 | span, | |
469 | &format!( | |
470 | "the trait `{}` is implemented for `{}`, \ | |
471 | but that implementation is not `const`", | |
472 | non_const_predicate.print_modifiers_and_trait_path(), | |
473 | trait_ref.skip_binder().self_ty(), | |
474 | ), | |
475 | ); | |
476 | } | |
477 | } | |
478 | ||
ba9703b0 XL |
479 | if let Some((msg, span)) = type_def { |
480 | err.span_label(span, &msg); | |
481 | } | |
482 | if let Some(ref s) = note { | |
483 | // If it has a custom `#[rustc_on_unimplemented]` note, let's display it | |
484 | err.note(s.as_str()); | |
485 | } | |
486 | if let Some(ref s) = enclosing_scope { | |
3dfed10e XL |
487 | let body = tcx |
488 | .hir() | |
489 | .opt_local_def_id(obligation.cause.body_id) | |
490 | .unwrap_or_else(|| { | |
491 | tcx.hir().body_owner_def_id(hir::BodyId { | |
492 | hir_id: obligation.cause.body_id, | |
ba9703b0 | 493 | }) |
3dfed10e XL |
494 | }); |
495 | ||
496 | let enclosing_scope_span = | |
497 | tcx.hir().span_with_body(tcx.hir().local_def_id_to_hir_id(body)); | |
ba9703b0 XL |
498 | |
499 | err.span_label(enclosing_scope_span, s.as_str()); | |
500 | } | |
501 | ||
5099ac24 FG |
502 | self.suggest_dereferences(&obligation, &mut err, trait_predicate); |
503 | self.suggest_fn_call(&obligation, &mut err, trait_predicate); | |
504 | self.suggest_remove_reference(&obligation, &mut err, trait_predicate); | |
505 | self.suggest_semicolon_removal( | |
506 | &obligation, | |
507 | &mut err, | |
508 | span, | |
509 | trait_predicate, | |
510 | ); | |
ba9703b0 | 511 | self.note_version_mismatch(&mut err, &trait_ref); |
a2a8927a | 512 | self.suggest_remove_await(&obligation, &mut err); |
f9f354fc XL |
513 | |
514 | if Some(trait_ref.def_id()) == tcx.lang_items().try_trait() { | |
5099ac24 FG |
515 | self.suggest_await_before_try( |
516 | &mut err, | |
517 | &obligation, | |
518 | trait_predicate, | |
519 | span, | |
520 | ); | |
f9f354fc XL |
521 | } |
522 | ||
5099ac24 | 523 | if self.suggest_impl_trait(&mut err, span, &obligation, trait_predicate) { |
ba9703b0 XL |
524 | err.emit(); |
525 | return; | |
526 | } | |
527 | ||
f9f354fc XL |
528 | if is_unsize { |
529 | // If the obligation failed due to a missing implementation of the | |
530 | // `Unsize` trait, give a pointer to why that might be the case | |
531 | err.note( | |
532 | "all implementations of `Unsize` are provided \ | |
533 | automatically by the compiler, see \ | |
534 | <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> \ | |
535 | for more information", | |
536 | ); | |
537 | } | |
538 | ||
f035d41b XL |
539 | let is_fn_trait = [ |
540 | self.tcx.lang_items().fn_trait(), | |
541 | self.tcx.lang_items().fn_mut_trait(), | |
542 | self.tcx.lang_items().fn_once_trait(), | |
543 | ] | |
544 | .contains(&Some(trait_ref.def_id())); | |
1b1a35ee XL |
545 | let is_target_feature_fn = if let ty::FnDef(def_id, _) = |
546 | *trait_ref.skip_binder().self_ty().kind() | |
547 | { | |
548 | !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty() | |
549 | } else { | |
550 | false | |
551 | }; | |
f035d41b XL |
552 | if is_fn_trait && is_target_feature_fn { |
553 | err.note( | |
554 | "`#[target_feature]` functions do not implement the `Fn` traits", | |
555 | ); | |
556 | } | |
557 | ||
ba9703b0 XL |
558 | // Try to report a help message |
559 | if !trait_ref.has_infer_types_or_consts() | |
560 | && self.predicate_can_apply(obligation.param_env, trait_ref) | |
561 | { | |
562 | // If a where-clause may be useful, remind the | |
563 | // user that they can add it. | |
564 | // | |
565 | // don't display an on-unimplemented note, as | |
566 | // these notes will often be of the form | |
567 | // "the type `T` can't be frobnicated" | |
568 | // which is somewhat confusing. | |
569 | self.suggest_restricting_param_bound( | |
570 | &mut err, | |
5099ac24 | 571 | trait_predicate, |
ba9703b0 XL |
572 | obligation.cause.body_id, |
573 | ); | |
6a06907d XL |
574 | } else if !have_alt_message { |
575 | // Can't show anything else useful, try to find similar impls. | |
576 | let impl_candidates = self.find_similar_impl_candidates(trait_ref); | |
577 | self.report_similar_impl_candidates(impl_candidates, &mut err); | |
578 | } | |
579 | ||
580 | // Changing mutability doesn't make a difference to whether we have | |
581 | // an `Unsize` impl (Fixes ICE in #71036) | |
582 | if !is_unsize { | |
5099ac24 | 583 | self.suggest_change_mut(&obligation, &mut err, trait_predicate); |
ba9703b0 XL |
584 | } |
585 | ||
586 | // If this error is due to `!: Trait` not implemented but `(): Trait` is | |
587 | // implemented, and fallback has occurred, then it could be due to a | |
588 | // variable that used to fallback to `()` now falling back to `!`. Issue a | |
589 | // note informing about the change in behaviour. | |
590 | if trait_predicate.skip_binder().self_ty().is_never() | |
591 | && fallback_has_occurred | |
592 | { | |
593 | let predicate = trait_predicate.map_bound(|mut trait_pred| { | |
594 | trait_pred.trait_ref.substs = self.tcx.mk_substs_trait( | |
595 | self.tcx.mk_unit(), | |
596 | &trait_pred.trait_ref.substs[1..], | |
597 | ); | |
598 | trait_pred | |
599 | }); | |
94222f64 | 600 | let unit_obligation = obligation.with(predicate.to_predicate(tcx)); |
ba9703b0 | 601 | if self.predicate_may_hold(&unit_obligation) { |
c295e0f8 | 602 | err.note("this trait is implemented for `()`"); |
ba9703b0 | 603 | err.note( |
cdc7bbd5 XL |
604 | "this error might have been caused by changes to \ |
605 | Rust's type-inference algorithm (see issue #48950 \ | |
606 | <https://github.com/rust-lang/rust/issues/48950> \ | |
c295e0f8 | 607 | for more information)", |
ba9703b0 | 608 | ); |
cdc7bbd5 | 609 | err.help("did you intend to use the type `()` here instead?"); |
ba9703b0 XL |
610 | } |
611 | } | |
612 | ||
136023e0 XL |
613 | // Return early if the trait is Debug or Display and the invocation |
614 | // originates within a standard library macro, because the output | |
615 | // is otherwise overwhelming and unhelpful (see #85844 for an | |
616 | // example). | |
617 | ||
136023e0 XL |
618 | let in_std_macro = |
619 | match obligation.cause.span.ctxt().outer_expn_data().macro_def_id { | |
620 | Some(macro_def_id) => { | |
621 | let crate_name = tcx.crate_name(macro_def_id.krate); | |
622 | crate_name == sym::std || crate_name == sym::core | |
623 | } | |
624 | None => false, | |
625 | }; | |
626 | ||
a2a8927a XL |
627 | if in_std_macro |
628 | && matches!( | |
629 | self.tcx.get_diagnostic_name(trait_ref.def_id()), | |
630 | Some(sym::Debug | sym::Display) | |
631 | ) | |
632 | { | |
136023e0 XL |
633 | err.emit(); |
634 | return; | |
635 | } | |
636 | ||
ba9703b0 XL |
637 | err |
638 | } | |
639 | ||
5869c6ff | 640 | ty::PredicateKind::Subtype(predicate) => { |
ba9703b0 XL |
641 | // Errors for Subtype predicates show up as |
642 | // `FulfillmentErrorCode::CodeSubtypeError`, | |
643 | // not selection error. | |
644 | span_bug!(span, "subtype requirement gave wrong error: `{:?}`", predicate) | |
645 | } | |
646 | ||
94222f64 XL |
647 | ty::PredicateKind::Coerce(predicate) => { |
648 | // Errors for Coerce predicates show up as | |
649 | // `FulfillmentErrorCode::CodeSubtypeError`, | |
650 | // not selection error. | |
651 | span_bug!(span, "coerce requirement gave wrong error: `{:?}`", predicate) | |
652 | } | |
653 | ||
5869c6ff | 654 | ty::PredicateKind::RegionOutlives(predicate) => { |
29967ef6 | 655 | let predicate = bound_predicate.rebind(predicate); |
fc512014 | 656 | let predicate = self.resolve_vars_if_possible(predicate); |
ba9703b0 | 657 | let err = self |
f9f354fc | 658 | .region_outlives_predicate(&obligation.cause, predicate) |
ba9703b0 XL |
659 | .err() |
660 | .unwrap(); | |
661 | struct_span_err!( | |
662 | self.tcx.sess, | |
663 | span, | |
664 | E0279, | |
665 | "the requirement `{}` is not satisfied (`{}`)", | |
666 | predicate, | |
667 | err, | |
668 | ) | |
669 | } | |
670 | ||
5869c6ff | 671 | ty::PredicateKind::Projection(..) | ty::PredicateKind::TypeOutlives(..) => { |
fc512014 | 672 | let predicate = self.resolve_vars_if_possible(obligation.predicate); |
ba9703b0 XL |
673 | struct_span_err!( |
674 | self.tcx.sess, | |
675 | span, | |
676 | E0280, | |
677 | "the requirement `{}` is not satisfied", | |
678 | predicate | |
679 | ) | |
680 | } | |
681 | ||
5869c6ff | 682 | ty::PredicateKind::ObjectSafe(trait_def_id) => { |
ba9703b0 XL |
683 | let violations = self.tcx.object_safety_violations(trait_def_id); |
684 | report_object_safety_error(self.tcx, span, trait_def_id, violations) | |
685 | } | |
686 | ||
5869c6ff | 687 | ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => { |
ba9703b0 XL |
688 | let found_kind = self.closure_kind(closure_substs).unwrap(); |
689 | let closure_span = | |
690 | self.tcx.sess.source_map().guess_head_span( | |
691 | self.tcx.hir().span_if_local(closure_def_id).unwrap(), | |
692 | ); | |
ba9703b0 XL |
693 | let mut err = struct_span_err!( |
694 | self.tcx.sess, | |
695 | closure_span, | |
696 | E0525, | |
697 | "expected a closure that implements the `{}` trait, \ | |
698 | but this closure only implements `{}`", | |
699 | kind, | |
700 | found_kind | |
701 | ); | |
702 | ||
703 | err.span_label( | |
704 | closure_span, | |
705 | format!("this closure implements `{}`, not `{}`", found_kind, kind), | |
706 | ); | |
707 | err.span_label( | |
708 | obligation.cause.span, | |
709 | format!("the requirement to implement `{}` derives from here", kind), | |
710 | ); | |
711 | ||
712 | // Additional context information explaining why the closure only implements | |
713 | // a particular trait. | |
3dfed10e | 714 | if let Some(typeck_results) = self.in_progress_typeck_results { |
5099ac24 FG |
715 | let hir_id = self |
716 | .tcx | |
717 | .hir() | |
718 | .local_def_id_to_hir_id(closure_def_id.expect_local()); | |
3dfed10e XL |
719 | let typeck_results = typeck_results.borrow(); |
720 | match (found_kind, typeck_results.closure_kind_origins().get(hir_id)) { | |
5869c6ff | 721 | (ty::ClosureKind::FnOnce, Some((span, place))) => { |
ba9703b0 XL |
722 | err.span_label( |
723 | *span, | |
724 | format!( | |
725 | "closure is `FnOnce` because it moves the \ | |
726 | variable `{}` out of its environment", | |
5869c6ff | 727 | ty::place_to_string_for_capture(tcx, place) |
ba9703b0 XL |
728 | ), |
729 | ); | |
730 | } | |
5869c6ff | 731 | (ty::ClosureKind::FnMut, Some((span, place))) => { |
ba9703b0 XL |
732 | err.span_label( |
733 | *span, | |
734 | format!( | |
735 | "closure is `FnMut` because it mutates the \ | |
736 | variable `{}` here", | |
5869c6ff | 737 | ty::place_to_string_for_capture(tcx, place) |
ba9703b0 XL |
738 | ), |
739 | ); | |
740 | } | |
741 | _ => {} | |
742 | } | |
743 | } | |
744 | ||
745 | err.emit(); | |
746 | return; | |
747 | } | |
748 | ||
5869c6ff | 749 | ty::PredicateKind::WellFormed(ty) => { |
f9f354fc XL |
750 | if !self.tcx.sess.opts.debugging_opts.chalk { |
751 | // WF predicates cannot themselves make | |
752 | // errors. They can only block due to | |
753 | // ambiguity; otherwise, they always | |
754 | // degenerate into other obligations | |
755 | // (which may fail). | |
756 | span_bug!(span, "WF predicate not satisfied for {:?}", ty); | |
757 | } else { | |
758 | // FIXME: we'll need a better message which takes into account | |
759 | // which bounds actually failed to hold. | |
760 | self.tcx.sess.struct_span_err( | |
761 | span, | |
762 | &format!("the type `{}` is not well-formed (chalk)", ty), | |
763 | ) | |
764 | } | |
ba9703b0 XL |
765 | } |
766 | ||
5869c6ff | 767 | ty::PredicateKind::ConstEvaluatable(..) => { |
ba9703b0 XL |
768 | // Errors for `ConstEvaluatable` predicates show up as |
769 | // `SelectionError::ConstEvalFailure`, | |
770 | // not `Unimplemented`. | |
771 | span_bug!( | |
772 | span, | |
773 | "const-evaluatable requirement gave wrong error: `{:?}`", | |
774 | obligation | |
775 | ) | |
776 | } | |
f9f354fc | 777 | |
5869c6ff | 778 | ty::PredicateKind::ConstEquate(..) => { |
f9f354fc XL |
779 | // Errors for `ConstEquate` predicates show up as |
780 | // `SelectionError::ConstEvalFailure`, | |
781 | // not `Unimplemented`. | |
782 | span_bug!( | |
783 | span, | |
784 | "const-equate requirement gave wrong error: `{:?}`", | |
785 | obligation | |
786 | ) | |
787 | } | |
1b1a35ee | 788 | |
5869c6ff | 789 | ty::PredicateKind::TypeWellFormedFromEnv(..) => span_bug!( |
1b1a35ee XL |
790 | span, |
791 | "TypeWellFormedFromEnv predicate should only exist in the environment" | |
792 | ), | |
ba9703b0 XL |
793 | } |
794 | } | |
795 | ||
fc512014 XL |
796 | OutputTypeParameterMismatch(found_trait_ref, expected_trait_ref, _) => { |
797 | let found_trait_ref = self.resolve_vars_if_possible(found_trait_ref); | |
798 | let expected_trait_ref = self.resolve_vars_if_possible(expected_trait_ref); | |
ba9703b0 XL |
799 | |
800 | if expected_trait_ref.self_ty().references_error() { | |
801 | return; | |
802 | } | |
803 | ||
f035d41b XL |
804 | let found_trait_ty = match found_trait_ref.self_ty().no_bound_vars() { |
805 | Some(ty) => ty, | |
806 | None => return, | |
807 | }; | |
ba9703b0 | 808 | |
1b1a35ee | 809 | let found_did = match *found_trait_ty.kind() { |
c295e0f8 XL |
810 | ty::Closure(did, _) |
811 | | ty::Foreign(did) | |
812 | | ty::FnDef(did, _) | |
813 | | ty::Generator(did, ..) => Some(did), | |
ba9703b0 XL |
814 | ty::Adt(def, _) => Some(def.did), |
815 | _ => None, | |
816 | }; | |
817 | ||
818 | let found_span = found_did | |
819 | .and_then(|did| self.tcx.hir().span_if_local(did)) | |
820 | .map(|sp| self.tcx.sess.source_map().guess_head_span(sp)); // the sp could be an fn def | |
821 | ||
822 | if self.reported_closure_mismatch.borrow().contains(&(span, found_span)) { | |
823 | // We check closures twice, with obligations flowing in different directions, | |
824 | // but we want to complain about them only once. | |
825 | return; | |
826 | } | |
827 | ||
828 | self.reported_closure_mismatch.borrow_mut().insert((span, found_span)); | |
829 | ||
1b1a35ee | 830 | let found = match found_trait_ref.skip_binder().substs.type_at(1).kind() { |
ba9703b0 XL |
831 | ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()], |
832 | _ => vec![ArgKind::empty()], | |
833 | }; | |
834 | ||
835 | let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1); | |
1b1a35ee | 836 | let expected = match expected_ty.kind() { |
ba9703b0 XL |
837 | ty::Tuple(ref tys) => tys |
838 | .iter() | |
839 | .map(|t| ArgKind::from_expected_ty(t.expect_ty(), Some(span))) | |
840 | .collect(), | |
841 | _ => vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())], | |
842 | }; | |
843 | ||
844 | if found.len() == expected.len() { | |
845 | self.report_closure_arg_mismatch( | |
846 | span, | |
847 | found_span, | |
848 | found_trait_ref, | |
849 | expected_trait_ref, | |
850 | ) | |
851 | } else { | |
852 | let (closure_span, found) = found_did | |
853 | .and_then(|did| { | |
854 | let node = self.tcx.hir().get_if_local(did)?; | |
855 | let (found_span, found) = self.get_fn_like_arguments(node)?; | |
856 | Some((Some(found_span), found)) | |
857 | }) | |
858 | .unwrap_or((found_span, found)); | |
859 | ||
860 | self.report_arg_count_mismatch( | |
861 | span, | |
862 | closure_span, | |
863 | expected, | |
864 | found, | |
865 | found_trait_ty.is_closure(), | |
866 | ) | |
867 | } | |
868 | } | |
869 | ||
870 | TraitNotObjectSafe(did) => { | |
871 | let violations = self.tcx.object_safety_violations(did); | |
872 | report_object_safety_error(self.tcx, span, did, violations) | |
873 | } | |
cdc7bbd5 XL |
874 | |
875 | SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsInfer) => { | |
876 | bug!( | |
877 | "MentionsInfer should have been handled in `traits/fulfill.rs` or `traits/select/mod.rs`" | |
878 | ) | |
879 | } | |
880 | SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsParam) => { | |
94222f64 | 881 | if !self.tcx.features().generic_const_exprs { |
cdc7bbd5 XL |
882 | let mut err = self.tcx.sess.struct_span_err( |
883 | span, | |
884 | "constant expression depends on a generic parameter", | |
885 | ); | |
886 | // FIXME(const_generics): we should suggest to the user how they can resolve this | |
887 | // issue. However, this is currently not actually possible | |
888 | // (see https://github.com/rust-lang/rust/issues/66962#issuecomment-575907083). | |
889 | // | |
94222f64 | 890 | // Note that with `feature(generic_const_exprs)` this case should not |
cdc7bbd5 XL |
891 | // be reachable. |
892 | err.note("this may fail depending on what value the parameter takes"); | |
893 | err.emit(); | |
894 | return; | |
895 | } | |
896 | ||
897 | match obligation.predicate.kind().skip_binder() { | |
94222f64 | 898 | ty::PredicateKind::ConstEvaluatable(uv) => { |
cdc7bbd5 XL |
899 | let mut err = |
900 | self.tcx.sess.struct_span_err(span, "unconstrained generic constant"); | |
94222f64 | 901 | let const_span = self.tcx.def_span(uv.def.did); |
cdc7bbd5 XL |
902 | match self.tcx.sess.source_map().span_to_snippet(const_span) { |
903 | Ok(snippet) => err.help(&format!( | |
904 | "try adding a `where` bound using this expression: `where [(); {}]:`", | |
905 | snippet | |
906 | )), | |
907 | _ => err.help("consider adding a `where` bound using this expression"), | |
908 | }; | |
909 | err | |
910 | } | |
911 | _ => { | |
912 | span_bug!( | |
913 | span, | |
914 | "unexpected non-ConstEvaluatable predicate, this should not be reachable" | |
915 | ) | |
916 | } | |
917 | } | |
ba9703b0 | 918 | } |
cdc7bbd5 | 919 | |
ba9703b0 | 920 | // Already reported in the query. |
cdc7bbd5 | 921 | SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(ErrorReported)) => { |
ba9703b0 XL |
922 | // FIXME(eddyb) remove this once `ErrorReported` becomes a proof token. |
923 | self.tcx.sess.delay_span_bug(span, "`ErrorReported` without an error"); | |
924 | return; | |
925 | } | |
926 | ||
ba9703b0 XL |
927 | Overflow => { |
928 | bug!("overflow should be handled before the `report_selection_error` path"); | |
929 | } | |
c295e0f8 XL |
930 | SelectionError::ErrorReporting => { |
931 | bug!("ErrorReporting Overflow should not reach `report_selection_err` call") | |
932 | } | |
ba9703b0 XL |
933 | }; |
934 | ||
136023e0 | 935 | self.note_obligation_cause(&mut err, &obligation); |
ba9703b0 XL |
936 | self.point_at_returns_when_relevant(&mut err, &obligation); |
937 | ||
938 | err.emit(); | |
939 | } | |
940 | ||
941 | /// Given some node representing a fn-like thing in the HIR map, | |
942 | /// returns a span and `ArgKind` information that describes the | |
943 | /// arguments it expects. This can be supplied to | |
944 | /// `report_arg_count_mismatch`. | |
945 | fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec<ArgKind>)> { | |
946 | let sm = self.tcx.sess.source_map(); | |
947 | let hir = self.tcx.hir(); | |
948 | Some(match node { | |
949 | Node::Expr(&hir::Expr { | |
950 | kind: hir::ExprKind::Closure(_, ref _decl, id, span, _), | |
951 | .. | |
952 | }) => ( | |
953 | sm.guess_head_span(span), | |
954 | hir.body(id) | |
955 | .params | |
956 | .iter() | |
957 | .map(|arg| { | |
958 | if let hir::Pat { kind: hir::PatKind::Tuple(ref args, _), span, .. } = | |
959 | *arg.pat | |
960 | { | |
961 | Some(ArgKind::Tuple( | |
962 | Some(span), | |
963 | args.iter() | |
964 | .map(|pat| { | |
965 | sm.span_to_snippet(pat.span) | |
966 | .ok() | |
967 | .map(|snippet| (snippet, "_".to_owned())) | |
968 | }) | |
969 | .collect::<Option<Vec<_>>>()?, | |
970 | )) | |
971 | } else { | |
972 | let name = sm.span_to_snippet(arg.pat.span).ok()?; | |
973 | Some(ArgKind::Arg(name, "_".to_owned())) | |
974 | } | |
975 | }) | |
976 | .collect::<Option<Vec<ArgKind>>>()?, | |
977 | ), | |
978 | Node::Item(&hir::Item { span, kind: hir::ItemKind::Fn(ref sig, ..), .. }) | |
979 | | Node::ImplItem(&hir::ImplItem { | |
980 | span, | |
981 | kind: hir::ImplItemKind::Fn(ref sig, _), | |
982 | .. | |
983 | }) | |
984 | | Node::TraitItem(&hir::TraitItem { | |
985 | span, | |
986 | kind: hir::TraitItemKind::Fn(ref sig, _), | |
987 | .. | |
988 | }) => ( | |
989 | sm.guess_head_span(span), | |
990 | sig.decl | |
991 | .inputs | |
992 | .iter() | |
6a06907d | 993 | .map(|arg| match arg.kind { |
ba9703b0 XL |
994 | hir::TyKind::Tup(ref tys) => ArgKind::Tuple( |
995 | Some(arg.span), | |
996 | vec![("_".to_owned(), "_".to_owned()); tys.len()], | |
997 | ), | |
998 | _ => ArgKind::empty(), | |
999 | }) | |
1000 | .collect::<Vec<ArgKind>>(), | |
1001 | ), | |
1002 | Node::Ctor(ref variant_data) => { | |
5869c6ff | 1003 | let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id)); |
ba9703b0 XL |
1004 | let span = sm.guess_head_span(span); |
1005 | (span, vec![ArgKind::empty(); variant_data.fields().len()]) | |
1006 | } | |
1007 | _ => panic!("non-FnLike node found: {:?}", node), | |
1008 | }) | |
1009 | } | |
1010 | ||
1011 | /// Reports an error when the number of arguments needed by a | |
1012 | /// trait match doesn't match the number that the expression | |
1013 | /// provides. | |
1014 | fn report_arg_count_mismatch( | |
1015 | &self, | |
1016 | span: Span, | |
1017 | found_span: Option<Span>, | |
1018 | expected_args: Vec<ArgKind>, | |
1019 | found_args: Vec<ArgKind>, | |
1020 | is_closure: bool, | |
1021 | ) -> DiagnosticBuilder<'tcx> { | |
1022 | let kind = if is_closure { "closure" } else { "function" }; | |
1023 | ||
1024 | let args_str = |arguments: &[ArgKind], other: &[ArgKind]| { | |
1025 | let arg_length = arguments.len(); | |
5869c6ff | 1026 | let distinct = matches!(other, &[ArgKind::Tuple(..)]); |
ba9703b0 XL |
1027 | match (arg_length, arguments.get(0)) { |
1028 | (1, Some(&ArgKind::Tuple(_, ref fields))) => { | |
1029 | format!("a single {}-tuple as argument", fields.len()) | |
1030 | } | |
1031 | _ => format!( | |
1032 | "{} {}argument{}", | |
1033 | arg_length, | |
1034 | if distinct && arg_length > 1 { "distinct " } else { "" }, | |
1035 | pluralize!(arg_length) | |
1036 | ), | |
1037 | } | |
1038 | }; | |
1039 | ||
1040 | let expected_str = args_str(&expected_args, &found_args); | |
1041 | let found_str = args_str(&found_args, &expected_args); | |
1042 | ||
1043 | let mut err = struct_span_err!( | |
1044 | self.tcx.sess, | |
1045 | span, | |
1046 | E0593, | |
1047 | "{} is expected to take {}, but it takes {}", | |
1048 | kind, | |
1049 | expected_str, | |
1050 | found_str, | |
1051 | ); | |
1052 | ||
1053 | err.span_label(span, format!("expected {} that takes {}", kind, expected_str)); | |
1054 | ||
1055 | if let Some(found_span) = found_span { | |
1056 | err.span_label(found_span, format!("takes {}", found_str)); | |
1057 | ||
1058 | // move |_| { ... } | |
1059 | // ^^^^^^^^-- def_span | |
1060 | // | |
1061 | // move |_| { ... } | |
1062 | // ^^^^^-- prefix | |
1063 | let prefix_span = self.tcx.sess.source_map().span_until_non_whitespace(found_span); | |
1064 | // move |_| { ... } | |
1065 | // ^^^-- pipe_span | |
1066 | let pipe_span = | |
1067 | if let Some(span) = found_span.trim_start(prefix_span) { span } else { found_span }; | |
1068 | ||
1069 | // Suggest to take and ignore the arguments with expected_args_length `_`s if | |
1070 | // found arguments is empty (assume the user just wants to ignore args in this case). | |
1071 | // For example, if `expected_args_length` is 2, suggest `|_, _|`. | |
1072 | if found_args.is_empty() && is_closure { | |
1073 | let underscores = vec!["_"; expected_args.len()].join(", "); | |
1074 | err.span_suggestion_verbose( | |
1075 | pipe_span, | |
1076 | &format!( | |
1077 | "consider changing the closure to take and ignore the expected argument{}", | |
1078 | pluralize!(expected_args.len()) | |
1079 | ), | |
1080 | format!("|{}|", underscores), | |
1081 | Applicability::MachineApplicable, | |
1082 | ); | |
1083 | } | |
1084 | ||
1085 | if let &[ArgKind::Tuple(_, ref fields)] = &found_args[..] { | |
1086 | if fields.len() == expected_args.len() { | |
1087 | let sugg = fields | |
1088 | .iter() | |
1089 | .map(|(name, _)| name.to_owned()) | |
1090 | .collect::<Vec<String>>() | |
1091 | .join(", "); | |
1092 | err.span_suggestion_verbose( | |
1093 | found_span, | |
1094 | "change the closure to take multiple arguments instead of a single tuple", | |
1095 | format!("|{}|", sugg), | |
1096 | Applicability::MachineApplicable, | |
1097 | ); | |
1098 | } | |
1099 | } | |
1100 | if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..] { | |
1101 | if fields.len() == found_args.len() && is_closure { | |
1102 | let sugg = format!( | |
1103 | "|({}){}|", | |
1104 | found_args | |
1105 | .iter() | |
1106 | .map(|arg| match arg { | |
1107 | ArgKind::Arg(name, _) => name.to_owned(), | |
1108 | _ => "_".to_owned(), | |
1109 | }) | |
1110 | .collect::<Vec<String>>() | |
1111 | .join(", "), | |
1112 | // add type annotations if available | |
1113 | if found_args.iter().any(|arg| match arg { | |
1114 | ArgKind::Arg(_, ty) => ty != "_", | |
1115 | _ => false, | |
1116 | }) { | |
1117 | format!( | |
1118 | ": ({})", | |
1119 | fields | |
1120 | .iter() | |
1121 | .map(|(_, ty)| ty.to_owned()) | |
1122 | .collect::<Vec<String>>() | |
1123 | .join(", ") | |
1124 | ) | |
1125 | } else { | |
1126 | String::new() | |
1127 | }, | |
1128 | ); | |
1129 | err.span_suggestion_verbose( | |
1130 | found_span, | |
1131 | "change the closure to accept a tuple instead of individual arguments", | |
1132 | sugg, | |
1133 | Applicability::MachineApplicable, | |
1134 | ); | |
1135 | } | |
1136 | } | |
1137 | } | |
1138 | ||
1139 | err | |
1140 | } | |
1141 | } | |
1142 | ||
a2a8927a | 1143 | trait InferCtxtPrivExt<'hir, 'tcx> { |
ba9703b0 XL |
1144 | // returns if `cond` not occurring implies that `error` does not occur - i.e., that |
1145 | // `error` occurring implies that `cond` occurs. | |
f9f354fc | 1146 | fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool; |
ba9703b0 XL |
1147 | |
1148 | fn report_fulfillment_error( | |
1149 | &self, | |
1150 | error: &FulfillmentError<'tcx>, | |
1151 | body_id: Option<hir::BodyId>, | |
1152 | fallback_has_occurred: bool, | |
1153 | ); | |
1154 | ||
1155 | fn report_projection_error( | |
1156 | &self, | |
1157 | obligation: &PredicateObligation<'tcx>, | |
1158 | error: &MismatchedProjectionTypes<'tcx>, | |
1159 | ); | |
1160 | ||
5099ac24 FG |
1161 | fn fuzzy_match_tys( |
1162 | &self, | |
1163 | a: Ty<'tcx>, | |
1164 | b: Ty<'tcx>, | |
1165 | ignoring_lifetimes: bool, | |
1166 | ) -> Option<CandidateSimilarity>; | |
ba9703b0 XL |
1167 | |
1168 | fn describe_generator(&self, body_id: hir::BodyId) -> Option<&'static str>; | |
1169 | ||
1170 | fn find_similar_impl_candidates( | |
1171 | &self, | |
1172 | trait_ref: ty::PolyTraitRef<'tcx>, | |
5099ac24 | 1173 | ) -> Vec<ImplCandidate<'tcx>>; |
ba9703b0 XL |
1174 | |
1175 | fn report_similar_impl_candidates( | |
1176 | &self, | |
5099ac24 | 1177 | impl_candidates: Vec<ImplCandidate<'tcx>>, |
ba9703b0 XL |
1178 | err: &mut DiagnosticBuilder<'_>, |
1179 | ); | |
1180 | ||
1181 | /// Gets the parent trait chain start | |
1182 | fn get_parent_trait_ref( | |
1183 | &self, | |
1184 | code: &ObligationCauseCode<'tcx>, | |
1185 | ) -> Option<(String, Option<Span>)>; | |
1186 | ||
1187 | /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait | |
1188 | /// with the same path as `trait_ref`, a help message about | |
1189 | /// a probable version mismatch is added to `err` | |
1190 | fn note_version_mismatch( | |
1191 | &self, | |
1192 | err: &mut DiagnosticBuilder<'_>, | |
1193 | trait_ref: &ty::PolyTraitRef<'tcx>, | |
1194 | ); | |
1195 | ||
f9f354fc XL |
1196 | /// Creates a `PredicateObligation` with `new_self_ty` replacing the existing type in the |
1197 | /// `trait_ref`. | |
1198 | /// | |
1199 | /// For this to work, `new_self_ty` must have no escaping bound variables. | |
1200 | fn mk_trait_obligation_with_new_self_ty( | |
ba9703b0 | 1201 | &self, |
ba9703b0 | 1202 | param_env: ty::ParamEnv<'tcx>, |
5099ac24 | 1203 | trait_ref: ty::PolyTraitPredicate<'tcx>, |
f9f354fc | 1204 | new_self_ty: Ty<'tcx>, |
ba9703b0 XL |
1205 | ) -> PredicateObligation<'tcx>; |
1206 | ||
1207 | fn maybe_report_ambiguity( | |
1208 | &self, | |
1209 | obligation: &PredicateObligation<'tcx>, | |
1210 | body_id: Option<hir::BodyId>, | |
1211 | ); | |
1212 | ||
1213 | fn predicate_can_apply( | |
1214 | &self, | |
1215 | param_env: ty::ParamEnv<'tcx>, | |
1216 | pred: ty::PolyTraitRef<'tcx>, | |
1217 | ) -> bool; | |
1218 | ||
1219 | fn note_obligation_cause( | |
1220 | &self, | |
f9f354fc | 1221 | err: &mut DiagnosticBuilder<'tcx>, |
ba9703b0 XL |
1222 | obligation: &PredicateObligation<'tcx>, |
1223 | ); | |
1224 | ||
1225 | fn suggest_unsized_bound_if_applicable( | |
1226 | &self, | |
f9f354fc | 1227 | err: &mut DiagnosticBuilder<'tcx>, |
ba9703b0 XL |
1228 | obligation: &PredicateObligation<'tcx>, |
1229 | ); | |
1230 | ||
3c0e092e XL |
1231 | fn annotate_source_of_ambiguity( |
1232 | &self, | |
1233 | err: &mut DiagnosticBuilder<'tcx>, | |
1234 | impls: &[DefId], | |
1235 | predicate: ty::Predicate<'tcx>, | |
1236 | ); | |
1237 | ||
94222f64 XL |
1238 | fn maybe_suggest_unsized_generics( |
1239 | &self, | |
1240 | err: &mut DiagnosticBuilder<'tcx>, | |
1241 | span: Span, | |
1242 | node: Node<'hir>, | |
1243 | ); | |
1244 | ||
1245 | fn maybe_indirection_for_unsized( | |
1246 | &self, | |
1247 | err: &mut DiagnosticBuilder<'tcx>, | |
1248 | item: &'hir Item<'hir>, | |
1249 | param: &'hir GenericParam<'hir>, | |
1250 | ) -> bool; | |
1251 | ||
ba9703b0 XL |
1252 | fn is_recursive_obligation( |
1253 | &self, | |
5099ac24 | 1254 | obligated_types: &mut Vec<Ty<'tcx>>, |
ba9703b0 XL |
1255 | cause_code: &ObligationCauseCode<'tcx>, |
1256 | ) -> bool; | |
1257 | } | |
1258 | ||
a2a8927a | 1259 | impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { |
ba9703b0 XL |
1260 | // returns if `cond` not occurring implies that `error` does not occur - i.e., that |
1261 | // `error` occurring implies that `cond` occurs. | |
f9f354fc | 1262 | fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool { |
ba9703b0 XL |
1263 | if cond == error { |
1264 | return true; | |
1265 | } | |
1266 | ||
3dfed10e | 1267 | // FIXME: It should be possible to deal with `ForAll` in a cleaner way. |
5869c6ff XL |
1268 | let bound_error = error.kind(); |
1269 | let (cond, error) = match (cond.kind().skip_binder(), bound_error.skip_binder()) { | |
94222f64 | 1270 | (ty::PredicateKind::Trait(..), ty::PredicateKind::Trait(error)) => { |
29967ef6 | 1271 | (cond, bound_error.rebind(error)) |
3dfed10e | 1272 | } |
ba9703b0 XL |
1273 | _ => { |
1274 | // FIXME: make this work in other cases too. | |
1275 | return false; | |
1276 | } | |
1277 | }; | |
1278 | ||
f9f354fc | 1279 | for obligation in super::elaborate_predicates(self.tcx, std::iter::once(cond)) { |
5869c6ff | 1280 | let bound_predicate = obligation.predicate.kind(); |
94222f64 | 1281 | if let ty::PredicateKind::Trait(implication) = bound_predicate.skip_binder() { |
ba9703b0 | 1282 | let error = error.to_poly_trait_ref(); |
29967ef6 | 1283 | let implication = bound_predicate.rebind(implication.trait_ref); |
ba9703b0 XL |
1284 | // FIXME: I'm just not taking associated types at all here. |
1285 | // Eventually I'll need to implement param-env-aware | |
1286 | // `Γ₁ ⊦ φ₁ => Γ₂ ⊦ φ₂` logic. | |
1287 | let param_env = ty::ParamEnv::empty(); | |
1288 | if self.can_sub(param_env, error, implication).is_ok() { | |
1289 | debug!("error_implies: {:?} -> {:?} -> {:?}", cond, error, implication); | |
1290 | return true; | |
1291 | } | |
1292 | } | |
1293 | } | |
1294 | ||
1295 | false | |
1296 | } | |
1297 | ||
c295e0f8 | 1298 | #[instrument(skip(self), level = "debug")] |
ba9703b0 XL |
1299 | fn report_fulfillment_error( |
1300 | &self, | |
1301 | error: &FulfillmentError<'tcx>, | |
1302 | body_id: Option<hir::BodyId>, | |
1303 | fallback_has_occurred: bool, | |
1304 | ) { | |
ba9703b0 XL |
1305 | match error.code { |
1306 | FulfillmentErrorCode::CodeSelectionError(ref selection_error) => { | |
1307 | self.report_selection_error( | |
136023e0 XL |
1308 | error.obligation.clone(), |
1309 | &error.root_obligation, | |
ba9703b0 XL |
1310 | selection_error, |
1311 | fallback_has_occurred, | |
ba9703b0 XL |
1312 | ); |
1313 | } | |
1314 | FulfillmentErrorCode::CodeProjectionError(ref e) => { | |
1315 | self.report_projection_error(&error.obligation, e); | |
1316 | } | |
1317 | FulfillmentErrorCode::CodeAmbiguity => { | |
1318 | self.maybe_report_ambiguity(&error.obligation, body_id); | |
1319 | } | |
1320 | FulfillmentErrorCode::CodeSubtypeError(ref expected_found, ref err) => { | |
1321 | self.report_mismatched_types( | |
1322 | &error.obligation.cause, | |
1323 | expected_found.expected, | |
1324 | expected_found.found, | |
1325 | err.clone(), | |
1326 | ) | |
1327 | .emit(); | |
1328 | } | |
f9f354fc XL |
1329 | FulfillmentErrorCode::CodeConstEquateError(ref expected_found, ref err) => { |
1330 | self.report_mismatched_consts( | |
1331 | &error.obligation.cause, | |
1332 | expected_found.expected, | |
1333 | expected_found.found, | |
1334 | err.clone(), | |
1335 | ) | |
1336 | .emit(); | |
1337 | } | |
ba9703b0 XL |
1338 | } |
1339 | } | |
1340 | ||
1341 | fn report_projection_error( | |
1342 | &self, | |
1343 | obligation: &PredicateObligation<'tcx>, | |
1344 | error: &MismatchedProjectionTypes<'tcx>, | |
1345 | ) { | |
fc512014 | 1346 | let predicate = self.resolve_vars_if_possible(obligation.predicate); |
ba9703b0 XL |
1347 | |
1348 | if predicate.references_error() { | |
1349 | return; | |
1350 | } | |
1351 | ||
1352 | self.probe(|_| { | |
1353 | let err_buf; | |
1354 | let mut err = &error.err; | |
1355 | let mut values = None; | |
1356 | ||
1357 | // try to find the mismatched types to report the error with. | |
1358 | // | |
1359 | // this can fail if the problem was higher-ranked, in which | |
1360 | // cause I have no idea for a good error message. | |
5869c6ff XL |
1361 | let bound_predicate = predicate.kind(); |
1362 | if let ty::PredicateKind::Projection(data) = bound_predicate.skip_binder() { | |
ba9703b0 XL |
1363 | let mut selcx = SelectionContext::new(self); |
1364 | let (data, _) = self.replace_bound_vars_with_fresh_vars( | |
1365 | obligation.cause.span, | |
1366 | infer::LateBoundRegionConversionTime::HigherRankedType, | |
fc512014 | 1367 | bound_predicate.rebind(data), |
ba9703b0 XL |
1368 | ); |
1369 | let mut obligations = vec![]; | |
1370 | let normalized_ty = super::normalize_projection_type( | |
1371 | &mut selcx, | |
1372 | obligation.param_env, | |
1373 | data.projection_ty, | |
1374 | obligation.cause.clone(), | |
1375 | 0, | |
1376 | &mut obligations, | |
1377 | ); | |
1378 | ||
1379 | debug!( | |
1380 | "report_projection_error obligation.cause={:?} obligation.param_env={:?}", | |
1381 | obligation.cause, obligation.param_env | |
1382 | ); | |
1383 | ||
1384 | debug!( | |
1385 | "report_projection_error normalized_ty={:?} data.ty={:?}", | |
5099ac24 | 1386 | normalized_ty, data.term, |
ba9703b0 XL |
1387 | ); |
1388 | ||
5869c6ff | 1389 | let is_normalized_ty_expected = !matches!( |
a2a8927a | 1390 | obligation.cause.code().peel_derives(), |
ba9703b0 | 1391 | ObligationCauseCode::ItemObligation(_) |
5869c6ff XL |
1392 | | ObligationCauseCode::BindingObligation(_, _) |
1393 | | ObligationCauseCode::ObjectCastObligation(_) | |
cdc7bbd5 | 1394 | | ObligationCauseCode::OpaqueType |
5869c6ff | 1395 | ); |
ba9703b0 XL |
1396 | if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp( |
1397 | is_normalized_ty_expected, | |
1398 | normalized_ty, | |
5099ac24 | 1399 | data.term, |
ba9703b0 | 1400 | ) { |
5099ac24 | 1401 | values = Some(infer::ValuePairs::Terms(ExpectedFound::new( |
ba9703b0 XL |
1402 | is_normalized_ty_expected, |
1403 | normalized_ty, | |
5099ac24 | 1404 | data.term, |
ba9703b0 | 1405 | ))); |
ba9703b0 XL |
1406 | err_buf = error; |
1407 | err = &err_buf; | |
1408 | } | |
1409 | } | |
1410 | ||
1411 | let msg = format!("type mismatch resolving `{}`", predicate); | |
1412 | let error_id = (DiagnosticMessageId::ErrorId(271), Some(obligation.cause.span), msg); | |
1413 | let fresh = self.tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id); | |
1414 | if fresh { | |
1415 | let mut diag = struct_span_err!( | |
1416 | self.tcx.sess, | |
1417 | obligation.cause.span, | |
1418 | E0271, | |
1419 | "type mismatch resolving `{}`", | |
1420 | predicate | |
1421 | ); | |
a2a8927a XL |
1422 | let secondary_span = match predicate.kind().skip_binder() { |
1423 | ty::PredicateKind::Projection(proj) => self | |
1424 | .tcx | |
1425 | .opt_associated_item(proj.projection_ty.item_def_id) | |
1426 | .and_then(|trait_assoc_item| { | |
1427 | self.tcx | |
1428 | .trait_of_item(proj.projection_ty.item_def_id) | |
1429 | .map(|id| (trait_assoc_item, id)) | |
1430 | }) | |
1431 | .and_then(|(trait_assoc_item, id)| { | |
5099ac24 | 1432 | let trait_assoc_ident = trait_assoc_item.ident(self.tcx); |
a2a8927a XL |
1433 | self.tcx.find_map_relevant_impl( |
1434 | id, | |
1435 | proj.projection_ty.self_ty(), | |
1436 | |did| { | |
1437 | self.tcx | |
1438 | .associated_items(did) | |
1439 | .in_definition_order() | |
5099ac24 | 1440 | .find(|assoc| assoc.ident(self.tcx) == trait_assoc_ident) |
a2a8927a XL |
1441 | }, |
1442 | ) | |
1443 | }) | |
1444 | .and_then(|item| match self.tcx.hir().get_if_local(item.def_id) { | |
1445 | Some( | |
1446 | hir::Node::TraitItem(hir::TraitItem { | |
1447 | kind: hir::TraitItemKind::Type(_, Some(ty)), | |
1448 | .. | |
1449 | }) | |
1450 | | hir::Node::ImplItem(hir::ImplItem { | |
1451 | kind: hir::ImplItemKind::TyAlias(ty), | |
1452 | .. | |
1453 | }), | |
1454 | ) => { | |
1455 | Some((ty.span, format!("type mismatch resolving `{}`", predicate))) | |
1456 | } | |
1457 | _ => None, | |
1458 | }), | |
1459 | _ => None, | |
1460 | }; | |
1461 | self.note_type_err(&mut diag, &obligation.cause, secondary_span, values, err, true); | |
ba9703b0 XL |
1462 | self.note_obligation_cause(&mut diag, obligation); |
1463 | diag.emit(); | |
1464 | } | |
1465 | }); | |
1466 | } | |
1467 | ||
5099ac24 FG |
1468 | fn fuzzy_match_tys( |
1469 | &self, | |
1470 | mut a: Ty<'tcx>, | |
1471 | mut b: Ty<'tcx>, | |
1472 | ignoring_lifetimes: bool, | |
1473 | ) -> Option<CandidateSimilarity> { | |
ba9703b0 XL |
1474 | /// returns the fuzzy category of a given type, or None |
1475 | /// if the type can be equated to any type. | |
5099ac24 | 1476 | fn type_category(tcx: TyCtxt<'_>, t: Ty<'_>) -> Option<u32> { |
1b1a35ee | 1477 | match t.kind() { |
ba9703b0 XL |
1478 | ty::Bool => Some(0), |
1479 | ty::Char => Some(1), | |
1480 | ty::Str => Some(2), | |
5099ac24 FG |
1481 | ty::Adt(def, _) if tcx.is_diagnostic_item(sym::String, def.did) => Some(2), |
1482 | ty::Int(..) | |
1483 | | ty::Uint(..) | |
1484 | | ty::Float(..) | |
1485 | | ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) => Some(4), | |
ba9703b0 XL |
1486 | ty::Ref(..) | ty::RawPtr(..) => Some(5), |
1487 | ty::Array(..) | ty::Slice(..) => Some(6), | |
1488 | ty::FnDef(..) | ty::FnPtr(..) => Some(7), | |
1489 | ty::Dynamic(..) => Some(8), | |
1490 | ty::Closure(..) => Some(9), | |
1491 | ty::Tuple(..) => Some(10), | |
5099ac24 FG |
1492 | ty::Param(..) => Some(11), |
1493 | ty::Projection(..) => Some(12), | |
ba9703b0 XL |
1494 | ty::Opaque(..) => Some(13), |
1495 | ty::Never => Some(14), | |
5099ac24 FG |
1496 | ty::Adt(..) => Some(15), |
1497 | ty::Generator(..) => Some(16), | |
1498 | ty::Foreign(..) => Some(17), | |
1499 | ty::GeneratorWitness(..) => Some(18), | |
f035d41b | 1500 | ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None, |
ba9703b0 XL |
1501 | } |
1502 | } | |
1503 | ||
5099ac24 FG |
1504 | let strip_references = |mut t: Ty<'tcx>| -> Ty<'tcx> { |
1505 | loop { | |
1506 | match t.kind() { | |
1507 | ty::Ref(_, inner, _) | ty::RawPtr(ty::TypeAndMut { ty: inner, .. }) => { | |
1508 | t = *inner | |
1509 | } | |
1510 | _ => break t, | |
1511 | } | |
1512 | } | |
1513 | }; | |
1514 | ||
1515 | if !ignoring_lifetimes { | |
1516 | a = strip_references(a); | |
1517 | b = strip_references(b); | |
1518 | } | |
1519 | ||
1520 | let cat_a = type_category(self.tcx, a)?; | |
1521 | let cat_b = type_category(self.tcx, b)?; | |
1522 | if a == b { | |
1523 | Some(CandidateSimilarity::Exact { ignoring_lifetimes }) | |
1524 | } else if cat_a == cat_b { | |
1525 | match (a.kind(), b.kind()) { | |
1526 | (ty::Adt(def_a, _), ty::Adt(def_b, _)) => def_a == def_b, | |
1527 | // Matching on references results in a lot of unhelpful | |
1528 | // suggestions, so let's just not do that for now. | |
1529 | // | |
1530 | // We still upgrade successful matches to `ignoring_lifetimes: true` | |
1531 | // to prioritize that impl. | |
1532 | (ty::Ref(..) | ty::RawPtr(..), ty::Ref(..) | ty::RawPtr(..)) => { | |
1533 | self.fuzzy_match_tys(a, b, true).is_some() | |
1534 | } | |
1535 | _ => true, | |
1536 | } | |
1537 | .then_some(CandidateSimilarity::Fuzzy { ignoring_lifetimes }) | |
1538 | } else if ignoring_lifetimes { | |
1539 | None | |
1540 | } else { | |
1541 | self.fuzzy_match_tys(a, b, true) | |
ba9703b0 XL |
1542 | } |
1543 | } | |
1544 | ||
1545 | fn describe_generator(&self, body_id: hir::BodyId) -> Option<&'static str> { | |
1546 | self.tcx.hir().body(body_id).generator_kind.map(|gen_kind| match gen_kind { | |
1547 | hir::GeneratorKind::Gen => "a generator", | |
1548 | hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) => "an async block", | |
1549 | hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn) => "an async function", | |
1550 | hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure) => "an async closure", | |
1551 | }) | |
1552 | } | |
1553 | ||
1554 | fn find_similar_impl_candidates( | |
1555 | &self, | |
1556 | trait_ref: ty::PolyTraitRef<'tcx>, | |
5099ac24 FG |
1557 | ) -> Vec<ImplCandidate<'tcx>> { |
1558 | self.tcx | |
1559 | .all_impls(trait_ref.def_id()) | |
1560 | .filter_map(|def_id| { | |
1561 | if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative { | |
1562 | return None; | |
1563 | } | |
1564 | ||
1565 | let imp = self.tcx.impl_trait_ref(def_id).unwrap(); | |
1566 | ||
1567 | self.fuzzy_match_tys(trait_ref.skip_binder().self_ty(), imp.self_ty(), false) | |
1568 | .map(|similarity| ImplCandidate { trait_ref: imp, similarity }) | |
1569 | }) | |
1570 | .collect() | |
ba9703b0 XL |
1571 | } |
1572 | ||
1573 | fn report_similar_impl_candidates( | |
1574 | &self, | |
5099ac24 | 1575 | impl_candidates: Vec<ImplCandidate<'tcx>>, |
ba9703b0 XL |
1576 | err: &mut DiagnosticBuilder<'_>, |
1577 | ) { | |
1578 | if impl_candidates.is_empty() { | |
1579 | return; | |
1580 | } | |
1581 | ||
1582 | let len = impl_candidates.len(); | |
1583 | let end = if impl_candidates.len() <= 5 { impl_candidates.len() } else { 4 }; | |
1584 | ||
1585 | let normalize = |candidate| { | |
1586 | self.tcx.infer_ctxt().enter(|ref infcx| { | |
1587 | let normalized = infcx | |
1588 | .at(&ObligationCause::dummy(), ty::ParamEnv::empty()) | |
1589 | .normalize(candidate) | |
1590 | .ok(); | |
1591 | match normalized { | |
1b1a35ee XL |
1592 | Some(normalized) => format!("\n {}", normalized.value), |
1593 | None => format!("\n {}", candidate), | |
ba9703b0 XL |
1594 | } |
1595 | }) | |
1596 | }; | |
1597 | ||
1598 | // Sort impl candidates so that ordering is consistent for UI tests. | |
ba9703b0 XL |
1599 | // because the ordering of `impl_candidates` may not be deterministic: |
1600 | // https://github.com/rust-lang/rust/pull/57475#issuecomment-455519507 | |
5099ac24 FG |
1601 | // |
1602 | // Prefer more similar candidates first, then sort lexicographically | |
1603 | // by their normalized string representation. | |
1604 | let mut normalized_impl_candidates_and_similarities = impl_candidates | |
1605 | .into_iter() | |
1606 | .map(|ImplCandidate { trait_ref, similarity }| { | |
1607 | let normalized = normalize(trait_ref); | |
1608 | (similarity, normalized) | |
1609 | }) | |
1610 | .collect::<Vec<_>>(); | |
1611 | normalized_impl_candidates_and_similarities.sort(); | |
1612 | ||
1613 | let normalized_impl_candidates = normalized_impl_candidates_and_similarities | |
1614 | .into_iter() | |
1615 | .map(|(_, normalized)| normalized) | |
1616 | .collect::<Vec<_>>(); | |
ba9703b0 XL |
1617 | |
1618 | err.help(&format!( | |
1619 | "the following implementations were found:{}{}", | |
1620 | normalized_impl_candidates[..end].join(""), | |
1621 | if len > 5 { format!("\nand {} others", len - 4) } else { String::new() } | |
1622 | )); | |
1623 | } | |
1624 | ||
1625 | /// Gets the parent trait chain start | |
1626 | fn get_parent_trait_ref( | |
1627 | &self, | |
1628 | code: &ObligationCauseCode<'tcx>, | |
1629 | ) -> Option<(String, Option<Span>)> { | |
1630 | match code { | |
5869c6ff | 1631 | ObligationCauseCode::BuiltinDerivedObligation(data) => { |
5099ac24 | 1632 | let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); |
ba9703b0 XL |
1633 | match self.get_parent_trait_ref(&data.parent_code) { |
1634 | Some(t) => Some(t), | |
1635 | None => { | |
1636 | let ty = parent_trait_ref.skip_binder().self_ty(); | |
6a06907d XL |
1637 | let span = TyCategory::from_ty(self.tcx, ty) |
1638 | .map(|(_, def_id)| self.tcx.def_span(def_id)); | |
ba9703b0 XL |
1639 | Some((ty.to_string(), span)) |
1640 | } | |
1641 | } | |
1642 | } | |
3c0e092e XL |
1643 | ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => { |
1644 | self.get_parent_trait_ref(&parent_code) | |
1645 | } | |
ba9703b0 XL |
1646 | _ => None, |
1647 | } | |
1648 | } | |
1649 | ||
1650 | /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait | |
1651 | /// with the same path as `trait_ref`, a help message about | |
1652 | /// a probable version mismatch is added to `err` | |
1653 | fn note_version_mismatch( | |
1654 | &self, | |
1655 | err: &mut DiagnosticBuilder<'_>, | |
1656 | trait_ref: &ty::PolyTraitRef<'tcx>, | |
1657 | ) { | |
1658 | let get_trait_impl = |trait_def_id| { | |
29967ef6 | 1659 | self.tcx.find_map_relevant_impl(trait_def_id, trait_ref.skip_binder().self_ty(), Some) |
ba9703b0 XL |
1660 | }; |
1661 | let required_trait_path = self.tcx.def_path_str(trait_ref.def_id()); | |
a2a8927a XL |
1662 | let traits_with_same_path: std::collections::BTreeSet<_> = self |
1663 | .tcx | |
1664 | .all_traits() | |
1665 | .filter(|trait_def_id| *trait_def_id != trait_ref.def_id()) | |
1666 | .filter(|trait_def_id| self.tcx.def_path_str(*trait_def_id) == required_trait_path) | |
ba9703b0 XL |
1667 | .collect(); |
1668 | for trait_with_same_path in traits_with_same_path { | |
a2a8927a | 1669 | if let Some(impl_def_id) = get_trait_impl(trait_with_same_path) { |
ba9703b0 XL |
1670 | let impl_span = self.tcx.def_span(impl_def_id); |
1671 | err.span_help(impl_span, "trait impl with same name found"); | |
1672 | let trait_crate = self.tcx.crate_name(trait_with_same_path.krate); | |
1673 | let crate_msg = format!( | |
1674 | "perhaps two different versions of crate `{}` are being used?", | |
1675 | trait_crate | |
1676 | ); | |
1677 | err.note(&crate_msg); | |
1678 | } | |
1679 | } | |
1680 | } | |
1681 | ||
f9f354fc | 1682 | fn mk_trait_obligation_with_new_self_ty( |
ba9703b0 | 1683 | &self, |
ba9703b0 | 1684 | param_env: ty::ParamEnv<'tcx>, |
5099ac24 | 1685 | trait_ref: ty::PolyTraitPredicate<'tcx>, |
f9f354fc | 1686 | new_self_ty: Ty<'tcx>, |
ba9703b0 | 1687 | ) -> PredicateObligation<'tcx> { |
f9f354fc XL |
1688 | assert!(!new_self_ty.has_escaping_bound_vars()); |
1689 | ||
5099ac24 FG |
1690 | let trait_pred = trait_ref.map_bound_ref(|tr| ty::TraitPredicate { |
1691 | trait_ref: ty::TraitRef { | |
1692 | substs: self.tcx.mk_substs_trait(new_self_ty, &tr.trait_ref.substs[1..]), | |
1693 | ..tr.trait_ref | |
1694 | }, | |
f9f354fc XL |
1695 | ..*tr |
1696 | }); | |
1697 | ||
5099ac24 | 1698 | Obligation::new(ObligationCause::dummy(), param_env, trait_pred.to_predicate(self.tcx)) |
ba9703b0 XL |
1699 | } |
1700 | ||
c295e0f8 | 1701 | #[instrument(skip(self), level = "debug")] |
ba9703b0 XL |
1702 | fn maybe_report_ambiguity( |
1703 | &self, | |
1704 | obligation: &PredicateObligation<'tcx>, | |
1705 | body_id: Option<hir::BodyId>, | |
1706 | ) { | |
1707 | // Unable to successfully determine, probably means | |
1708 | // insufficient type information, but could mean | |
1709 | // ambiguous impls. The latter *ought* to be a | |
1710 | // coherence violation, so we don't report it here. | |
1711 | ||
fc512014 | 1712 | let predicate = self.resolve_vars_if_possible(obligation.predicate); |
ba9703b0 XL |
1713 | let span = obligation.cause.span; |
1714 | ||
a2a8927a | 1715 | debug!(?predicate, obligation.cause.code = tracing::field::debug(&obligation.cause.code())); |
ba9703b0 | 1716 | |
3c0e092e XL |
1717 | // Ambiguity errors are often caused as fallout from earlier errors. |
1718 | // We ignore them if this `infcx` is tainted in some cases below. | |
ba9703b0 | 1719 | |
5869c6ff | 1720 | let bound_predicate = predicate.kind(); |
29967ef6 | 1721 | let mut err = match bound_predicate.skip_binder() { |
94222f64 | 1722 | ty::PredicateKind::Trait(data) => { |
29967ef6 | 1723 | let trait_ref = bound_predicate.rebind(data.trait_ref); |
c295e0f8 | 1724 | debug!(?trait_ref); |
ba9703b0 XL |
1725 | |
1726 | if predicate.references_error() { | |
1727 | return; | |
1728 | } | |
1729 | // Typically, this ambiguity should only happen if | |
1730 | // there are unresolved type inference variables | |
1731 | // (otherwise it would suggest a coherence | |
1732 | // failure). But given #21974 that is not necessarily | |
1733 | // the case -- we can have multiple where clauses that | |
1734 | // are only distinguished by a region, which results | |
1735 | // in an ambiguity even when all types are fully | |
1736 | // known, since we don't dispatch based on region | |
1737 | // relationships. | |
1738 | ||
29967ef6 XL |
1739 | // Pick the first substitution that still contains inference variables as the one |
1740 | // we're going to emit an error for. If there are none (see above), fall back to | |
1741 | // the substitution for `Self`. | |
1742 | let subst = { | |
1743 | let substs = data.trait_ref.substs; | |
1744 | substs | |
1745 | .iter() | |
1746 | .find(|s| s.has_infer_types_or_consts()) | |
1747 | .unwrap_or_else(|| substs[0]) | |
1748 | }; | |
1749 | ||
ba9703b0 XL |
1750 | // This is kind of a hack: it frequently happens that some earlier |
1751 | // error prevents types from being fully inferred, and then we get | |
1752 | // a bunch of uninteresting errors saying something like "<generic | |
1753 | // #0> doesn't implement Sized". It may even be true that we | |
1754 | // could just skip over all checks where the self-ty is an | |
1755 | // inference variable, but I was afraid that there might be an | |
1756 | // inference variable created, registered as an obligation, and | |
1757 | // then never forced by writeback, and hence by skipping here we'd | |
1758 | // be ignoring the fact that we don't KNOW the type works | |
1759 | // out. Though even that would probably be harmless, given that | |
1760 | // we're only talking about builtin traits, which are known to be | |
1761 | // inhabited. We used to check for `self.tcx.sess.has_errors()` to | |
1762 | // avoid inundating the user with unnecessary errors, but we now | |
1763 | // check upstream for type errors and don't add the obligations to | |
1764 | // begin with in those cases. | |
1b1a35ee | 1765 | if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) { |
3c0e092e XL |
1766 | if !self.is_tainted_by_errors() { |
1767 | self.emit_inference_failure_err( | |
1768 | body_id, | |
1769 | span, | |
1770 | subst, | |
1771 | vec![], | |
1772 | ErrorCode::E0282, | |
1773 | ) | |
5869c6ff | 1774 | .emit(); |
3c0e092e | 1775 | } |
ba9703b0 XL |
1776 | return; |
1777 | } | |
3c0e092e | 1778 | |
5099ac24 FG |
1779 | let impl_candidates = self |
1780 | .find_similar_impl_candidates(trait_ref) | |
1781 | .into_iter() | |
1782 | .map(|candidate| candidate.trait_ref) | |
1783 | .collect(); | |
5869c6ff XL |
1784 | let mut err = self.emit_inference_failure_err( |
1785 | body_id, | |
1786 | span, | |
1787 | subst, | |
1788 | impl_candidates, | |
1789 | ErrorCode::E0283, | |
1790 | ); | |
3c0e092e XL |
1791 | |
1792 | let obligation = Obligation::new( | |
1793 | obligation.cause.clone(), | |
1794 | obligation.param_env, | |
1795 | trait_ref.to_poly_trait_predicate(), | |
1796 | ); | |
1797 | let mut selcx = SelectionContext::with_query_mode( | |
1798 | &self, | |
1799 | crate::traits::TraitQueryMode::Standard, | |
1800 | ); | |
1801 | match selcx.select_from_obligation(&obligation) { | |
1802 | Err(SelectionError::Ambiguous(impls)) if impls.len() > 1 => { | |
1803 | self.annotate_source_of_ambiguity(&mut err, &impls, predicate); | |
1804 | } | |
1805 | _ => { | |
1806 | if self.is_tainted_by_errors() { | |
1807 | err.cancel(); | |
1808 | return; | |
1809 | } | |
1810 | err.note(&format!("cannot satisfy `{}`", predicate)); | |
1811 | } | |
1812 | } | |
1813 | ||
a2a8927a | 1814 | if let ObligationCauseCode::ItemObligation(def_id) = *obligation.cause.code() { |
ba9703b0 XL |
1815 | self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id()); |
1816 | } else if let ( | |
1817 | Ok(ref snippet), | |
1818 | ObligationCauseCode::BindingObligation(ref def_id, _), | |
1819 | ) = | |
a2a8927a | 1820 | (self.tcx.sess.source_map().span_to_snippet(span), obligation.cause.code()) |
ba9703b0 XL |
1821 | { |
1822 | let generics = self.tcx.generics_of(*def_id); | |
3dfed10e | 1823 | if generics.params.iter().any(|p| p.name != kw::SelfUpper) |
ba9703b0 | 1824 | && !snippet.ends_with('>') |
94222f64 XL |
1825 | && !generics.has_impl_trait() |
1826 | && !self.tcx.fn_trait_kind_from_lang_item(*def_id).is_some() | |
ba9703b0 XL |
1827 | { |
1828 | // FIXME: To avoid spurious suggestions in functions where type arguments | |
1829 | // where already supplied, we check the snippet to make sure it doesn't | |
1830 | // end with a turbofish. Ideally we would have access to a `PathSegment` | |
1831 | // instead. Otherwise we would produce the following output: | |
1832 | // | |
1833 | // error[E0283]: type annotations needed | |
1834 | // --> $DIR/issue-54954.rs:3:24 | |
1835 | // | | |
1836 | // LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>(); | |
1837 | // | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
1838 | // | | | |
1839 | // | cannot infer type | |
1840 | // | help: consider specifying the type argument | |
1841 | // | in the function call: | |
1842 | // | `Tt::const_val::<[i8; 123]>::<T>` | |
1843 | // ... | |
1844 | // LL | const fn const_val<T: Sized>() -> usize { | |
1845 | // | - required by this bound in `Tt::const_val` | |
1846 | // | | |
1847 | // = note: cannot satisfy `_: Tt` | |
1848 | ||
1849 | err.span_suggestion_verbose( | |
1850 | span.shrink_to_hi(), | |
1851 | &format!( | |
1852 | "consider specifying the type argument{} in the function call", | |
1853 | pluralize!(generics.params.len()), | |
1854 | ), | |
1855 | format!( | |
1856 | "::<{}>", | |
1857 | generics | |
1858 | .params | |
1859 | .iter() | |
1860 | .map(|p| p.name.to_string()) | |
1861 | .collect::<Vec<String>>() | |
1862 | .join(", ") | |
1863 | ), | |
1864 | Applicability::HasPlaceholders, | |
1865 | ); | |
1866 | } | |
1867 | } | |
1868 | err | |
1869 | } | |
1870 | ||
5869c6ff | 1871 | ty::PredicateKind::WellFormed(arg) => { |
ba9703b0 XL |
1872 | // Same hacky approach as above to avoid deluging user |
1873 | // with error messages. | |
3c0e092e XL |
1874 | if arg.references_error() |
1875 | || self.tcx.sess.has_errors() | |
1876 | || self.is_tainted_by_errors() | |
1877 | { | |
ba9703b0 XL |
1878 | return; |
1879 | } | |
f035d41b | 1880 | |
5869c6ff | 1881 | self.emit_inference_failure_err(body_id, span, arg, vec![], ErrorCode::E0282) |
ba9703b0 XL |
1882 | } |
1883 | ||
5869c6ff | 1884 | ty::PredicateKind::Subtype(data) => { |
3c0e092e XL |
1885 | if data.references_error() |
1886 | || self.tcx.sess.has_errors() | |
1887 | || self.is_tainted_by_errors() | |
1888 | { | |
ba9703b0 XL |
1889 | // no need to overload user in such cases |
1890 | return; | |
1891 | } | |
3dfed10e | 1892 | let SubtypePredicate { a_is_expected: _, a, b } = data; |
ba9703b0 XL |
1893 | // both must be type variables, or the other would've been instantiated |
1894 | assert!(a.is_ty_var() && b.is_ty_var()); | |
5869c6ff | 1895 | self.emit_inference_failure_err(body_id, span, a.into(), vec![], ErrorCode::E0282) |
ba9703b0 | 1896 | } |
5869c6ff | 1897 | ty::PredicateKind::Projection(data) => { |
6a06907d | 1898 | let self_ty = data.projection_ty.self_ty(); |
5099ac24 | 1899 | let term = data.term; |
3c0e092e | 1900 | if predicate.references_error() || self.is_tainted_by_errors() { |
ba9703b0 XL |
1901 | return; |
1902 | } | |
5099ac24 | 1903 | if self_ty.needs_infer() && term.needs_infer() { |
ba9703b0 | 1904 | // We do this for the `foo.collect()?` case to produce a suggestion. |
1b1a35ee XL |
1905 | let mut err = self.emit_inference_failure_err( |
1906 | body_id, | |
1907 | span, | |
1908 | self_ty.into(), | |
5869c6ff | 1909 | vec![], |
1b1a35ee XL |
1910 | ErrorCode::E0284, |
1911 | ); | |
ba9703b0 XL |
1912 | err.note(&format!("cannot satisfy `{}`", predicate)); |
1913 | err | |
1914 | } else { | |
1915 | let mut err = struct_span_err!( | |
1916 | self.tcx.sess, | |
1917 | span, | |
1918 | E0284, | |
1919 | "type annotations needed: cannot satisfy `{}`", | |
1920 | predicate, | |
1921 | ); | |
1922 | err.span_label(span, &format!("cannot satisfy `{}`", predicate)); | |
1923 | err | |
1924 | } | |
1925 | } | |
1926 | ||
1927 | _ => { | |
3c0e092e | 1928 | if self.tcx.sess.has_errors() || self.is_tainted_by_errors() { |
ba9703b0 XL |
1929 | return; |
1930 | } | |
1931 | let mut err = struct_span_err!( | |
1932 | self.tcx.sess, | |
1933 | span, | |
1934 | E0284, | |
1935 | "type annotations needed: cannot satisfy `{}`", | |
1936 | predicate, | |
1937 | ); | |
1938 | err.span_label(span, &format!("cannot satisfy `{}`", predicate)); | |
1939 | err | |
1940 | } | |
1941 | }; | |
1942 | self.note_obligation_cause(&mut err, obligation); | |
1943 | err.emit(); | |
1944 | } | |
1945 | ||
3c0e092e XL |
1946 | fn annotate_source_of_ambiguity( |
1947 | &self, | |
1948 | err: &mut DiagnosticBuilder<'tcx>, | |
1949 | impls: &[DefId], | |
1950 | predicate: ty::Predicate<'tcx>, | |
1951 | ) { | |
1952 | let mut spans = vec![]; | |
1953 | let mut crates = vec![]; | |
1954 | let mut post = vec![]; | |
1955 | for def_id in impls { | |
1956 | match self.tcx.span_of_impl(*def_id) { | |
1957 | Ok(span) => spans.push(self.tcx.sess.source_map().guess_head_span(span)), | |
1958 | Err(name) => { | |
1959 | crates.push(name); | |
1960 | if let Some(header) = to_pretty_impl_header(self.tcx, *def_id) { | |
1961 | post.push(header); | |
1962 | } | |
1963 | } | |
1964 | } | |
1965 | } | |
1966 | let msg = format!("multiple `impl`s satisfying `{}` found", predicate); | |
1967 | let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{}`", n)).collect(); | |
1968 | crate_names.sort(); | |
1969 | crate_names.dedup(); | |
1970 | post.sort(); | |
1971 | post.dedup(); | |
1972 | ||
1973 | if self.is_tainted_by_errors() | |
1974 | && crate_names.len() == 1 | |
1975 | && crate_names[0] == "`core`" | |
1976 | && spans.len() == 0 | |
1977 | { | |
1978 | // Avoid complaining about other inference issues for expressions like | |
1979 | // `42 >> 1`, where the types are still `{integer}`, but we want to | |
1980 | // Do we need `trait_ref.skip_binder().self_ty().is_numeric() &&` too? | |
1981 | err.cancel(); | |
1982 | return; | |
1983 | } | |
1984 | let post = if post.len() > 4 { | |
1985 | format!( | |
1986 | ":\n{}\nand {} more", | |
1987 | post.iter().map(|p| format!("- {}", p)).take(4).collect::<Vec<_>>().join("\n"), | |
1988 | post.len() - 4, | |
1989 | ) | |
1990 | } else if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) { | |
1991 | format!(":\n{}", post.iter().map(|p| format!("- {}", p)).collect::<Vec<_>>().join("\n"),) | |
1992 | } else if post.len() == 1 { | |
1993 | format!(": `{}`", post[0]) | |
1994 | } else { | |
1995 | String::new() | |
1996 | }; | |
1997 | ||
1998 | match (spans.len(), crates.len(), crate_names.len()) { | |
1999 | (0, 0, 0) => { | |
2000 | err.note(&format!("cannot satisfy `{}`", predicate)); | |
2001 | } | |
2002 | (0, _, 1) => { | |
2003 | err.note(&format!("{} in the `{}` crate{}", msg, crates[0], post,)); | |
2004 | } | |
2005 | (0, _, _) => { | |
2006 | err.note(&format!( | |
2007 | "{} in the following crates: {}{}", | |
2008 | msg, | |
2009 | crate_names.join(", "), | |
2010 | post, | |
2011 | )); | |
2012 | } | |
2013 | (_, 0, 0) => { | |
2014 | let span: MultiSpan = spans.into(); | |
2015 | err.span_note(span, &msg); | |
2016 | } | |
2017 | (_, 1, 1) => { | |
2018 | let span: MultiSpan = spans.into(); | |
2019 | err.span_note(span, &msg); | |
2020 | err.note( | |
2021 | &format!("and another `impl` found in the `{}` crate{}", crates[0], post,), | |
2022 | ); | |
2023 | } | |
2024 | _ => { | |
2025 | let span: MultiSpan = spans.into(); | |
2026 | err.span_note(span, &msg); | |
2027 | err.note(&format!( | |
2028 | "and more `impl`s found in the following crates: {}{}", | |
2029 | crate_names.join(", "), | |
2030 | post, | |
2031 | )); | |
2032 | } | |
2033 | } | |
2034 | } | |
2035 | ||
ba9703b0 XL |
2036 | /// Returns `true` if the trait predicate may apply for *some* assignment |
2037 | /// to the type parameters. | |
2038 | fn predicate_can_apply( | |
2039 | &self, | |
2040 | param_env: ty::ParamEnv<'tcx>, | |
2041 | pred: ty::PolyTraitRef<'tcx>, | |
2042 | ) -> bool { | |
2043 | struct ParamToVarFolder<'a, 'tcx> { | |
2044 | infcx: &'a InferCtxt<'a, 'tcx>, | |
2045 | var_map: FxHashMap<Ty<'tcx>, Ty<'tcx>>, | |
2046 | } | |
2047 | ||
2048 | impl<'a, 'tcx> TypeFolder<'tcx> for ParamToVarFolder<'a, 'tcx> { | |
2049 | fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { | |
2050 | self.infcx.tcx | |
2051 | } | |
2052 | ||
2053 | fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { | |
1b1a35ee | 2054 | if let ty::Param(ty::ParamTy { name, .. }) = *ty.kind() { |
ba9703b0 | 2055 | let infcx = self.infcx; |
5099ac24 | 2056 | *self.var_map.entry(ty).or_insert_with(|| { |
ba9703b0 XL |
2057 | infcx.next_ty_var(TypeVariableOrigin { |
2058 | kind: TypeVariableOriginKind::TypeParameterDefinition(name, None), | |
2059 | span: DUMMY_SP, | |
2060 | }) | |
2061 | }) | |
2062 | } else { | |
2063 | ty.super_fold_with(self) | |
2064 | } | |
2065 | } | |
2066 | } | |
2067 | ||
2068 | self.probe(|_| { | |
2069 | let mut selcx = SelectionContext::new(self); | |
2070 | ||
2071 | let cleaned_pred = | |
2072 | pred.fold_with(&mut ParamToVarFolder { infcx: self, var_map: Default::default() }); | |
2073 | ||
2074 | let cleaned_pred = super::project::normalize( | |
2075 | &mut selcx, | |
2076 | param_env, | |
2077 | ObligationCause::dummy(), | |
fc512014 | 2078 | cleaned_pred, |
ba9703b0 XL |
2079 | ) |
2080 | .value; | |
2081 | ||
2082 | let obligation = Obligation::new( | |
2083 | ObligationCause::dummy(), | |
2084 | param_env, | |
f9f354fc | 2085 | cleaned_pred.without_const().to_predicate(selcx.tcx()), |
ba9703b0 XL |
2086 | ); |
2087 | ||
2088 | self.predicate_may_hold(&obligation) | |
2089 | }) | |
2090 | } | |
2091 | ||
2092 | fn note_obligation_cause( | |
2093 | &self, | |
f9f354fc | 2094 | err: &mut DiagnosticBuilder<'tcx>, |
ba9703b0 XL |
2095 | obligation: &PredicateObligation<'tcx>, |
2096 | ) { | |
2097 | // First, attempt to add note to this error with an async-await-specific | |
2098 | // message, and fall back to regular note otherwise. | |
2099 | if !self.maybe_note_obligation_cause_for_async_await(err, obligation) { | |
2100 | self.note_obligation_cause_code( | |
2101 | err, | |
2102 | &obligation.predicate, | |
5099ac24 | 2103 | obligation.param_env, |
a2a8927a | 2104 | obligation.cause.code(), |
ba9703b0 | 2105 | &mut vec![], |
fc512014 | 2106 | &mut Default::default(), |
ba9703b0 XL |
2107 | ); |
2108 | self.suggest_unsized_bound_if_applicable(err, obligation); | |
2109 | } | |
2110 | } | |
2111 | ||
2112 | fn suggest_unsized_bound_if_applicable( | |
2113 | &self, | |
f9f354fc | 2114 | err: &mut DiagnosticBuilder<'tcx>, |
ba9703b0 XL |
2115 | obligation: &PredicateObligation<'tcx>, |
2116 | ) { | |
a2a8927a XL |
2117 | let (pred, item_def_id, span) = match ( |
2118 | obligation.predicate.kind().skip_binder(), | |
2119 | obligation.cause.code().peel_derives(), | |
2120 | ) { | |
2121 | ( | |
2122 | ty::PredicateKind::Trait(pred), | |
2123 | &ObligationCauseCode::BindingObligation(item_def_id, span), | |
2124 | ) => (pred, item_def_id, span), | |
2125 | _ => return, | |
2126 | }; | |
94222f64 XL |
2127 | debug!( |
2128 | "suggest_unsized_bound_if_applicable: pred={:?} item_def_id={:?} span={:?}", | |
2129 | pred, item_def_id, span | |
2130 | ); | |
f035d41b | 2131 | let node = match ( |
3dfed10e | 2132 | self.tcx.hir().get_if_local(item_def_id), |
f035d41b XL |
2133 | Some(pred.def_id()) == self.tcx.lang_items().sized_trait(), |
2134 | ) { | |
2135 | (Some(node), true) => node, | |
2136 | _ => return, | |
2137 | }; | |
94222f64 XL |
2138 | self.maybe_suggest_unsized_generics(err, span, node); |
2139 | } | |
2140 | ||
a2a8927a | 2141 | fn maybe_suggest_unsized_generics<'hir>( |
94222f64 XL |
2142 | &self, |
2143 | err: &mut DiagnosticBuilder<'tcx>, | |
2144 | span: Span, | |
2145 | node: Node<'hir>, | |
2146 | ) { | |
f035d41b XL |
2147 | let generics = match node.generics() { |
2148 | Some(generics) => generics, | |
2149 | None => return, | |
2150 | }; | |
94222f64 XL |
2151 | let sized_trait = self.tcx.lang_items().sized_trait(); |
2152 | debug!("maybe_suggest_unsized_generics: generics.params={:?}", generics.params); | |
2153 | debug!("maybe_suggest_unsized_generics: generics.where_clause={:?}", generics.where_clause); | |
3c0e092e XL |
2154 | let param = generics.params.iter().filter(|param| param.span == span).find(|param| { |
2155 | // Check that none of the explicit trait bounds is `Sized`. Assume that an explicit | |
2156 | // `Sized` bound is there intentionally and we don't need to suggest relaxing it. | |
2157 | param | |
2158 | .bounds | |
2159 | .iter() | |
2160 | .all(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) != sized_trait) | |
2161 | }); | |
94222f64 XL |
2162 | let param = match param { |
2163 | Some(param) => param, | |
2164 | _ => return, | |
2165 | }; | |
3c0e092e XL |
2166 | let param_def_id = self.tcx.hir().local_def_id(param.hir_id).to_def_id(); |
2167 | let preds = generics.where_clause.predicates.iter(); | |
2168 | let explicitly_sized = preds | |
2169 | .filter_map(|pred| match pred { | |
2170 | hir::WherePredicate::BoundPredicate(bp) => Some(bp), | |
2171 | _ => None, | |
2172 | }) | |
2173 | .filter(|bp| bp.is_param_bound(param_def_id)) | |
2174 | .flat_map(|bp| bp.bounds) | |
2175 | .any(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) == sized_trait); | |
2176 | if explicitly_sized { | |
2177 | return; | |
2178 | } | |
94222f64 XL |
2179 | debug!("maybe_suggest_unsized_generics: param={:?}", param); |
2180 | match node { | |
2181 | hir::Node::Item( | |
a2a8927a | 2182 | item @ hir::Item { |
94222f64 XL |
2183 | // Only suggest indirection for uses of type parameters in ADTs. |
2184 | kind: | |
2185 | hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Union(..), | |
2186 | .. | |
2187 | }, | |
2188 | ) => { | |
2189 | if self.maybe_indirection_for_unsized(err, item, param) { | |
2190 | return; | |
ba9703b0 XL |
2191 | } |
2192 | } | |
94222f64 XL |
2193 | _ => {} |
2194 | }; | |
2195 | // Didn't add an indirection suggestion, so add a general suggestion to relax `Sized`. | |
2196 | let (span, separator) = match param.bounds { | |
2197 | [] => (span.shrink_to_hi(), ":"), | |
2198 | [.., bound] => (bound.span().shrink_to_hi(), " +"), | |
2199 | }; | |
2200 | err.span_suggestion_verbose( | |
2201 | span, | |
2202 | "consider relaxing the implicit `Sized` restriction", | |
2203 | format!("{} ?Sized", separator), | |
2204 | Applicability::MachineApplicable, | |
2205 | ); | |
2206 | } | |
2207 | ||
a2a8927a | 2208 | fn maybe_indirection_for_unsized<'hir>( |
94222f64 XL |
2209 | &self, |
2210 | err: &mut DiagnosticBuilder<'tcx>, | |
2211 | item: &'hir Item<'hir>, | |
2212 | param: &'hir GenericParam<'hir>, | |
2213 | ) -> bool { | |
2214 | // Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a | |
2215 | // borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S<T: ?Sized>(T);` | |
2216 | // is not. Look for invalid "bare" parameter uses, and suggest using indirection. | |
2217 | let mut visitor = | |
2218 | FindTypeParam { param: param.name.ident().name, invalid_spans: vec![], nested: false }; | |
2219 | visitor.visit_item(item); | |
2220 | if visitor.invalid_spans.is_empty() { | |
2221 | return false; | |
2222 | } | |
2223 | let mut multispan: MultiSpan = param.span.into(); | |
2224 | multispan.push_span_label( | |
2225 | param.span, | |
2226 | format!("this could be changed to `{}: ?Sized`...", param.name.ident()), | |
2227 | ); | |
2228 | for sp in visitor.invalid_spans { | |
2229 | multispan.push_span_label( | |
2230 | sp, | |
2231 | format!("...if indirection were used here: `Box<{}>`", param.name.ident()), | |
f035d41b | 2232 | ); |
ba9703b0 | 2233 | } |
94222f64 XL |
2234 | err.span_help( |
2235 | multispan, | |
2236 | &format!( | |
2237 | "you could relax the implicit `Sized` bound on `{T}` if it were \ | |
2238 | used through indirection like `&{T}` or `Box<{T}>`", | |
2239 | T = param.name.ident(), | |
2240 | ), | |
2241 | ); | |
2242 | true | |
ba9703b0 XL |
2243 | } |
2244 | ||
2245 | fn is_recursive_obligation( | |
2246 | &self, | |
5099ac24 | 2247 | obligated_types: &mut Vec<Ty<'tcx>>, |
ba9703b0 XL |
2248 | cause_code: &ObligationCauseCode<'tcx>, |
2249 | ) -> bool { | |
2250 | if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = cause_code { | |
5099ac24 | 2251 | let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); |
a2a8927a XL |
2252 | let self_ty = parent_trait_ref.skip_binder().self_ty(); |
2253 | if obligated_types.iter().any(|ot| ot == &self_ty) { | |
ba9703b0 XL |
2254 | return true; |
2255 | } | |
a2a8927a XL |
2256 | if let ty::Adt(def, substs) = self_ty.kind() { |
2257 | if let [arg] = &substs[..] { | |
2258 | if let ty::subst::GenericArgKind::Type(ty) = arg.unpack() { | |
2259 | if let ty::Adt(inner_def, _) = ty.kind() { | |
2260 | if inner_def == def { | |
2261 | return true; | |
2262 | } | |
2263 | } | |
2264 | } | |
2265 | } | |
2266 | } | |
ba9703b0 XL |
2267 | } |
2268 | false | |
2269 | } | |
2270 | } | |
2271 | ||
f035d41b XL |
2272 | /// Look for type `param` in an ADT being used only through a reference to confirm that suggesting |
2273 | /// `param: ?Sized` would be a valid constraint. | |
2274 | struct FindTypeParam { | |
2275 | param: rustc_span::Symbol, | |
2276 | invalid_spans: Vec<Span>, | |
2277 | nested: bool, | |
2278 | } | |
2279 | ||
2280 | impl<'v> Visitor<'v> for FindTypeParam { | |
17df50a5 XL |
2281 | fn visit_where_predicate(&mut self, _: &'v hir::WherePredicate<'v>) { |
2282 | // Skip where-clauses, to avoid suggesting indirection for type parameters found there. | |
2283 | } | |
2284 | ||
f035d41b XL |
2285 | fn visit_ty(&mut self, ty: &hir::Ty<'_>) { |
2286 | // We collect the spans of all uses of the "bare" type param, like in `field: T` or | |
2287 | // `field: (T, T)` where we could make `T: ?Sized` while skipping cases that are known to be | |
2288 | // valid like `field: &'a T` or `field: *mut T` and cases that *might* have further `Sized` | |
2289 | // obligations like `Box<T>` and `Vec<T>`, but we perform no extra analysis for those cases | |
2290 | // and suggest `T: ?Sized` regardless of their obligations. This is fine because the errors | |
2291 | // in that case should make what happened clear enough. | |
2292 | match ty.kind { | |
2293 | hir::TyKind::Ptr(_) | hir::TyKind::Rptr(..) | hir::TyKind::TraitObject(..) => {} | |
2294 | hir::TyKind::Path(hir::QPath::Resolved(None, path)) | |
2295 | if path.segments.len() == 1 && path.segments[0].ident.name == self.param => | |
2296 | { | |
2297 | if !self.nested { | |
94222f64 | 2298 | debug!("FindTypeParam::visit_ty: ty={:?}", ty); |
f035d41b XL |
2299 | self.invalid_spans.push(ty.span); |
2300 | } | |
2301 | } | |
2302 | hir::TyKind::Path(_) => { | |
2303 | let prev = self.nested; | |
2304 | self.nested = true; | |
2305 | hir::intravisit::walk_ty(self, ty); | |
2306 | self.nested = prev; | |
2307 | } | |
2308 | _ => { | |
2309 | hir::intravisit::walk_ty(self, ty); | |
2310 | } | |
2311 | } | |
2312 | } | |
2313 | } | |
2314 | ||
ba9703b0 | 2315 | pub fn recursive_type_with_infinite_size_error( |
a2a8927a | 2316 | tcx: TyCtxt<'_>, |
ba9703b0 | 2317 | type_def_id: DefId, |
f035d41b XL |
2318 | spans: Vec<Span>, |
2319 | ) { | |
ba9703b0 XL |
2320 | assert!(type_def_id.is_local()); |
2321 | let span = tcx.hir().span_if_local(type_def_id).unwrap(); | |
2322 | let span = tcx.sess.source_map().guess_head_span(span); | |
f035d41b XL |
2323 | let path = tcx.def_path_str(type_def_id); |
2324 | let mut err = | |
2325 | struct_span_err!(tcx.sess, span, E0072, "recursive type `{}` has infinite size", path); | |
ba9703b0 | 2326 | err.span_label(span, "recursive type has infinite size"); |
f035d41b XL |
2327 | for &span in &spans { |
2328 | err.span_label(span, "recursive without indirection"); | |
2329 | } | |
2330 | let msg = format!( | |
2331 | "insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `{}` representable", | |
2332 | path, | |
2333 | ); | |
2334 | if spans.len() <= 4 { | |
2335 | err.multipart_suggestion( | |
2336 | &msg, | |
2337 | spans | |
2338 | .iter() | |
2339 | .flat_map(|&span| { | |
5099ac24 | 2340 | [ |
f035d41b XL |
2341 | (span.shrink_to_lo(), "Box<".to_string()), |
2342 | (span.shrink_to_hi(), ">".to_string()), | |
2343 | ] | |
2344 | .into_iter() | |
2345 | }) | |
2346 | .collect(), | |
2347 | Applicability::HasPlaceholders, | |
2348 | ); | |
2349 | } else { | |
2350 | err.help(&msg); | |
2351 | } | |
2352 | err.emit(); | |
ba9703b0 XL |
2353 | } |
2354 | ||
2355 | /// Summarizes information | |
2356 | #[derive(Clone)] | |
2357 | pub enum ArgKind { | |
2358 | /// An argument of non-tuple type. Parameters are (name, ty) | |
2359 | Arg(String, String), | |
2360 | ||
2361 | /// An argument of tuple type. For a "found" argument, the span is | |
94222f64 | 2362 | /// the location in the source of the pattern. For an "expected" |
ba9703b0 XL |
2363 | /// argument, it will be None. The vector is a list of (name, ty) |
2364 | /// strings for the components of the tuple. | |
2365 | Tuple(Option<Span>, Vec<(String, String)>), | |
2366 | } | |
2367 | ||
2368 | impl ArgKind { | |
2369 | fn empty() -> ArgKind { | |
2370 | ArgKind::Arg("_".to_owned(), "_".to_owned()) | |
2371 | } | |
2372 | ||
2373 | /// Creates an `ArgKind` from the expected type of an | |
2374 | /// argument. It has no name (`_`) and an optional source span. | |
2375 | pub fn from_expected_ty(t: Ty<'_>, span: Option<Span>) -> ArgKind { | |
1b1a35ee XL |
2376 | match t.kind() { |
2377 | ty::Tuple(tys) => ArgKind::Tuple( | |
ba9703b0 XL |
2378 | span, |
2379 | tys.iter().map(|ty| ("_".to_owned(), ty.to_string())).collect::<Vec<_>>(), | |
2380 | ), | |
2381 | _ => ArgKind::Arg("_".to_owned(), t.to_string()), | |
2382 | } | |
2383 | } | |
2384 | } |