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