]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | //! Error Reporting Code for the inference engine |
2 | //! | |
3 | //! Because of the way inference, and in particular region inference, | |
4 | //! works, it often happens that errors are not detected until far after | |
5 | //! the relevant line of code has been type-checked. Therefore, there is | |
6 | //! an elaborate system to track why a particular constraint in the | |
7 | //! inference graph arose so that we can explain to the user what gave | |
8 | //! rise to a particular error. | |
9 | //! | |
10 | //! The basis of the system are the "origin" types. An "origin" is the | |
11 | //! reason that a constraint or inference variable arose. There are | |
12 | //! different "origin" enums for different kinds of constraints/variables | |
13 | //! (e.g., `TypeOrigin`, `RegionVariableOrigin`). An origin always has | |
14 | //! a span, but also more information so that we can generate a meaningful | |
15 | //! error message. | |
16 | //! | |
3b2f2976 | 17 | //! Having a catalog of all the different reasons an error can arise is |
1a4d82fc JJ |
18 | //! also useful for other reasons, like cross-referencing FAQs etc, though |
19 | //! we are not really taking advantage of this yet. | |
20 | //! | |
21 | //! # Region Inference | |
22 | //! | |
23 | //! Region inference is particularly tricky because it always succeeds "in | |
24 | //! the moment" and simply registers a constraint. Then, at the end, we | |
25 | //! can compute the full graph and report errors, so we need to be able to | |
26 | //! store and later report what gave rise to the conflicting constraints. | |
27 | //! | |
28 | //! # Subtype Trace | |
29 | //! | |
30 | //! Determining whether `T1 <: T2` often involves a number of subtypes and | |
31 | //! subconstraints along the way. A "TypeTrace" is an extended version | |
32 | //! of an origin that traces the types and other values that were being | |
33 | //! compared. It is not necessarily comprehensive (in fact, at the time of | |
34 | //! this writing it only tracks the root values being compared) but I'd | |
35 | //! like to extend it to include significant "waypoints". For example, if | |
36 | //! you are comparing `(T1, T2) <: (T3, T4)`, and the problem is that `T2 | |
37 | //! <: T4` fails, I'd like the trace to include enough information to say | |
38 | //! "in the 2nd element of the tuple". Similarly, failures when comparing | |
39 | //! arguments or return types in fn types should be able to cite the | |
40 | //! specific position, etc. | |
41 | //! | |
42 | //! # Reality vs plan | |
43 | //! | |
44 | //! Of course, there is still a LOT of code in typeck that has yet to be | |
45 | //! ported to this system, and which relies on string concatenation at the | |
46 | //! time of error detection. | |
47 | ||
abe05a73 | 48 | use super::lexical_region_resolve::RegionResolutionError; |
0bf4aa26 XL |
49 | use super::region_constraints::GenericKind; |
50 | use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs}; | |
9fa01778 | 51 | |
ba9703b0 | 52 | use crate::infer; |
dfeec247 | 53 | use crate::traits::error_reporting::report_object_safety_error; |
60c5eb7d XL |
54 | use crate::traits::{ |
55 | IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, | |
56 | }; | |
74b04a01 | 57 | |
dfeec247 XL |
58 | use rustc_data_structures::fx::{FxHashMap, FxHashSet}; |
59 | use rustc_errors::{pluralize, struct_span_err}; | |
60 | use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString}; | |
61 | use rustc_hir as hir; | |
62 | use rustc_hir::def_id::DefId; | |
f9f354fc | 63 | use rustc_hir::{Item, ItemKind, Node}; |
ba9703b0 XL |
64 | use rustc_middle::ty::error::TypeError; |
65 | use rustc_middle::ty::{ | |
66 | self, | |
67 | subst::{Subst, SubstsRef}, | |
68 | Region, Ty, TyCtxt, TypeFoldable, | |
69 | }; | |
dfeec247 | 70 | use rustc_span::{DesugaringKind, Pos, Span}; |
60c5eb7d | 71 | use rustc_target::spec::abi; |
60c5eb7d | 72 | use std::{cmp, fmt}; |
1a4d82fc | 73 | |
8bb4bdeb XL |
74 | mod note; |
75 | ||
041b39d2 | 76 | mod need_type_info; |
60c5eb7d | 77 | pub use need_type_info::TypeAnnotationNeeded; |
3b2f2976 | 78 | |
ff7c6d11 | 79 | pub mod nice_region_error; |
041b39d2 | 80 | |
dfeec247 XL |
81 | pub(super) fn note_and_explain_region( |
82 | tcx: TyCtxt<'tcx>, | |
dfeec247 XL |
83 | err: &mut DiagnosticBuilder<'_>, |
84 | prefix: &str, | |
85 | region: ty::Region<'tcx>, | |
86 | suffix: &str, | |
87 | ) { | |
88 | let (description, span) = match *region { | |
dfeec247 XL |
89 | ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic => { |
90 | msg_span_from_free_region(tcx, region) | |
91 | } | |
62682a34 | 92 | |
74b04a01 XL |
93 | ty::ReEmpty(ty::UniverseIndex::ROOT) => ("the empty lifetime".to_owned(), None), |
94 | ||
95 | // uh oh, hope no user ever sees THIS | |
96 | ty::ReEmpty(ui) => (format!("the empty lifetime in universe {:?}", ui), None), | |
62682a34 | 97 | |
74b04a01 | 98 | ty::RePlaceholder(_) => ("any other region".to_string(), None), |
0731742a | 99 | |
dfeec247 XL |
100 | // FIXME(#13998) RePlaceholder should probably print like |
101 | // ReFree rather than dumping Debug output on the user. | |
102 | // | |
103 | // We shouldn't really be having unification failures with ReVar | |
104 | // and ReLateBound though. | |
105 | ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => { | |
106 | (format!("lifetime {:?}", region), None) | |
107 | } | |
dfeec247 | 108 | }; |
0531ce1d | 109 | |
dfeec247 XL |
110 | emit_msg_span(err, prefix, description, span, suffix); |
111 | } | |
0531ce1d | 112 | |
dfeec247 XL |
113 | pub(super) fn note_and_explain_free_region( |
114 | tcx: TyCtxt<'tcx>, | |
115 | err: &mut DiagnosticBuilder<'_>, | |
116 | prefix: &str, | |
117 | region: ty::Region<'tcx>, | |
118 | suffix: &str, | |
119 | ) { | |
120 | let (description, span) = msg_span_from_free_region(tcx, region); | |
0531ce1d | 121 | |
dfeec247 XL |
122 | emit_msg_span(err, prefix, description, span, suffix); |
123 | } | |
0531ce1d | 124 | |
dfeec247 XL |
125 | fn msg_span_from_free_region( |
126 | tcx: TyCtxt<'tcx>, | |
127 | region: ty::Region<'tcx>, | |
128 | ) -> (String, Option<Span>) { | |
129 | match *region { | |
130 | ty::ReEarlyBound(_) | ty::ReFree(_) => { | |
131 | msg_span_from_early_bound_and_free_regions(tcx, region) | |
0531ce1d | 132 | } |
dfeec247 | 133 | ty::ReStatic => ("the static lifetime".to_owned(), None), |
74b04a01 XL |
134 | ty::ReEmpty(ty::UniverseIndex::ROOT) => ("an empty lifetime".to_owned(), None), |
135 | ty::ReEmpty(ui) => (format!("an empty lifetime in universe {:?}", ui), None), | |
dfeec247 | 136 | _ => bug!("{:?}", region), |
0531ce1d | 137 | } |
dfeec247 | 138 | } |
0531ce1d | 139 | |
dfeec247 XL |
140 | fn msg_span_from_early_bound_and_free_regions( |
141 | tcx: TyCtxt<'tcx>, | |
142 | region: ty::Region<'tcx>, | |
143 | ) -> (String, Option<Span>) { | |
74b04a01 | 144 | let sm = tcx.sess.source_map(); |
dfeec247 XL |
145 | |
146 | let scope = region.free_region_binding_scope(tcx); | |
f9f354fc | 147 | let node = tcx.hir().as_local_hir_id(scope.expect_local()); |
dfeec247 | 148 | let tag = match tcx.hir().find(node) { |
ba9703b0 | 149 | Some(Node::Block(_) | Node::Expr(_)) => "body", |
dfeec247 XL |
150 | Some(Node::Item(it)) => item_scope_tag(&it), |
151 | Some(Node::TraitItem(it)) => trait_item_scope_tag(&it), | |
152 | Some(Node::ImplItem(it)) => impl_item_scope_tag(&it), | |
153 | _ => unreachable!(), | |
154 | }; | |
155 | let (prefix, span) = match *region { | |
156 | ty::ReEarlyBound(ref br) => { | |
ba9703b0 | 157 | let mut sp = sm.guess_head_span(tcx.hir().span(node)); |
dfeec247 XL |
158 | if let Some(param) = |
159 | tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name)) | |
160 | { | |
161 | sp = param.span; | |
8faf50e0 | 162 | } |
dfeec247 | 163 | (format!("the lifetime `{}` as defined on", br.name), sp) |
62682a34 | 164 | } |
dfeec247 | 165 | ty::ReFree(ty::FreeRegion { bound_region: ty::BoundRegion::BrNamed(_, name), .. }) => { |
ba9703b0 | 166 | let mut sp = sm.guess_head_span(tcx.hir().span(node)); |
dfeec247 XL |
167 | if let Some(param) = |
168 | tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name)) | |
169 | { | |
170 | sp = param.span; | |
171 | } | |
172 | (format!("the lifetime `{}` as defined on", name), sp) | |
0531ce1d | 173 | } |
dfeec247 XL |
174 | ty::ReFree(ref fr) => match fr.bound_region { |
175 | ty::BrAnon(idx) => { | |
176 | (format!("the anonymous lifetime #{} defined on", idx + 1), tcx.hir().span(node)) | |
177 | } | |
178 | _ => ( | |
179 | format!("the lifetime `{}` as defined on", region), | |
ba9703b0 | 180 | sm.guess_head_span(tcx.hir().span(node)), |
dfeec247 XL |
181 | ), |
182 | }, | |
183 | _ => bug!(), | |
184 | }; | |
185 | let (msg, opt_span) = explain_span(tcx, tag, span); | |
186 | (format!("{} {}", prefix, msg), opt_span) | |
187 | } | |
188 | ||
189 | fn emit_msg_span( | |
190 | err: &mut DiagnosticBuilder<'_>, | |
191 | prefix: &str, | |
192 | description: String, | |
193 | span: Option<Span>, | |
194 | suffix: &str, | |
195 | ) { | |
196 | let message = format!("{}{}{}", prefix, description, suffix); | |
197 | ||
198 | if let Some(span) = span { | |
199 | err.span_note(span, &message); | |
200 | } else { | |
201 | err.note(&message); | |
0531ce1d | 202 | } |
dfeec247 | 203 | } |
0531ce1d | 204 | |
dfeec247 XL |
205 | fn item_scope_tag(item: &hir::Item<'_>) -> &'static str { |
206 | match item.kind { | |
207 | hir::ItemKind::Impl { .. } => "impl", | |
208 | hir::ItemKind::Struct(..) => "struct", | |
209 | hir::ItemKind::Union(..) => "union", | |
210 | hir::ItemKind::Enum(..) => "enum", | |
211 | hir::ItemKind::Trait(..) => "trait", | |
212 | hir::ItemKind::Fn(..) => "function body", | |
213 | _ => "item", | |
0531ce1d | 214 | } |
dfeec247 | 215 | } |
0531ce1d | 216 | |
dfeec247 XL |
217 | fn trait_item_scope_tag(item: &hir::TraitItem<'_>) -> &'static str { |
218 | match item.kind { | |
ba9703b0 | 219 | hir::TraitItemKind::Fn(..) => "method body", |
dfeec247 | 220 | hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => "associated item", |
0531ce1d | 221 | } |
dfeec247 | 222 | } |
0531ce1d | 223 | |
dfeec247 XL |
224 | fn impl_item_scope_tag(item: &hir::ImplItem<'_>) -> &'static str { |
225 | match item.kind { | |
ba9703b0 | 226 | hir::ImplItemKind::Fn(..) => "method body", |
dfeec247 XL |
227 | hir::ImplItemKind::Const(..) |
228 | | hir::ImplItemKind::OpaqueTy(..) | |
229 | | hir::ImplItemKind::TyAlias(..) => "associated item", | |
0531ce1d | 230 | } |
62682a34 | 231 | } |
1a4d82fc | 232 | |
dfeec247 XL |
233 | fn explain_span(tcx: TyCtxt<'tcx>, heading: &str, span: Span) -> (String, Option<Span>) { |
234 | let lo = tcx.sess.source_map().lookup_char_pos(span.lo()); | |
235 | (format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize() + 1), Some(span)) | |
236 | } | |
237 | ||
ba9703b0 XL |
238 | pub fn unexpected_hidden_region_diagnostic( |
239 | tcx: TyCtxt<'tcx>, | |
ba9703b0 XL |
240 | span: Span, |
241 | hidden_ty: Ty<'tcx>, | |
242 | hidden_region: ty::Region<'tcx>, | |
243 | ) -> DiagnosticBuilder<'tcx> { | |
244 | let mut err = struct_span_err!( | |
245 | tcx.sess, | |
246 | span, | |
247 | E0700, | |
248 | "hidden type for `impl Trait` captures lifetime that does not appear in bounds", | |
249 | ); | |
250 | ||
251 | // Explain the region we are capturing. | |
f9f354fc XL |
252 | match hidden_region { |
253 | ty::ReEmpty(ty::UniverseIndex::ROOT) => { | |
254 | // All lifetimes shorter than the function body are `empty` in | |
255 | // lexical region resolution. The default explanation of "an empty | |
256 | // lifetime" isn't really accurate here. | |
257 | let message = format!( | |
258 | "hidden type `{}` captures lifetime smaller than the function body", | |
259 | hidden_ty | |
260 | ); | |
261 | err.span_note(span, &message); | |
262 | } | |
263 | ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic | ty::ReEmpty(_) => { | |
264 | // Assuming regionck succeeded (*), we ought to always be | |
265 | // capturing *some* region from the fn header, and hence it | |
266 | // ought to be free. So under normal circumstances, we will go | |
267 | // down this path which gives a decent human readable | |
268 | // explanation. | |
269 | // | |
270 | // (*) if not, the `tainted_by_errors` field would be set to | |
271 | // `Some(ErrorReported)` in any case, so we wouldn't be here at all. | |
272 | note_and_explain_free_region( | |
ba9703b0 | 273 | tcx, |
ba9703b0 XL |
274 | &mut err, |
275 | &format!("hidden type `{}` captures ", hidden_ty), | |
276 | hidden_region, | |
277 | "", | |
278 | ); | |
f9f354fc XL |
279 | } |
280 | _ => { | |
281 | // Ugh. This is a painful case: the hidden region is not one | |
282 | // that we can easily summarize or explain. This can happen | |
283 | // in a case like | |
284 | // `src/test/ui/multiple-lifetimes/ordinary-bounds-unsuited.rs`: | |
285 | // | |
286 | // ``` | |
287 | // fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> { | |
288 | // if condition() { a } else { b } | |
289 | // } | |
290 | // ``` | |
291 | // | |
292 | // Here the captured lifetime is the intersection of `'a` and | |
293 | // `'b`, which we can't quite express. | |
294 | ||
295 | // We can at least report a really cryptic error for now. | |
296 | note_and_explain_region( | |
297 | tcx, | |
298 | &mut err, | |
299 | &format!("hidden type `{}` captures ", hidden_ty), | |
300 | hidden_region, | |
301 | "", | |
ba9703b0 XL |
302 | ); |
303 | } | |
304 | } | |
305 | ||
306 | err | |
307 | } | |
308 | ||
dc9dc135 | 309 | impl<'a, 'tcx> InferCtxt<'a, 'tcx> { |
f9f354fc | 310 | pub fn report_region_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>) { |
ba9703b0 | 311 | debug!("report_region_errors(): {} errors to start", errors.len()); |
abe05a73 | 312 | |
54a0048b SL |
313 | // try to pre-process the errors, which will group some of them |
314 | // together into a `ProcessedErrors` group: | |
32a655c1 | 315 | let errors = self.process_errors(errors); |
54a0048b | 316 | |
dfeec247 | 317 | debug!("report_region_errors: {} errors after preprocessing", errors.len()); |
54a0048b | 318 | |
85aaf69f | 319 | for error in errors { |
c30ab7b3 | 320 | debug!("report_region_errors: error = {:?}", error); |
1a4d82fc | 321 | |
ff7c6d11 | 322 | if !self.try_report_nice_region_error(&error) { |
abe05a73 XL |
323 | match error.clone() { |
324 | // These errors could indicate all manner of different | |
325 | // problems with many different solutions. Rather | |
326 | // than generate a "one size fits all" error, what we | |
327 | // attempt to do is go through a number of specific | |
328 | // scenarios and try to find the best way to present | |
329 | // the error. If all of these fails, we fall back to a rather | |
330 | // general bit of code that displays the error information | |
331 | RegionResolutionError::ConcreteFailure(origin, sub, sup) => { | |
0731742a | 332 | if sub.is_placeholder() || sup.is_placeholder() { |
f9f354fc | 333 | self.report_placeholder_failure(origin, sub, sup).emit(); |
0731742a | 334 | } else { |
f9f354fc | 335 | self.report_concrete_failure(origin, sub, sup).emit(); |
0731742a | 336 | } |
abe05a73 XL |
337 | } |
338 | ||
ff7c6d11 XL |
339 | RegionResolutionError::GenericBoundFailure(origin, param_ty, sub) => { |
340 | self.report_generic_bound_failure( | |
ff7c6d11 XL |
341 | origin.span(), |
342 | Some(origin), | |
343 | param_ty, | |
344 | sub, | |
345 | ); | |
abe05a73 XL |
346 | } |
347 | ||
0531ce1d | 348 | RegionResolutionError::SubSupConflict( |
0731742a | 349 | _, |
0531ce1d XL |
350 | var_origin, |
351 | sub_origin, | |
352 | sub_r, | |
353 | sup_origin, | |
354 | sup_r, | |
355 | ) => { | |
0731742a | 356 | if sub_r.is_placeholder() { |
f9f354fc | 357 | self.report_placeholder_failure(sub_origin, sub_r, sup_r).emit(); |
0731742a | 358 | } else if sup_r.is_placeholder() { |
f9f354fc | 359 | self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit(); |
0731742a XL |
360 | } else { |
361 | self.report_sub_sup_conflict( | |
f9f354fc | 362 | var_origin, sub_origin, sub_r, sup_origin, sup_r, |
0731742a XL |
363 | ); |
364 | } | |
abe05a73 | 365 | } |
dc9dc135 | 366 | |
74b04a01 XL |
367 | RegionResolutionError::UpperBoundUniverseConflict( |
368 | _, | |
369 | _, | |
370 | var_universe, | |
371 | sup_origin, | |
372 | sup_r, | |
373 | ) => { | |
374 | assert!(sup_r.is_placeholder()); | |
375 | ||
376 | // Make a dummy value for the "sub region" -- | |
377 | // this is the initial value of the | |
378 | // placeholder. In practice, we expect more | |
379 | // tailored errors that don't really use this | |
380 | // value. | |
381 | let sub_r = self.tcx.mk_region(ty::ReEmpty(var_universe)); | |
382 | ||
f9f354fc | 383 | self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit(); |
74b04a01 XL |
384 | } |
385 | ||
dc9dc135 | 386 | RegionResolutionError::MemberConstraintFailure { |
dc9dc135 XL |
387 | hidden_ty, |
388 | member_region, | |
74b04a01 | 389 | span, |
dc9dc135 XL |
390 | } => { |
391 | let hidden_ty = self.resolve_vars_if_possible(&hidden_ty); | |
ba9703b0 | 392 | unexpected_hidden_region_diagnostic( |
dc9dc135 | 393 | self.tcx, |
74b04a01 | 394 | span, |
dc9dc135 XL |
395 | hidden_ty, |
396 | member_region, | |
dfeec247 XL |
397 | ) |
398 | .emit(); | |
dc9dc135 | 399 | } |
abe05a73 | 400 | } |
1a4d82fc JJ |
401 | } |
402 | } | |
403 | } | |
404 | ||
405 | // This method goes through all the errors and try to group certain types | |
406 | // of error together, for the purpose of suggesting explicit lifetime | |
407 | // parameters to the user. This is done so that we can have a more | |
408 | // complete view of what lifetimes should be the same. | |
409 | // If the return value is an empty vector, it means that processing | |
54a0048b SL |
410 | // failed (so the return value of this method should not be used). |
411 | // | |
412 | // The method also attempts to weed out messages that seem like | |
413 | // duplicates that will be unhelpful to the end-user. But | |
414 | // obviously it never weeds out ALL errors. | |
0531ce1d XL |
415 | fn process_errors( |
416 | &self, | |
417 | errors: &Vec<RegionResolutionError<'tcx>>, | |
418 | ) -> Vec<RegionResolutionError<'tcx>> { | |
1a4d82fc | 419 | debug!("process_errors()"); |
54a0048b | 420 | |
32a655c1 SL |
421 | // We want to avoid reporting generic-bound failures if we can |
422 | // avoid it: these have a very high rate of being unhelpful in | |
423 | // practice. This is because they are basically secondary | |
424 | // checks that test the state of the region graph after the | |
425 | // rest of inference is done, and the other kinds of errors | |
426 | // indicate that the region constraint graph is internally | |
427 | // inconsistent, so these test results are likely to be | |
428 | // meaningless. | |
429 | // | |
430 | // Therefore, we filter them out of the list unless they are | |
431 | // the only thing in the list. | |
432 | ||
433 | let is_bound_failure = |e: &RegionResolutionError<'tcx>| match *e { | |
abe05a73 | 434 | RegionResolutionError::GenericBoundFailure(..) => true, |
0531ce1d | 435 | RegionResolutionError::ConcreteFailure(..) |
dfeec247 | 436 | | RegionResolutionError::SubSupConflict(..) |
74b04a01 | 437 | | RegionResolutionError::UpperBoundUniverseConflict(..) |
dfeec247 | 438 | | RegionResolutionError::MemberConstraintFailure { .. } => false, |
32a655c1 | 439 | }; |
1a4d82fc | 440 | |
ea8adc8c | 441 | let mut errors = if errors.iter().all(|e| is_bound_failure(e)) { |
32a655c1 SL |
442 | errors.clone() |
443 | } else { | |
dfeec247 | 444 | errors.iter().filter(|&e| !is_bound_failure(e)).cloned().collect() |
ea8adc8c XL |
445 | }; |
446 | ||
447 | // sort the errors by span, for better error message stability. | |
448 | errors.sort_by_key(|u| match *u { | |
abe05a73 XL |
449 | RegionResolutionError::ConcreteFailure(ref sro, _, _) => sro.span(), |
450 | RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(), | |
0731742a | 451 | RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _) => rvo.span(), |
74b04a01 | 452 | RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => rvo.span(), |
dc9dc135 | 453 | RegionResolutionError::MemberConstraintFailure { span, .. } => span, |
ea8adc8c XL |
454 | }); |
455 | errors | |
1a4d82fc JJ |
456 | } |
457 | ||
e9174d1e | 458 | /// Adds a note if the types come from similarly named crates |
0531ce1d XL |
459 | fn check_and_note_conflicting_crates( |
460 | &self, | |
0bf4aa26 | 461 | err: &mut DiagnosticBuilder<'_>, |
0531ce1d | 462 | terr: &TypeError<'tcx>, |
0531ce1d | 463 | ) { |
532ac7d7 | 464 | use hir::def_id::CrateNum; |
ba9703b0 | 465 | use rustc_hir::definitions::DisambiguatedDefPathData; |
532ac7d7 | 466 | use ty::print::Printer; |
e74abb32 | 467 | use ty::subst::GenericArg; |
532ac7d7 | 468 | |
dc9dc135 XL |
469 | struct AbsolutePathPrinter<'tcx> { |
470 | tcx: TyCtxt<'tcx>, | |
532ac7d7 XL |
471 | } |
472 | ||
473 | struct NonTrivialPath; | |
474 | ||
dc9dc135 | 475 | impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { |
532ac7d7 XL |
476 | type Error = NonTrivialPath; |
477 | ||
478 | type Path = Vec<String>; | |
479 | type Region = !; | |
480 | type Type = !; | |
481 | type DynExistential = !; | |
dc9dc135 | 482 | type Const = !; |
532ac7d7 | 483 | |
dc9dc135 | 484 | fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { |
532ac7d7 XL |
485 | self.tcx |
486 | } | |
487 | ||
dfeec247 | 488 | fn print_region(self, _region: ty::Region<'_>) -> Result<Self::Region, Self::Error> { |
532ac7d7 XL |
489 | Err(NonTrivialPath) |
490 | } | |
491 | ||
dfeec247 | 492 | fn print_type(self, _ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> { |
532ac7d7 XL |
493 | Err(NonTrivialPath) |
494 | } | |
495 | ||
496 | fn print_dyn_existential( | |
497 | self, | |
498 | _predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>, | |
499 | ) -> Result<Self::DynExistential, Self::Error> { | |
500 | Err(NonTrivialPath) | |
501 | } | |
502 | ||
dfeec247 | 503 | fn print_const(self, _ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { |
dc9dc135 XL |
504 | Err(NonTrivialPath) |
505 | } | |
506 | ||
dfeec247 | 507 | fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> { |
532ac7d7 XL |
508 | Ok(vec![self.tcx.original_crate_name(cnum).to_string()]) |
509 | } | |
510 | fn path_qualified( | |
511 | self, | |
512 | _self_ty: Ty<'tcx>, | |
513 | _trait_ref: Option<ty::TraitRef<'tcx>>, | |
514 | ) -> Result<Self::Path, Self::Error> { | |
515 | Err(NonTrivialPath) | |
516 | } | |
517 | ||
518 | fn path_append_impl( | |
519 | self, | |
520 | _print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, | |
521 | _disambiguated_data: &DisambiguatedDefPathData, | |
522 | _self_ty: Ty<'tcx>, | |
523 | _trait_ref: Option<ty::TraitRef<'tcx>>, | |
524 | ) -> Result<Self::Path, Self::Error> { | |
525 | Err(NonTrivialPath) | |
526 | } | |
527 | fn path_append( | |
528 | self, | |
529 | print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, | |
530 | disambiguated_data: &DisambiguatedDefPathData, | |
531 | ) -> Result<Self::Path, Self::Error> { | |
532 | let mut path = print_prefix(self)?; | |
e74abb32 | 533 | path.push(disambiguated_data.data.as_symbol().to_string()); |
532ac7d7 XL |
534 | Ok(path) |
535 | } | |
536 | fn path_generic_args( | |
537 | self, | |
538 | print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, | |
e74abb32 | 539 | _args: &[GenericArg<'tcx>], |
532ac7d7 XL |
540 | ) -> Result<Self::Path, Self::Error> { |
541 | print_prefix(self) | |
542 | } | |
543 | } | |
544 | ||
0bf4aa26 | 545 | let report_path_match = |err: &mut DiagnosticBuilder<'_>, did1: DefId, did2: DefId| { |
e9174d1e SL |
546 | // Only external crates, if either is from a local |
547 | // module we could have false positives | |
548 | if !(did1.is_local() || did2.is_local()) && did1.krate != did2.krate { | |
dfeec247 XL |
549 | let abs_path = |
550 | |def_id| AbsolutePathPrinter { tcx: self.tcx }.print_def_path(def_id, &[]); | |
532ac7d7 | 551 | |
54a0048b | 552 | // We compare strings because DefPath can be different |
e9174d1e | 553 | // for imported and non-imported crates |
532ac7d7 | 554 | let same_path = || -> Result<_, NonTrivialPath> { |
dfeec247 XL |
555 | Ok(self.tcx.def_path_str(did1) == self.tcx.def_path_str(did2) |
556 | || abs_path(did1)? == abs_path(did2)?) | |
532ac7d7 XL |
557 | }; |
558 | if same_path().unwrap_or(false) { | |
ea8adc8c | 559 | let crate_name = self.tcx.crate_name(did1.krate); |
60c5eb7d XL |
560 | err.note(&format!( |
561 | "perhaps two different versions of crate `{}` are being used?", | |
562 | crate_name | |
563 | )); | |
e9174d1e SL |
564 | } |
565 | } | |
566 | }; | |
567 | match *terr { | |
568 | TypeError::Sorts(ref exp_found) => { | |
569 | // if they are both "path types", there's a chance of ambiguity | |
570 | // due to different versions of the same crate | |
dfeec247 XL |
571 | if let (&ty::Adt(exp_adt, _), &ty::Adt(found_adt, _)) = |
572 | (&exp_found.expected.kind, &exp_found.found.kind) | |
0bf4aa26 XL |
573 | { |
574 | report_path_match(err, exp_adt.did, found_adt.did); | |
e9174d1e | 575 | } |
0531ce1d | 576 | } |
e9174d1e | 577 | TypeError::Traits(ref exp_found) => { |
9cc50fc6 | 578 | report_path_match(err, exp_found.expected, exp_found.found); |
0531ce1d XL |
579 | } |
580 | _ => (), // FIXME(#22750) handle traits and stuff | |
e9174d1e SL |
581 | } |
582 | } | |
583 | ||
9fa01778 XL |
584 | fn note_error_origin( |
585 | &self, | |
586 | err: &mut DiagnosticBuilder<'tcx>, | |
587 | cause: &ObligationCause<'tcx>, | |
588 | exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>, | |
589 | ) { | |
476ff2be | 590 | match cause.code { |
dfeec247 XL |
591 | ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => { |
592 | let ty = self.resolve_vars_if_possible(&root_ty); | |
593 | if ty.is_suggestable() { | |
594 | // don't show type `_` | |
595 | err.span_label(span, format!("this expression has type `{}`", ty)); | |
0731742a | 596 | } |
9fa01778 XL |
597 | if let Some(ty::error::ExpectedFound { found, .. }) = exp_found { |
598 | if ty.is_box() && ty.boxed_ty() == found { | |
599 | if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { | |
600 | err.span_suggestion( | |
601 | span, | |
602 | "consider dereferencing the boxed value", | |
603 | format!("*{}", snippet), | |
604 | Applicability::MachineApplicable, | |
605 | ); | |
606 | } | |
607 | } | |
608 | } | |
0731742a | 609 | } |
dfeec247 XL |
610 | ObligationCauseCode::Pattern { origin_expr: false, span: Some(span), .. } => { |
611 | err.span_label(span, "expected due to this"); | |
612 | } | |
e1599b0c | 613 | ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { |
9fa01778 XL |
614 | source, |
615 | ref prior_arms, | |
616 | last_ty, | |
dfeec247 | 617 | scrut_hir_id, |
9fa01778 | 618 | .. |
e1599b0c | 619 | }) => match source { |
0531ce1d | 620 | hir::MatchSource::IfLetDesugar { .. } => { |
9fa01778 XL |
621 | let msg = "`if let` arms have incompatible types"; |
622 | err.span_label(cause.span, msg); | |
0bf4aa26 | 623 | } |
48663c56 XL |
624 | hir::MatchSource::TryDesugar => { |
625 | if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found { | |
dfeec247 XL |
626 | let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id); |
627 | let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind { | |
48663c56 | 628 | let arg_expr = args.first().expect("try desugaring call w/out arg"); |
dfeec247 XL |
629 | self.in_progress_tables |
630 | .and_then(|tables| tables.borrow().expr_ty_opt(arg_expr)) | |
48663c56 | 631 | } else { |
dfeec247 | 632 | bug!("try desugaring w/out call expr as scrutinee"); |
48663c56 XL |
633 | }; |
634 | ||
dfeec247 | 635 | match scrut_ty { |
48663c56 XL |
636 | Some(ty) if expected == ty => { |
637 | let source_map = self.tcx.sess.source_map(); | |
638 | err.span_suggestion( | |
639 | source_map.end_point(cause.span), | |
640 | "try removing this `?`", | |
641 | "".to_string(), | |
642 | Applicability::MachineApplicable, | |
643 | ); | |
dfeec247 XL |
644 | } |
645 | _ => {} | |
48663c56 XL |
646 | } |
647 | } | |
648 | } | |
5bcae85e | 649 | _ => { |
416331ca XL |
650 | // `last_ty` can be `!`, `expected` will have better info when present. |
651 | let t = self.resolve_vars_if_possible(&match exp_found { | |
652 | Some(ty::error::ExpectedFound { expected, .. }) => expected, | |
653 | _ => last_ty, | |
654 | }); | |
9fa01778 XL |
655 | let msg = "`match` arms have incompatible types"; |
656 | err.span_label(cause.span, msg); | |
657 | if prior_arms.len() <= 4 { | |
658 | for sp in prior_arms { | |
dfeec247 | 659 | err.span_label(*sp, format!("this is found to be of type `{}`", t)); |
9fa01778 XL |
660 | } |
661 | } else if let Some(sp) = prior_arms.last() { | |
416331ca XL |
662 | err.span_label( |
663 | *sp, | |
664 | format!("this and all prior arms are found to be of type `{}`", t), | |
665 | ); | |
ff7c6d11 | 666 | } |
5bcae85e SL |
667 | } |
668 | }, | |
e1599b0c | 669 | ObligationCauseCode::IfExpression(box IfExpressionCause { then, outer, semicolon }) => { |
0731742a | 670 | err.span_label(then, "expected because of this"); |
f9f354fc XL |
671 | if let Some(sp) = outer { |
672 | err.span_label(sp, "`if` and `else` have incompatible types"); | |
673 | } | |
0731742a | 674 | if let Some(sp) = semicolon { |
9fa01778 | 675 | err.span_suggestion_short( |
0731742a XL |
676 | sp, |
677 | "consider removing this semicolon", | |
678 | String::new(), | |
679 | Applicability::MachineApplicable, | |
680 | ); | |
681 | } | |
682 | } | |
0531ce1d | 683 | _ => (), |
5bcae85e SL |
684 | } |
685 | } | |
686 | ||
cc61c64b XL |
687 | /// Given that `other_ty` is the same as a type argument for `name` in `sub`, populate `value` |
688 | /// highlighting `name` and every type argument that isn't at `pos` (which is `other_ty`), and | |
689 | /// populate `other_value` with `other_ty`. | |
690 | /// | |
691 | /// ```text | |
692 | /// Foo<Bar<Qux>> | |
693 | /// ^^^^--------^ this is highlighted | |
694 | /// | | | |
695 | /// | this type argument is exactly the same as the other type, not highlighted | |
696 | /// this is highlighted | |
697 | /// Bar<Qux> | |
698 | /// -------- this type is the same as a type argument in the other type, not highlighted | |
699 | /// ``` | |
0531ce1d XL |
700 | fn highlight_outer( |
701 | &self, | |
702 | value: &mut DiagnosticStyledString, | |
703 | other_value: &mut DiagnosticStyledString, | |
704 | name: String, | |
532ac7d7 | 705 | sub: ty::subst::SubstsRef<'tcx>, |
0531ce1d | 706 | pos: usize, |
48663c56 | 707 | other_ty: Ty<'tcx>, |
0531ce1d | 708 | ) { |
cc61c64b XL |
709 | // `value` and `other_value` hold two incomplete type representation for display. |
710 | // `name` is the path of both types being compared. `sub` | |
711 | value.push_highlighted(name); | |
712 | let len = sub.len(); | |
713 | if len > 0 { | |
714 | value.push_highlighted("<"); | |
715 | } | |
716 | ||
b7449926 | 717 | // Output the lifetimes for the first type |
dfeec247 XL |
718 | let lifetimes = sub |
719 | .regions() | |
0531ce1d | 720 | .map(|lifetime| { |
8faf50e0 | 721 | let s = lifetime.to_string(); |
dfeec247 | 722 | if s.is_empty() { "'_".to_string() } else { s } |
0531ce1d XL |
723 | }) |
724 | .collect::<Vec<_>>() | |
725 | .join(", "); | |
cc61c64b XL |
726 | if !lifetimes.is_empty() { |
727 | if sub.regions().count() < len { | |
74b04a01 | 728 | value.push_normal(lifetimes + ", "); |
cc61c64b XL |
729 | } else { |
730 | value.push_normal(lifetimes); | |
731 | } | |
732 | } | |
733 | ||
734 | // Highlight all the type arguments that aren't at `pos` and compare the type argument at | |
735 | // `pos` and `other_ty`. | |
736 | for (i, type_arg) in sub.types().enumerate() { | |
737 | if i == pos { | |
738 | let values = self.cmp(type_arg, other_ty); | |
739 | value.0.extend((values.0).0); | |
740 | other_value.0.extend((values.1).0); | |
741 | } else { | |
8faf50e0 | 742 | value.push_highlighted(type_arg.to_string()); |
cc61c64b XL |
743 | } |
744 | ||
745 | if len > 0 && i != len - 1 { | |
746 | value.push_normal(", "); | |
747 | } | |
cc61c64b XL |
748 | } |
749 | if len > 0 { | |
750 | value.push_highlighted(">"); | |
751 | } | |
752 | } | |
753 | ||
754 | /// If `other_ty` is the same as a type argument present in `sub`, highlight `path` in `t1_out`, | |
755 | /// as that is the difference to the other type. | |
756 | /// | |
757 | /// For the following code: | |
758 | /// | |
f9f354fc | 759 | /// ```no_run |
cc61c64b XL |
760 | /// let x: Foo<Bar<Qux>> = foo::<Bar<Qux>>(); |
761 | /// ``` | |
762 | /// | |
763 | /// The type error output will behave in the following way: | |
764 | /// | |
765 | /// ```text | |
766 | /// Foo<Bar<Qux>> | |
767 | /// ^^^^--------^ this is highlighted | |
768 | /// | | | |
769 | /// | this type argument is exactly the same as the other type, not highlighted | |
770 | /// this is highlighted | |
771 | /// Bar<Qux> | |
772 | /// -------- this type is the same as a type argument in the other type, not highlighted | |
773 | /// ``` | |
0531ce1d XL |
774 | fn cmp_type_arg( |
775 | &self, | |
776 | mut t1_out: &mut DiagnosticStyledString, | |
777 | mut t2_out: &mut DiagnosticStyledString, | |
778 | path: String, | |
532ac7d7 | 779 | sub: ty::subst::SubstsRef<'tcx>, |
0531ce1d | 780 | other_path: String, |
48663c56 | 781 | other_ty: Ty<'tcx>, |
0531ce1d | 782 | ) -> Option<()> { |
cc61c64b | 783 | for (i, ta) in sub.types().enumerate() { |
48663c56 | 784 | if ta == other_ty { |
cc61c64b XL |
785 | self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty); |
786 | return Some(()); | |
787 | } | |
e74abb32 | 788 | if let &ty::Adt(def, _) = &ta.kind { |
ba9703b0 | 789 | let path_ = self.tcx.def_path_str(def.did); |
cc61c64b XL |
790 | if path_ == other_path { |
791 | self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty); | |
792 | return Some(()); | |
793 | } | |
794 | } | |
795 | } | |
796 | None | |
797 | } | |
798 | ||
9fa01778 | 799 | /// Adds a `,` to the type representation only if it is appropriate. |
0531ce1d XL |
800 | fn push_comma( |
801 | &self, | |
802 | value: &mut DiagnosticStyledString, | |
803 | other_value: &mut DiagnosticStyledString, | |
804 | len: usize, | |
805 | pos: usize, | |
806 | ) { | |
cc61c64b XL |
807 | if len > 0 && pos != len - 1 { |
808 | value.push_normal(", "); | |
809 | other_value.push_normal(", "); | |
810 | } | |
811 | } | |
812 | ||
8faf50e0 | 813 | /// For generic types with parameters with defaults, remove the parameters corresponding to |
532ac7d7 | 814 | /// the defaults. This repeats a lot of the logic found in `ty::print::pretty`. |
8faf50e0 XL |
815 | fn strip_generic_default_params( |
816 | &self, | |
817 | def_id: DefId, | |
532ac7d7 XL |
818 | substs: ty::subst::SubstsRef<'tcx>, |
819 | ) -> SubstsRef<'tcx> { | |
8faf50e0 XL |
820 | let generics = self.tcx.generics_of(def_id); |
821 | let mut num_supplied_defaults = 0; | |
dfeec247 XL |
822 | let mut type_params = generics |
823 | .params | |
824 | .iter() | |
825 | .rev() | |
826 | .filter_map(|param| match param.kind { | |
827 | ty::GenericParamDefKind::Lifetime => None, | |
828 | ty::GenericParamDefKind::Type { has_default, .. } => { | |
829 | Some((param.def_id, has_default)) | |
830 | } | |
831 | ty::GenericParamDefKind::Const => None, // FIXME(const_generics:defaults) | |
832 | }) | |
833 | .peekable(); | |
8faf50e0 XL |
834 | let has_default = { |
835 | let has_default = type_params.peek().map(|(_, has_default)| has_default); | |
836 | *has_default.unwrap_or(&false) | |
837 | }; | |
838 | if has_default { | |
839 | let types = substs.types().rev(); | |
840 | for ((def_id, has_default), actual) in type_params.zip(types) { | |
841 | if !has_default { | |
842 | break; | |
843 | } | |
844 | if self.tcx.type_of(def_id).subst(self.tcx, substs) != actual { | |
845 | break; | |
846 | } | |
847 | num_supplied_defaults += 1; | |
848 | } | |
849 | } | |
850 | let len = generics.params.len(); | |
851 | let mut generics = generics.clone(); | |
852 | generics.params.truncate(len - num_supplied_defaults); | |
853 | substs.truncate_to(self.tcx, &generics) | |
854 | } | |
855 | ||
60c5eb7d XL |
856 | /// Given two `fn` signatures highlight only sub-parts that are different. |
857 | fn cmp_fn_sig( | |
858 | &self, | |
859 | sig1: &ty::PolyFnSig<'tcx>, | |
860 | sig2: &ty::PolyFnSig<'tcx>, | |
861 | ) -> (DiagnosticStyledString, DiagnosticStyledString) { | |
862 | let get_lifetimes = |sig| { | |
dfeec247 | 863 | use rustc_hir::def::Namespace; |
60c5eb7d XL |
864 | let mut s = String::new(); |
865 | let (_, (sig, reg)) = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS) | |
866 | .name_all_regions(sig) | |
867 | .unwrap(); | |
868 | let lts: Vec<String> = reg.into_iter().map(|(_, kind)| kind.to_string()).collect(); | |
dfeec247 | 869 | (if lts.is_empty() { String::new() } else { format!("for<{}> ", lts.join(", ")) }, sig) |
60c5eb7d XL |
870 | }; |
871 | ||
872 | let (lt1, sig1) = get_lifetimes(sig1); | |
873 | let (lt2, sig2) = get_lifetimes(sig2); | |
874 | ||
875 | // unsafe extern "C" for<'a> fn(&'a T) -> &'a T | |
876 | let mut values = ( | |
877 | DiagnosticStyledString::normal("".to_string()), | |
878 | DiagnosticStyledString::normal("".to_string()), | |
879 | ); | |
880 | ||
881 | // unsafe extern "C" for<'a> fn(&'a T) -> &'a T | |
882 | // ^^^^^^ | |
883 | values.0.push(sig1.unsafety.prefix_str(), sig1.unsafety != sig2.unsafety); | |
884 | values.1.push(sig2.unsafety.prefix_str(), sig1.unsafety != sig2.unsafety); | |
885 | ||
886 | // unsafe extern "C" for<'a> fn(&'a T) -> &'a T | |
887 | // ^^^^^^^^^^ | |
888 | if sig1.abi != abi::Abi::Rust { | |
889 | values.0.push(format!("extern {} ", sig1.abi), sig1.abi != sig2.abi); | |
890 | } | |
891 | if sig2.abi != abi::Abi::Rust { | |
892 | values.1.push(format!("extern {} ", sig2.abi), sig1.abi != sig2.abi); | |
893 | } | |
894 | ||
895 | // unsafe extern "C" for<'a> fn(&'a T) -> &'a T | |
896 | // ^^^^^^^^ | |
897 | let lifetime_diff = lt1 != lt2; | |
898 | values.0.push(lt1, lifetime_diff); | |
899 | values.1.push(lt2, lifetime_diff); | |
900 | ||
901 | // unsafe extern "C" for<'a> fn(&'a T) -> &'a T | |
902 | // ^^^ | |
903 | values.0.push_normal("fn("); | |
904 | values.1.push_normal("fn("); | |
905 | ||
906 | // unsafe extern "C" for<'a> fn(&'a T) -> &'a T | |
907 | // ^^^^^ | |
908 | let len1 = sig1.inputs().len(); | |
909 | let len2 = sig2.inputs().len(); | |
910 | if len1 == len2 { | |
911 | for (i, (l, r)) in sig1.inputs().iter().zip(sig2.inputs().iter()).enumerate() { | |
912 | let (x1, x2) = self.cmp(l, r); | |
913 | (values.0).0.extend(x1.0); | |
914 | (values.1).0.extend(x2.0); | |
915 | self.push_comma(&mut values.0, &mut values.1, len1, i); | |
916 | } | |
917 | } else { | |
918 | for (i, l) in sig1.inputs().iter().enumerate() { | |
919 | values.0.push_highlighted(l.to_string()); | |
920 | if i != len1 - 1 { | |
921 | values.0.push_highlighted(", "); | |
922 | } | |
923 | } | |
924 | for (i, r) in sig2.inputs().iter().enumerate() { | |
925 | values.1.push_highlighted(r.to_string()); | |
926 | if i != len2 - 1 { | |
927 | values.1.push_highlighted(", "); | |
928 | } | |
929 | } | |
930 | } | |
931 | ||
932 | if sig1.c_variadic { | |
933 | if len1 > 0 { | |
934 | values.0.push_normal(", "); | |
935 | } | |
936 | values.0.push("...", !sig2.c_variadic); | |
937 | } | |
938 | if sig2.c_variadic { | |
939 | if len2 > 0 { | |
940 | values.1.push_normal(", "); | |
941 | } | |
942 | values.1.push("...", !sig1.c_variadic); | |
943 | } | |
944 | ||
945 | // unsafe extern "C" for<'a> fn(&'a T) -> &'a T | |
946 | // ^ | |
947 | values.0.push_normal(")"); | |
948 | values.1.push_normal(")"); | |
949 | ||
950 | // unsafe extern "C" for<'a> fn(&'a T) -> &'a T | |
951 | // ^^^^^^^^ | |
952 | let output1 = sig1.output(); | |
953 | let output2 = sig2.output(); | |
954 | let (x1, x2) = self.cmp(output1, output2); | |
955 | if !output1.is_unit() { | |
956 | values.0.push_normal(" -> "); | |
957 | (values.0).0.extend(x1.0); | |
958 | } | |
959 | if !output2.is_unit() { | |
960 | values.1.push_normal(" -> "); | |
961 | (values.1).0.extend(x2.0); | |
962 | } | |
963 | values | |
964 | } | |
965 | ||
9fa01778 | 966 | /// Compares two given types, eliding parts that are the same between them and highlighting |
cc61c64b | 967 | /// relevant differences, and return two representation of those types for highlighted printing. |
0531ce1d | 968 | fn cmp(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> (DiagnosticStyledString, DiagnosticStyledString) { |
e74abb32 XL |
969 | debug!("cmp(t1={}, t1.kind={:?}, t2={}, t2.kind={:?})", t1, t1.kind, t2, t2.kind); |
970 | ||
971 | // helper functions | |
48663c56 | 972 | fn equals<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { |
e74abb32 | 973 | match (&a.kind, &b.kind) { |
ff7c6d11 | 974 | (a, b) if *a == *b => true, |
b7449926 | 975 | (&ty::Int(_), &ty::Infer(ty::InferTy::IntVar(_))) |
ba9703b0 XL |
976 | | ( |
977 | &ty::Infer(ty::InferTy::IntVar(_)), | |
978 | &ty::Int(_) | &ty::Infer(ty::InferTy::IntVar(_)), | |
979 | ) | |
b7449926 | 980 | | (&ty::Float(_), &ty::Infer(ty::InferTy::FloatVar(_))) |
ba9703b0 XL |
981 | | ( |
982 | &ty::Infer(ty::InferTy::FloatVar(_)), | |
983 | &ty::Float(_) | &ty::Infer(ty::InferTy::FloatVar(_)), | |
984 | ) => true, | |
ff7c6d11 XL |
985 | _ => false, |
986 | } | |
987 | } | |
988 | ||
0531ce1d | 989 | fn push_ty_ref<'tcx>( |
f9f354fc | 990 | region: &ty::Region<'tcx>, |
94b46f34 XL |
991 | ty: Ty<'tcx>, |
992 | mutbl: hir::Mutability, | |
0531ce1d XL |
993 | s: &mut DiagnosticStyledString, |
994 | ) { | |
f9f354fc | 995 | let mut r = region.to_string(); |
532ac7d7 XL |
996 | if r == "'_" { |
997 | r.clear(); | |
998 | } else { | |
999 | r.push(' '); | |
1000 | } | |
60c5eb7d | 1001 | s.push_highlighted(format!("&{}{}", r, mutbl.prefix_str())); |
8faf50e0 | 1002 | s.push_normal(ty.to_string()); |
ff7c6d11 XL |
1003 | } |
1004 | ||
e74abb32 XL |
1005 | // process starts here |
1006 | match (&t1.kind, &t2.kind) { | |
b7449926 | 1007 | (&ty::Adt(def1, sub1), &ty::Adt(def2, sub2)) => { |
8faf50e0 XL |
1008 | let sub_no_defaults_1 = self.strip_generic_default_params(def1.did, sub1); |
1009 | let sub_no_defaults_2 = self.strip_generic_default_params(def2.did, sub2); | |
cc61c64b | 1010 | let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); |
ba9703b0 XL |
1011 | let path1 = self.tcx.def_path_str(def1.did); |
1012 | let path2 = self.tcx.def_path_str(def2.did); | |
cc61c64b XL |
1013 | if def1.did == def2.did { |
1014 | // Easy case. Replace same types with `_` to shorten the output and highlight | |
1015 | // the differing ones. | |
1016 | // let x: Foo<Bar, Qux> = y::<Foo<Quz, Qux>>(); | |
1017 | // Foo<Bar, _> | |
1018 | // Foo<Quz, _> | |
1019 | // --- ^ type argument elided | |
1020 | // | | |
1021 | // highlighted in output | |
1022 | values.0.push_normal(path1); | |
1023 | values.1.push_normal(path2); | |
1024 | ||
8faf50e0 XL |
1025 | // Avoid printing out default generic parameters that are common to both |
1026 | // types. | |
1027 | let len1 = sub_no_defaults_1.len(); | |
1028 | let len2 = sub_no_defaults_2.len(); | |
1029 | let common_len = cmp::min(len1, len2); | |
1030 | let remainder1: Vec<_> = sub1.types().skip(common_len).collect(); | |
1031 | let remainder2: Vec<_> = sub2.types().skip(common_len).collect(); | |
0bf4aa26 XL |
1032 | let common_default_params = remainder1 |
1033 | .iter() | |
1034 | .rev() | |
1035 | .zip(remainder2.iter().rev()) | |
1036 | .filter(|(a, b)| a == b) | |
1037 | .count(); | |
8faf50e0 | 1038 | let len = sub1.len() - common_default_params; |
e74abb32 | 1039 | let consts_offset = len - sub1.consts().count(); |
8faf50e0 | 1040 | |
cc61c64b | 1041 | // Only draw `<...>` if there're lifetime/type arguments. |
cc61c64b XL |
1042 | if len > 0 { |
1043 | values.0.push_normal("<"); | |
1044 | values.1.push_normal("<"); | |
1045 | } | |
1046 | ||
0bf4aa26 | 1047 | fn lifetime_display(lifetime: Region<'_>) -> String { |
8faf50e0 | 1048 | let s = lifetime.to_string(); |
dfeec247 | 1049 | if s.is_empty() { "'_".to_string() } else { s } |
cc61c64b XL |
1050 | } |
1051 | // At one point we'd like to elide all lifetimes here, they are irrelevant for | |
1052 | // all diagnostics that use this output | |
1053 | // | |
1054 | // Foo<'x, '_, Bar> | |
1055 | // Foo<'y, '_, Qux> | |
1056 | // ^^ ^^ --- type arguments are not elided | |
1057 | // | | | |
1058 | // | elided as they were the same | |
1059 | // not elided, they were different, but irrelevant | |
1060 | let lifetimes = sub1.regions().zip(sub2.regions()); | |
1061 | for (i, lifetimes) in lifetimes.enumerate() { | |
1062 | let l1 = lifetime_display(lifetimes.0); | |
1063 | let l2 = lifetime_display(lifetimes.1); | |
60c5eb7d | 1064 | if lifetimes.0 == lifetimes.1 { |
cc61c64b XL |
1065 | values.0.push_normal("'_"); |
1066 | values.1.push_normal("'_"); | |
1067 | } else { | |
1068 | values.0.push_highlighted(l1); | |
1069 | values.1.push_highlighted(l2); | |
1070 | } | |
1071 | self.push_comma(&mut values.0, &mut values.1, len, i); | |
1072 | } | |
1073 | ||
1074 | // We're comparing two types with the same path, so we compare the type | |
1075 | // arguments for both. If they are the same, do not highlight and elide from the | |
1076 | // output. | |
1077 | // Foo<_, Bar> | |
1078 | // Foo<_, Qux> | |
1079 | // ^ elided type as this type argument was the same in both sides | |
1080 | let type_arguments = sub1.types().zip(sub2.types()); | |
8faf50e0 | 1081 | let regions_len = sub1.regions().count(); |
e74abb32 XL |
1082 | let num_display_types = consts_offset - regions_len; |
1083 | for (i, (ta1, ta2)) in type_arguments.take(num_display_types).enumerate() { | |
cc61c64b XL |
1084 | let i = i + regions_len; |
1085 | if ta1 == ta2 { | |
1086 | values.0.push_normal("_"); | |
1087 | values.1.push_normal("_"); | |
1088 | } else { | |
1089 | let (x1, x2) = self.cmp(ta1, ta2); | |
1090 | (values.0).0.extend(x1.0); | |
1091 | (values.1).0.extend(x2.0); | |
1092 | } | |
1093 | self.push_comma(&mut values.0, &mut values.1, len, i); | |
1094 | } | |
1095 | ||
e74abb32 XL |
1096 | // Do the same for const arguments, if they are equal, do not highlight and |
1097 | // elide them from the output. | |
1098 | let const_arguments = sub1.consts().zip(sub2.consts()); | |
1099 | for (i, (ca1, ca2)) in const_arguments.enumerate() { | |
1100 | let i = i + consts_offset; | |
1101 | if ca1 == ca2 { | |
1102 | values.0.push_normal("_"); | |
1103 | values.1.push_normal("_"); | |
1104 | } else { | |
1105 | values.0.push_highlighted(ca1.to_string()); | |
1106 | values.1.push_highlighted(ca2.to_string()); | |
1107 | } | |
1108 | self.push_comma(&mut values.0, &mut values.1, len, i); | |
1109 | } | |
1110 | ||
cc61c64b XL |
1111 | // Close the type argument bracket. |
1112 | // Only draw `<...>` if there're lifetime/type arguments. | |
1113 | if len > 0 { | |
1114 | values.0.push_normal(">"); | |
1115 | values.1.push_normal(">"); | |
1116 | } | |
1117 | values | |
1118 | } else { | |
1119 | // Check for case: | |
1120 | // let x: Foo<Bar<Qux> = foo::<Bar<Qux>>(); | |
1121 | // Foo<Bar<Qux> | |
1122 | // ------- this type argument is exactly the same as the other type | |
1123 | // Bar<Qux> | |
dfeec247 XL |
1124 | if self |
1125 | .cmp_type_arg( | |
1126 | &mut values.0, | |
1127 | &mut values.1, | |
1128 | path1.clone(), | |
1129 | sub_no_defaults_1, | |
1130 | path2.clone(), | |
1131 | &t2, | |
1132 | ) | |
1133 | .is_some() | |
0531ce1d | 1134 | { |
cc61c64b XL |
1135 | return values; |
1136 | } | |
1137 | // Check for case: | |
1138 | // let x: Bar<Qux> = y:<Foo<Bar<Qux>>>(); | |
1139 | // Bar<Qux> | |
1140 | // Foo<Bar<Qux>> | |
1141 | // ------- this type argument is exactly the same as the other type | |
dfeec247 XL |
1142 | if self |
1143 | .cmp_type_arg( | |
1144 | &mut values.1, | |
1145 | &mut values.0, | |
1146 | path2, | |
1147 | sub_no_defaults_2, | |
1148 | path1, | |
1149 | &t1, | |
1150 | ) | |
1151 | .is_some() | |
0531ce1d | 1152 | { |
cc61c64b XL |
1153 | return values; |
1154 | } | |
1155 | ||
e74abb32 XL |
1156 | // We can't find anything in common, highlight relevant part of type path. |
1157 | // let x: foo::bar::Baz<Qux> = y:<foo::bar::Bar<Zar>>(); | |
1158 | // foo::bar::Baz<Qux> | |
1159 | // foo::bar::Bar<Zar> | |
1160 | // -------- this part of the path is different | |
1161 | ||
1162 | let t1_str = t1.to_string(); | |
1163 | let t2_str = t2.to_string(); | |
1164 | let min_len = t1_str.len().min(t2_str.len()); | |
1165 | ||
1166 | const SEPARATOR: &str = "::"; | |
1167 | let separator_len = SEPARATOR.len(); | |
dfeec247 XL |
1168 | let split_idx: usize = t1_str |
1169 | .split(SEPARATOR) | |
1170 | .zip(t2_str.split(SEPARATOR)) | |
1171 | .take_while(|(mod1_str, mod2_str)| mod1_str == mod2_str) | |
1172 | .map(|(mod_str, _)| mod_str.len() + separator_len) | |
1173 | .sum(); | |
1174 | ||
1175 | debug!( | |
1176 | "cmp: separator_len={}, split_idx={}, min_len={}", | |
e74abb32 XL |
1177 | separator_len, split_idx, min_len |
1178 | ); | |
1179 | ||
1180 | if split_idx >= min_len { | |
1181 | // paths are identical, highlight everything | |
1182 | ( | |
1183 | DiagnosticStyledString::highlighted(t1_str), | |
dfeec247 | 1184 | DiagnosticStyledString::highlighted(t2_str), |
e74abb32 XL |
1185 | ) |
1186 | } else { | |
1187 | let (common, uniq1) = t1_str.split_at(split_idx); | |
1188 | let (_, uniq2) = t2_str.split_at(split_idx); | |
1189 | debug!("cmp: common={}, uniq1={}, uniq2={}", common, uniq1, uniq2); | |
1190 | ||
1191 | values.0.push_normal(common); | |
1192 | values.0.push_highlighted(uniq1); | |
1193 | values.1.push_normal(common); | |
1194 | values.1.push_highlighted(uniq2); | |
1195 | ||
1196 | values | |
1197 | } | |
cc61c64b XL |
1198 | } |
1199 | } | |
ff7c6d11 | 1200 | |
0531ce1d | 1201 | // When finding T != &T, highlight only the borrow |
b7449926 | 1202 | (&ty::Ref(r1, ref_ty1, mutbl1), _) if equals(&ref_ty1, &t2) => { |
ff7c6d11 | 1203 | let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); |
94b46f34 | 1204 | push_ty_ref(&r1, ref_ty1, mutbl1, &mut values.0); |
8faf50e0 | 1205 | values.1.push_normal(t2.to_string()); |
ff7c6d11 XL |
1206 | values |
1207 | } | |
b7449926 | 1208 | (_, &ty::Ref(r2, ref_ty2, mutbl2)) if equals(&t1, &ref_ty2) => { |
ff7c6d11 | 1209 | let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); |
8faf50e0 | 1210 | values.0.push_normal(t1.to_string()); |
94b46f34 | 1211 | push_ty_ref(&r2, ref_ty2, mutbl2, &mut values.1); |
ff7c6d11 XL |
1212 | values |
1213 | } | |
1214 | ||
1215 | // When encountering &T != &mut T, highlight only the borrow | |
0bf4aa26 XL |
1216 | (&ty::Ref(r1, ref_ty1, mutbl1), &ty::Ref(r2, ref_ty2, mutbl2)) |
1217 | if equals(&ref_ty1, &ref_ty2) => | |
1218 | { | |
ff7c6d11 | 1219 | let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); |
94b46f34 XL |
1220 | push_ty_ref(&r1, ref_ty1, mutbl1, &mut values.0); |
1221 | push_ty_ref(&r2, ref_ty2, mutbl2, &mut values.1); | |
ff7c6d11 XL |
1222 | values |
1223 | } | |
1224 | ||
60c5eb7d XL |
1225 | // When encountering tuples of the same size, highlight only the differing types |
1226 | (&ty::Tuple(substs1), &ty::Tuple(substs2)) if substs1.len() == substs2.len() => { | |
dfeec247 XL |
1227 | let mut values = |
1228 | (DiagnosticStyledString::normal("("), DiagnosticStyledString::normal("(")); | |
60c5eb7d XL |
1229 | let len = substs1.len(); |
1230 | for (i, (left, right)) in substs1.types().zip(substs2.types()).enumerate() { | |
1231 | let (x1, x2) = self.cmp(left, right); | |
1232 | (values.0).0.extend(x1.0); | |
1233 | (values.1).0.extend(x2.0); | |
1234 | self.push_comma(&mut values.0, &mut values.1, len, i); | |
1235 | } | |
dfeec247 XL |
1236 | if len == 1 { |
1237 | // Keep the output for single element tuples as `(ty,)`. | |
60c5eb7d XL |
1238 | values.0.push_normal(","); |
1239 | values.1.push_normal(","); | |
1240 | } | |
1241 | values.0.push_normal(")"); | |
1242 | values.1.push_normal(")"); | |
1243 | values | |
1244 | } | |
1245 | ||
1246 | (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => { | |
1247 | let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1); | |
1248 | let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2); | |
1249 | let mut values = self.cmp_fn_sig(&sig1, &sig2); | |
1250 | let path1 = format!(" {{{}}}", self.tcx.def_path_str_with_substs(*did1, substs1)); | |
1251 | let path2 = format!(" {{{}}}", self.tcx.def_path_str_with_substs(*did2, substs2)); | |
1252 | let same_path = path1 == path2; | |
1253 | values.0.push(path1, !same_path); | |
1254 | values.1.push(path2, !same_path); | |
1255 | values | |
1256 | } | |
1257 | ||
1258 | (ty::FnDef(did1, substs1), ty::FnPtr(sig2)) => { | |
1259 | let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1); | |
1260 | let mut values = self.cmp_fn_sig(&sig1, sig2); | |
1261 | values.0.push_normal(format!( | |
1262 | " {{{}}}", | |
dfeec247 XL |
1263 | self.tcx.def_path_str_with_substs(*did1, substs1) |
1264 | )); | |
60c5eb7d XL |
1265 | values |
1266 | } | |
1267 | ||
1268 | (ty::FnPtr(sig1), ty::FnDef(did2, substs2)) => { | |
1269 | let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2); | |
1270 | let mut values = self.cmp_fn_sig(sig1, &sig2); | |
1271 | values.1.push_normal(format!( | |
1272 | " {{{}}}", | |
dfeec247 XL |
1273 | self.tcx.def_path_str_with_substs(*did2, substs2) |
1274 | )); | |
60c5eb7d XL |
1275 | values |
1276 | } | |
1277 | ||
dfeec247 | 1278 | (ty::FnPtr(sig1), ty::FnPtr(sig2)) => self.cmp_fn_sig(sig1, sig2), |
60c5eb7d | 1279 | |
cc61c64b XL |
1280 | _ => { |
1281 | if t1 == t2 { | |
1282 | // The two types are the same, elide and don't highlight. | |
dfeec247 | 1283 | (DiagnosticStyledString::normal("_"), DiagnosticStyledString::normal("_")) |
cc61c64b XL |
1284 | } else { |
1285 | // We couldn't find anything in common, highlight everything. | |
0531ce1d | 1286 | ( |
8faf50e0 XL |
1287 | DiagnosticStyledString::highlighted(t1.to_string()), |
1288 | DiagnosticStyledString::highlighted(t2.to_string()), | |
0531ce1d | 1289 | ) |
cc61c64b XL |
1290 | } |
1291 | } | |
1292 | } | |
1293 | } | |
1294 | ||
0531ce1d XL |
1295 | pub fn note_type_err( |
1296 | &self, | |
1297 | diag: &mut DiagnosticBuilder<'tcx>, | |
1298 | cause: &ObligationCause<'tcx>, | |
1299 | secondary_span: Option<(Span, String)>, | |
1300 | mut values: Option<ValuePairs<'tcx>>, | |
1301 | terr: &TypeError<'tcx>, | |
1302 | ) { | |
dfeec247 | 1303 | let span = cause.span(self.tcx); |
f9f354fc | 1304 | debug!("note_type_err cause={:?} values={:?}, terr={:?}", cause, values, terr); |
dfeec247 | 1305 | |
ff7c6d11 XL |
1306 | // For some types of errors, expected-found does not make |
1307 | // sense, so just ignore the values we were given. | |
ba9703b0 XL |
1308 | if let TypeError::CyclicTy(_) = terr { |
1309 | values = None; | |
ff7c6d11 | 1310 | } |
dfeec247 XL |
1311 | struct OpaqueTypesVisitor<'tcx> { |
1312 | types: FxHashMap<TyCategory, FxHashSet<Span>>, | |
1313 | expected: FxHashMap<TyCategory, FxHashSet<Span>>, | |
1314 | found: FxHashMap<TyCategory, FxHashSet<Span>>, | |
1315 | ignore_span: Span, | |
1316 | tcx: TyCtxt<'tcx>, | |
1317 | } | |
1318 | ||
1319 | impl<'tcx> OpaqueTypesVisitor<'tcx> { | |
1320 | fn visit_expected_found( | |
1321 | tcx: TyCtxt<'tcx>, | |
1322 | expected: Ty<'tcx>, | |
1323 | found: Ty<'tcx>, | |
1324 | ignore_span: Span, | |
1325 | ) -> Self { | |
1326 | let mut types_visitor = OpaqueTypesVisitor { | |
1327 | types: Default::default(), | |
1328 | expected: Default::default(), | |
1329 | found: Default::default(), | |
1330 | ignore_span, | |
1331 | tcx, | |
1332 | }; | |
1333 | // The visitor puts all the relevant encountered types in `self.types`, but in | |
1334 | // here we want to visit two separate types with no relation to each other, so we | |
1335 | // move the results from `types` to `expected` or `found` as appropriate. | |
1336 | expected.visit_with(&mut types_visitor); | |
1337 | std::mem::swap(&mut types_visitor.expected, &mut types_visitor.types); | |
1338 | found.visit_with(&mut types_visitor); | |
1339 | std::mem::swap(&mut types_visitor.found, &mut types_visitor.types); | |
1340 | types_visitor | |
1341 | } | |
1342 | ||
1343 | fn report(&self, err: &mut DiagnosticBuilder<'_>) { | |
1344 | self.add_labels_for_types(err, "expected", &self.expected); | |
1345 | self.add_labels_for_types(err, "found", &self.found); | |
1346 | } | |
1347 | ||
1348 | fn add_labels_for_types( | |
1349 | &self, | |
1350 | err: &mut DiagnosticBuilder<'_>, | |
1351 | target: &str, | |
1352 | types: &FxHashMap<TyCategory, FxHashSet<Span>>, | |
1353 | ) { | |
1354 | for (key, values) in types.iter() { | |
1355 | let count = values.len(); | |
1356 | let kind = key.descr(); | |
1357 | for sp in values { | |
1358 | err.span_label( | |
1359 | *sp, | |
1360 | format!( | |
1361 | "{}{}{} {}{}", | |
1362 | if sp.is_desugaring(DesugaringKind::Async) { | |
1363 | "the `Output` of this `async fn`'s " | |
1364 | } else if count == 1 { | |
1365 | "the " | |
1366 | } else { | |
1367 | "" | |
1368 | }, | |
1369 | if count > 1 { "one of the " } else { "" }, | |
1370 | target, | |
1371 | kind, | |
1372 | pluralize!(count), | |
1373 | ), | |
1374 | ); | |
1375 | } | |
1376 | } | |
1377 | } | |
1378 | } | |
1379 | ||
1380 | impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> { | |
1381 | fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { | |
1382 | if let Some((kind, def_id)) = TyCategory::from_ty(t) { | |
1383 | let span = self.tcx.def_span(def_id); | |
1384 | // Avoid cluttering the output when the "found" and error span overlap: | |
1385 | // | |
1386 | // error[E0308]: mismatched types | |
1387 | // --> $DIR/issue-20862.rs:2:5 | |
1388 | // | | |
1389 | // LL | |y| x + y | |
1390 | // | ^^^^^^^^^ | |
1391 | // | | | |
1392 | // | the found closure | |
1393 | // | expected `()`, found closure | |
1394 | // | | |
1395 | // = note: expected unit type `()` | |
1396 | // found closure `[closure@$DIR/issue-20862.rs:2:5: 2:14 x:_]` | |
1397 | if !self.ignore_span.overlaps(span) { | |
1398 | self.types.entry(kind).or_default().insert(span); | |
1399 | } | |
1400 | } | |
1401 | t.super_visit_with(self) | |
1402 | } | |
1403 | } | |
1404 | ||
e74abb32 | 1405 | debug!("note_type_err(diag={:?})", diag); |
abe05a73 XL |
1406 | let (expected_found, exp_found, is_simple_error) = match values { |
1407 | None => (None, None, false), | |
8bb4bdeb | 1408 | Some(values) => { |
abe05a73 | 1409 | let (is_simple_error, exp_found) = match values { |
8bb4bdeb | 1410 | ValuePairs::Types(exp_found) => { |
dfeec247 XL |
1411 | let is_simple_err = |
1412 | exp_found.expected.is_simple_text() && exp_found.found.is_simple_text(); | |
1413 | OpaqueTypesVisitor::visit_expected_found( | |
1414 | self.tcx, | |
1415 | exp_found.expected, | |
1416 | exp_found.found, | |
1417 | span, | |
1418 | ) | |
1419 | .report(diag); | |
abe05a73 XL |
1420 | |
1421 | (is_simple_err, Some(exp_found)) | |
8bb4bdeb | 1422 | } |
abe05a73 | 1423 | _ => (false, None), |
8bb4bdeb XL |
1424 | }; |
1425 | let vals = match self.values_str(&values) { | |
1426 | Some((expected, found)) => Some((expected, found)), | |
1427 | None => { | |
1428 | // Derived error. Cancel the emitter. | |
e1599b0c | 1429 | diag.cancel(); |
0531ce1d | 1430 | return; |
8bb4bdeb XL |
1431 | } |
1432 | }; | |
abe05a73 | 1433 | (vals, exp_found, is_simple_error) |
5bcae85e SL |
1434 | } |
1435 | }; | |
1436 | ||
e74abb32 XL |
1437 | // Ignore msg for object safe coercion |
1438 | // since E0038 message will be printed | |
1439 | match terr { | |
1440 | TypeError::ObjectUnsafeCoercion(_) => {} | |
1441 | _ => { | |
1442 | diag.span_label(span, terr.to_string()); | |
1443 | if let Some((sp, msg)) = secondary_span { | |
1444 | diag.span_label(sp, msg); | |
1445 | } | |
1446 | } | |
1447 | }; | |
5bcae85e | 1448 | if let Some((expected, found)) = expected_found { |
60c5eb7d XL |
1449 | let expected_label = exp_found.map_or("type".into(), |ef| ef.expected.prefix_string()); |
1450 | let found_label = exp_found.map_or("type".into(), |ef| ef.found.prefix_string()); | |
1451 | match (&terr, expected == found) { | |
1452 | (TypeError::Sorts(values), extra) => { | |
1453 | let sort_string = |ty: Ty<'tcx>| match (extra, &ty.kind) { | |
1454 | (true, ty::Opaque(def_id, _)) => format!( | |
1455 | " (opaque type at {})", | |
dfeec247 XL |
1456 | self.tcx |
1457 | .sess | |
1458 | .source_map() | |
60c5eb7d XL |
1459 | .mk_substr_filename(self.tcx.def_span(*def_id)), |
1460 | ), | |
1461 | (true, _) => format!(" ({})", ty.sort_string(self.tcx)), | |
1462 | (false, _) => "".to_string(), | |
1463 | }; | |
dfeec247 XL |
1464 | if !(values.expected.is_simple_text() && values.found.is_simple_text()) |
1465 | || (exp_found.map_or(false, |ef| { | |
60c5eb7d XL |
1466 | // This happens when the type error is a subset of the expectation, |
1467 | // like when you have two references but one is `usize` and the other | |
1468 | // is `f32`. In those cases we still want to show the `note`. If the | |
1469 | // value from `ef` is `Infer(_)`, then we ignore it. | |
1470 | if !ef.expected.is_ty_infer() { | |
1471 | ef.expected != values.expected | |
1472 | } else if !ef.found.is_ty_infer() { | |
1473 | ef.found != values.found | |
1474 | } else { | |
1475 | false | |
1476 | } | |
dfeec247 XL |
1477 | })) |
1478 | { | |
60c5eb7d XL |
1479 | diag.note_expected_found_extra( |
1480 | &expected_label, | |
1481 | expected, | |
1482 | &found_label, | |
1483 | found, | |
1484 | &sort_string(values.expected), | |
1485 | &sort_string(values.found), | |
1486 | ); | |
1487 | } | |
8bb4bdeb | 1488 | } |
60c5eb7d | 1489 | (TypeError::ObjectUnsafeCoercion(_), _) => { |
e74abb32 XL |
1490 | diag.note_unsuccessfull_coercion(found, expected); |
1491 | } | |
60c5eb7d | 1492 | (_, _) => { |
e74abb32 XL |
1493 | debug!( |
1494 | "note_type_err: exp_found={:?}, expected={:?} found={:?}", | |
1495 | exp_found, expected, found | |
1496 | ); | |
60c5eb7d XL |
1497 | if !is_simple_error || terr.must_include_note() { |
1498 | diag.note_expected_found(&expected_label, expected, &found_label, found); | |
abe05a73 | 1499 | } |
9e0c209e | 1500 | } |
5bcae85e SL |
1501 | } |
1502 | } | |
60c5eb7d XL |
1503 | if let Some(exp_found) = exp_found { |
1504 | self.suggest_as_ref_where_appropriate(span, &exp_found, diag); | |
1505 | } | |
5bcae85e | 1506 | |
60c5eb7d XL |
1507 | // In some (most?) cases cause.body_id points to actual body, but in some cases |
1508 | // it's a actual definition. According to the comments (e.g. in | |
1509 | // librustc_typeck/check/compare_method.rs:compare_predicate_entailment) the latter | |
1510 | // is relied upon by some other code. This might (or might not) need cleanup. | |
dfeec247 XL |
1511 | let body_owner_def_id = |
1512 | self.tcx.hir().opt_local_def_id(cause.body_id).unwrap_or_else(|| { | |
60c5eb7d XL |
1513 | self.tcx.hir().body_owner_def_id(hir::BodyId { hir_id: cause.body_id }) |
1514 | }); | |
1515 | self.check_and_note_conflicting_crates(diag, terr); | |
f9f354fc | 1516 | self.tcx.note_and_explain_type_err(diag, terr, cause, span, body_owner_def_id.to_def_id()); |
abe05a73 XL |
1517 | |
1518 | // It reads better to have the error origin as the final | |
1519 | // thing. | |
f9f354fc | 1520 | self.note_error_origin(diag, cause, exp_found); |
5bcae85e SL |
1521 | } |
1522 | ||
0731742a | 1523 | /// When encountering a case where `.as_ref()` on a `Result` or `Option` would be appropriate, |
60c5eb7d | 1524 | /// suggests it. |
0731742a XL |
1525 | fn suggest_as_ref_where_appropriate( |
1526 | &self, | |
1527 | span: Span, | |
1528 | exp_found: &ty::error::ExpectedFound<Ty<'tcx>>, | |
1529 | diag: &mut DiagnosticBuilder<'tcx>, | |
1530 | ) { | |
ba9703b0 XL |
1531 | if let (ty::Adt(exp_def, exp_substs), ty::Ref(_, found_ty, _)) = |
1532 | (&exp_found.expected.kind, &exp_found.found.kind) | |
1533 | { | |
1534 | if let ty::Adt(found_def, found_substs) = found_ty.kind { | |
1535 | let path_str = format!("{:?}", exp_def); | |
1536 | if exp_def == &found_def { | |
1537 | let opt_msg = "you can convert from `&Option<T>` to `Option<&T>` using \ | |
0731742a | 1538 | `.as_ref()`"; |
ba9703b0 | 1539 | let result_msg = "you can convert from `&Result<T, E>` to \ |
0731742a | 1540 | `Result<&T, &E>` using `.as_ref()`"; |
ba9703b0 XL |
1541 | let have_as_ref = &[ |
1542 | ("std::option::Option", opt_msg), | |
1543 | ("core::option::Option", opt_msg), | |
1544 | ("std::result::Result", result_msg), | |
1545 | ("core::result::Result", result_msg), | |
1546 | ]; | |
1547 | if let Some(msg) = have_as_ref | |
1548 | .iter() | |
f9f354fc | 1549 | .find_map(|(path, msg)| (&path_str == path).then_some(msg)) |
ba9703b0 XL |
1550 | { |
1551 | let mut show_suggestion = true; | |
1552 | for (exp_ty, found_ty) in exp_substs.types().zip(found_substs.types()) { | |
1553 | match exp_ty.kind { | |
1554 | ty::Ref(_, exp_ty, _) => { | |
1555 | match (&exp_ty.kind, &found_ty.kind) { | |
1556 | (_, ty::Param(_)) | |
1557 | | (_, ty::Infer(_)) | |
1558 | | (ty::Param(_), _) | |
1559 | | (ty::Infer(_), _) => {} | |
1560 | _ if ty::TyS::same_type(exp_ty, found_ty) => {} | |
1561 | _ => show_suggestion = false, | |
1562 | }; | |
0731742a | 1563 | } |
ba9703b0 XL |
1564 | ty::Param(_) | ty::Infer(_) => {} |
1565 | _ => show_suggestion = false, | |
0731742a XL |
1566 | } |
1567 | } | |
ba9703b0 XL |
1568 | if let (Ok(snippet), true) = |
1569 | (self.tcx.sess.source_map().span_to_snippet(span), show_suggestion) | |
1570 | { | |
1571 | diag.span_suggestion( | |
1572 | span, | |
1573 | msg, | |
1574 | format!("{}.as_ref()", snippet), | |
1575 | Applicability::MachineApplicable, | |
1576 | ); | |
1577 | } | |
0731742a XL |
1578 | } |
1579 | } | |
1580 | } | |
0731742a XL |
1581 | } |
1582 | } | |
1583 | ||
0531ce1d XL |
1584 | pub fn report_and_explain_type_error( |
1585 | &self, | |
1586 | trace: TypeTrace<'tcx>, | |
1587 | terr: &TypeError<'tcx>, | |
1588 | ) -> DiagnosticBuilder<'tcx> { | |
dfeec247 | 1589 | debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr); |
abe05a73 | 1590 | |
48663c56 | 1591 | let span = trace.cause.span(self.tcx); |
ff7c6d11 XL |
1592 | let failure_code = trace.cause.as_failure_code(terr); |
1593 | let mut diag = match failure_code { | |
e74abb32 | 1594 | FailureCode::Error0038(did) => { |
74b04a01 | 1595 | let violations = self.tcx.object_safety_violations(did); |
dfeec247 | 1596 | report_object_safety_error(self.tcx, span, did, violations) |
e74abb32 | 1597 | } |
ff7c6d11 | 1598 | FailureCode::Error0317(failure_str) => { |
c30ab7b3 | 1599 | struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str) |
32a655c1 | 1600 | } |
ff7c6d11 | 1601 | FailureCode::Error0580(failure_str) => { |
32a655c1 SL |
1602 | struct_span_err!(self.tcx.sess, span, E0580, "{}", failure_str) |
1603 | } | |
ff7c6d11 | 1604 | FailureCode::Error0308(failure_str) => { |
c30ab7b3 | 1605 | struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str) |
32a655c1 | 1606 | } |
ff7c6d11 XL |
1607 | FailureCode::Error0644(failure_str) => { |
1608 | struct_span_err!(self.tcx.sess, span, E0644, "{}", failure_str) | |
1609 | } | |
c30ab7b3 | 1610 | }; |
476ff2be | 1611 | self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr); |
5bcae85e | 1612 | diag |
1a4d82fc JJ |
1613 | } |
1614 | ||
0531ce1d XL |
1615 | fn values_str( |
1616 | &self, | |
1617 | values: &ValuePairs<'tcx>, | |
1618 | ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { | |
1a4d82fc | 1619 | match *values { |
cc61c64b | 1620 | infer::Types(ref exp_found) => self.expected_found_str_ty(exp_found), |
0531ce1d | 1621 | infer::Regions(ref exp_found) => self.expected_found_str(exp_found), |
48663c56 | 1622 | infer::Consts(ref exp_found) => self.expected_found_str(exp_found), |
60c5eb7d XL |
1623 | infer::TraitRefs(ref exp_found) => { |
1624 | let pretty_exp_found = ty::error::ExpectedFound { | |
1625 | expected: exp_found.expected.print_only_trait_path(), | |
dfeec247 | 1626 | found: exp_found.found.print_only_trait_path(), |
60c5eb7d XL |
1627 | }; |
1628 | self.expected_found_str(&pretty_exp_found) | |
dfeec247 | 1629 | } |
60c5eb7d XL |
1630 | infer::PolyTraitRefs(ref exp_found) => { |
1631 | let pretty_exp_found = ty::error::ExpectedFound { | |
1632 | expected: exp_found.expected.print_only_trait_path(), | |
dfeec247 | 1633 | found: exp_found.found.print_only_trait_path(), |
60c5eb7d XL |
1634 | }; |
1635 | self.expected_found_str(&pretty_exp_found) | |
dfeec247 | 1636 | } |
1a4d82fc JJ |
1637 | } |
1638 | } | |
1639 | ||
0531ce1d XL |
1640 | fn expected_found_str_ty( |
1641 | &self, | |
1642 | exp_found: &ty::error::ExpectedFound<Ty<'tcx>>, | |
1643 | ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { | |
dc9dc135 | 1644 | let exp_found = self.resolve_vars_if_possible(exp_found); |
cc61c64b XL |
1645 | if exp_found.references_error() { |
1646 | return None; | |
1647 | } | |
1648 | ||
1649 | Some(self.cmp(exp_found.expected, exp_found.found)) | |
1650 | } | |
1651 | ||
1652 | /// Returns a string of the form "expected `{}`, found `{}`". | |
5bcae85e | 1653 | fn expected_found_str<T: fmt::Display + TypeFoldable<'tcx>>( |
1a4d82fc | 1654 | &self, |
0531ce1d XL |
1655 | exp_found: &ty::error::ExpectedFound<T>, |
1656 | ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { | |
dc9dc135 | 1657 | let exp_found = self.resolve_vars_if_possible(exp_found); |
5bcae85e | 1658 | if exp_found.references_error() { |
1a4d82fc JJ |
1659 | return None; |
1660 | } | |
1661 | ||
0531ce1d | 1662 | Some(( |
8faf50e0 XL |
1663 | DiagnosticStyledString::highlighted(exp_found.expected.to_string()), |
1664 | DiagnosticStyledString::highlighted(exp_found.found.to_string()), | |
0531ce1d | 1665 | )) |
1a4d82fc JJ |
1666 | } |
1667 | ||
0531ce1d XL |
1668 | pub fn report_generic_bound_failure( |
1669 | &self, | |
0531ce1d XL |
1670 | span: Span, |
1671 | origin: Option<SubregionOrigin<'tcx>>, | |
1672 | bound_kind: GenericKind<'tcx>, | |
1673 | sub: Region<'tcx>, | |
1674 | ) { | |
f9f354fc | 1675 | self.construct_generic_bound_failure(span, origin, bound_kind, sub).emit(); |
8faf50e0 XL |
1676 | } |
1677 | ||
1678 | pub fn construct_generic_bound_failure( | |
1679 | &self, | |
8faf50e0 XL |
1680 | span: Span, |
1681 | origin: Option<SubregionOrigin<'tcx>>, | |
1682 | bound_kind: GenericKind<'tcx>, | |
1683 | sub: Region<'tcx>, | |
0bf4aa26 | 1684 | ) -> DiagnosticBuilder<'a> { |
f9f354fc | 1685 | let hir = &self.tcx.hir(); |
ea8adc8c XL |
1686 | // Attempt to obtain the span of the parameter so we can |
1687 | // suggest adding an explicit lifetime bound to it. | |
f9f354fc XL |
1688 | let generics = |
1689 | self.in_progress_tables.and_then(|table| table.borrow().hir_owner).map(|table_owner| { | |
1690 | let hir_id = hir.as_local_hir_id(table_owner); | |
1691 | let parent_id = hir.get_parent_item(hir_id); | |
1692 | ( | |
1693 | // Parent item could be a `mod`, so we check the HIR before calling: | |
1694 | if let Some(Node::Item(Item { | |
1695 | kind: ItemKind::Trait(..) | ItemKind::Impl { .. }, | |
1696 | .. | |
1697 | })) = hir.find(parent_id) | |
1698 | { | |
1699 | Some(self.tcx.generics_of(hir.local_def_id(parent_id).to_def_id())) | |
ea8adc8c XL |
1700 | } else { |
1701 | None | |
f9f354fc XL |
1702 | }, |
1703 | self.tcx.generics_of(table_owner.to_def_id()), | |
1704 | ) | |
1705 | }); | |
1706 | let type_param_span = match (generics, bound_kind) { | |
1707 | (Some((_, ref generics)), GenericKind::Param(ref param)) => { | |
1708 | // Account for the case where `param` corresponds to `Self`, | |
1709 | // which doesn't have the expected type argument. | |
1710 | if !(generics.has_self && param.index == 0) { | |
1711 | let type_param = generics.type_param(param, self.tcx); | |
1712 | type_param.def_id.as_local().map(|def_id| { | |
1713 | // Get the `hir::Param` to verify whether it already has any bounds. | |
1714 | // We do this to avoid suggesting code that ends up as `T: 'a'b`, | |
1715 | // instead we suggest `T: 'a + 'b` in that case. | |
1716 | let id = hir.as_local_hir_id(def_id); | |
1717 | let mut has_bounds = false; | |
1718 | if let Node::GenericParam(param) = hir.get(id) { | |
1719 | has_bounds = !param.bounds.is_empty(); | |
1720 | } | |
1721 | let sp = hir.span(id); | |
1722 | // `sp` only covers `T`, change it so that it covers | |
1723 | // `T:` when appropriate | |
1724 | let is_impl_trait = bound_kind.to_string().starts_with("impl "); | |
1725 | let sp = if has_bounds && !is_impl_trait { | |
1726 | sp.to(self | |
1727 | .tcx | |
1728 | .sess | |
1729 | .source_map() | |
1730 | .next_point(self.tcx.sess.source_map().next_point(sp))) | |
1731 | } else { | |
1732 | sp | |
1733 | }; | |
1734 | (sp, has_bounds, is_impl_trait) | |
1735 | }) | |
1736 | } else { | |
1737 | None | |
1738 | } | |
ea8adc8c XL |
1739 | } |
1740 | _ => None, | |
1741 | }; | |
f9f354fc XL |
1742 | let new_lt = generics |
1743 | .as_ref() | |
1744 | .and_then(|(parent_g, g)| { | |
1745 | let possible: Vec<_> = (b'a'..=b'z').map(|c| format!("'{}", c as char)).collect(); | |
1746 | let mut lts_names = g | |
1747 | .params | |
1748 | .iter() | |
1749 | .filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime)) | |
1750 | .map(|p| p.name.as_str()) | |
1751 | .collect::<Vec<_>>(); | |
1752 | if let Some(g) = parent_g { | |
1753 | lts_names.extend( | |
1754 | g.params | |
1755 | .iter() | |
1756 | .filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime)) | |
1757 | .map(|p| p.name.as_str()), | |
1758 | ); | |
1759 | } | |
1760 | let lts = lts_names.iter().map(|s| -> &str { &*s }).collect::<Vec<_>>(); | |
1761 | possible.into_iter().find(|candidate| !lts.contains(&candidate.as_str())) | |
1762 | }) | |
1763 | .unwrap_or("'lt".to_string()); | |
1764 | let add_lt_sugg = generics | |
1765 | .as_ref() | |
1766 | .and_then(|(_, g)| g.params.first()) | |
1767 | .and_then(|param| param.def_id.as_local()) | |
1768 | .map(|def_id| { | |
1769 | (hir.span(hir.as_local_hir_id(def_id)).shrink_to_lo(), format!("{}, ", new_lt)) | |
1770 | }); | |
1a4d82fc JJ |
1771 | |
1772 | let labeled_user_string = match bound_kind { | |
0531ce1d XL |
1773 | GenericKind::Param(ref p) => format!("the parameter type `{}`", p), |
1774 | GenericKind::Projection(ref p) => format!("the associated type `{}`", p), | |
1a4d82fc JJ |
1775 | }; |
1776 | ||
ff7c6d11 | 1777 | if let Some(SubregionOrigin::CompareImplMethodObligation { |
0531ce1d XL |
1778 | span, |
1779 | item_name, | |
1780 | impl_item_def_id, | |
1781 | trait_item_def_id, | |
1782 | }) = origin | |
1783 | { | |
8faf50e0 | 1784 | return self.report_extra_impl_obligation( |
0531ce1d XL |
1785 | span, |
1786 | item_name, | |
1787 | impl_item_def_id, | |
1788 | trait_item_def_id, | |
1789 | &format!("`{}: {}`", bound_kind, sub), | |
8faf50e0 | 1790 | ); |
c30ab7b3 SL |
1791 | } |
1792 | ||
0531ce1d XL |
1793 | fn binding_suggestion<'tcx, S: fmt::Display>( |
1794 | err: &mut DiagnosticBuilder<'tcx>, | |
0731742a | 1795 | type_param_span: Option<(Span, bool, bool)>, |
0531ce1d XL |
1796 | bound_kind: GenericKind<'tcx>, |
1797 | sub: S, | |
1798 | ) { | |
74b04a01 | 1799 | let msg = "consider adding an explicit lifetime bound"; |
0731742a XL |
1800 | if let Some((sp, has_lifetimes, is_impl_trait)) = type_param_span { |
1801 | let suggestion = if is_impl_trait { | |
1802 | format!("{} + {}", bound_kind, sub) | |
1803 | } else { | |
1804 | let tail = if has_lifetimes { " + " } else { "" }; | |
1805 | format!("{}: {}{}", bound_kind, sub, tail) | |
1806 | }; | |
74b04a01 | 1807 | err.span_suggestion( |
0bf4aa26 | 1808 | sp, |
74b04a01 | 1809 | &format!("{}...", msg), |
0bf4aa26 XL |
1810 | suggestion, |
1811 | Applicability::MaybeIncorrect, // Issue #41966 | |
94b46f34 | 1812 | ); |
ea8adc8c | 1813 | } else { |
74b04a01 XL |
1814 | let consider = format!( |
1815 | "{} {}...", | |
1816 | msg, | |
1817 | if type_param_span.map(|(_, _, is_impl_trait)| is_impl_trait).unwrap_or(false) { | |
1818 | format!(" `{}` to `{}`", sub, bound_kind) | |
1819 | } else { | |
1820 | format!("`{}: {}`", bound_kind, sub) | |
1821 | }, | |
1822 | ); | |
0731742a | 1823 | err.help(&consider); |
ea8adc8c XL |
1824 | } |
1825 | } | |
1826 | ||
f9f354fc XL |
1827 | let new_binding_suggestion = |
1828 | |err: &mut DiagnosticBuilder<'tcx>, | |
1829 | type_param_span: Option<(Span, bool, bool)>, | |
1830 | bound_kind: GenericKind<'tcx>| { | |
1831 | let msg = "consider introducing an explicit lifetime bound"; | |
1832 | if let Some((sp, has_lifetimes, is_impl_trait)) = type_param_span { | |
1833 | let suggestion = if is_impl_trait { | |
1834 | (sp.shrink_to_hi(), format!(" + {}", new_lt)) | |
1835 | } else { | |
1836 | let tail = if has_lifetimes { " +" } else { "" }; | |
1837 | (sp, format!("{}: {}{}", bound_kind, new_lt, tail)) | |
1838 | }; | |
1839 | let mut sugg = | |
1840 | vec![suggestion, (span.shrink_to_hi(), format!(" + {}", new_lt))]; | |
1841 | if let Some(lt) = add_lt_sugg { | |
1842 | sugg.push(lt); | |
1843 | sugg.rotate_right(1); | |
1844 | } | |
1845 | // `MaybeIncorrect` due to issue #41966. | |
1846 | err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect); | |
1847 | } | |
1848 | }; | |
1849 | ||
9e0c209e | 1850 | let mut err = match *sub { |
dfeec247 XL |
1851 | ty::ReEarlyBound(ty::EarlyBoundRegion { name, .. }) |
1852 | | ty::ReFree(ty::FreeRegion { bound_region: ty::BrNamed(_, name), .. }) => { | |
1a4d82fc | 1853 | // Does the required lifetime have a nice name we can print? |
0531ce1d XL |
1854 | let mut err = struct_span_err!( |
1855 | self.tcx.sess, | |
1856 | span, | |
1857 | E0309, | |
1858 | "{} may not live long enough", | |
1859 | labeled_user_string | |
1860 | ); | |
74b04a01 | 1861 | // Explicitly use the name instead of `sub`'s `Display` impl. The `Display` impl |
dfeec247 XL |
1862 | // for the bound is not suitable for suggestions when `-Zverbose` is set because it |
1863 | // uses `Debug` output, so we handle it specially here so that suggestions are | |
1864 | // always correct. | |
1865 | binding_suggestion(&mut err, type_param_span, bound_kind, name); | |
9cc50fc6 | 1866 | err |
1a4d82fc JJ |
1867 | } |
1868 | ||
1869 | ty::ReStatic => { | |
1870 | // Does the required lifetime have a nice name we can print? | |
0531ce1d XL |
1871 | let mut err = struct_span_err!( |
1872 | self.tcx.sess, | |
1873 | span, | |
1874 | E0310, | |
1875 | "{} may not live long enough", | |
1876 | labeled_user_string | |
1877 | ); | |
ea8adc8c | 1878 | binding_suggestion(&mut err, type_param_span, bound_kind, "'static"); |
9cc50fc6 | 1879 | err |
1a4d82fc JJ |
1880 | } |
1881 | ||
1882 | _ => { | |
1883 | // If not, be less specific. | |
0531ce1d XL |
1884 | let mut err = struct_span_err!( |
1885 | self.tcx.sess, | |
1886 | span, | |
1887 | E0311, | |
1888 | "{} may not live long enough", | |
1889 | labeled_user_string | |
1890 | ); | |
dfeec247 XL |
1891 | note_and_explain_region( |
1892 | self.tcx, | |
9cc50fc6 | 1893 | &mut err, |
c34b1796 | 1894 | &format!("{} must be valid for ", labeled_user_string), |
1a4d82fc | 1895 | sub, |
0531ce1d XL |
1896 | "...", |
1897 | ); | |
f9f354fc XL |
1898 | if let Some(infer::RelateParamBound(_, t)) = origin { |
1899 | let t = self.resolve_vars_if_possible(&t); | |
1900 | match t.kind { | |
1901 | // We've got: | |
1902 | // fn get_later<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ | |
1903 | // suggest: | |
1904 | // fn get_later<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a | |
1905 | ty::Closure(_, _substs) | ty::Opaque(_, _substs) => { | |
1906 | new_binding_suggestion(&mut err, type_param_span, bound_kind); | |
1907 | } | |
1908 | _ => { | |
1909 | binding_suggestion(&mut err, type_param_span, bound_kind, new_lt); | |
1910 | } | |
1911 | } | |
1912 | } | |
9cc50fc6 | 1913 | err |
1a4d82fc | 1914 | } |
9cc50fc6 | 1915 | }; |
e9174d1e | 1916 | |
ff7c6d11 XL |
1917 | if let Some(origin) = origin { |
1918 | self.note_region_origin(&mut err, &origin); | |
1919 | } | |
8faf50e0 | 1920 | err |
1a4d82fc JJ |
1921 | } |
1922 | ||
0531ce1d XL |
1923 | fn report_sub_sup_conflict( |
1924 | &self, | |
0531ce1d XL |
1925 | var_origin: RegionVariableOrigin, |
1926 | sub_origin: SubregionOrigin<'tcx>, | |
1927 | sub_region: Region<'tcx>, | |
1928 | sup_origin: SubregionOrigin<'tcx>, | |
1929 | sup_region: Region<'tcx>, | |
1930 | ) { | |
9cc50fc6 | 1931 | let mut err = self.report_inference_failure(var_origin); |
1a4d82fc | 1932 | |
dfeec247 XL |
1933 | note_and_explain_region( |
1934 | self.tcx, | |
0531ce1d | 1935 | &mut err, |
1a4d82fc JJ |
1936 | "first, the lifetime cannot outlive ", |
1937 | sup_region, | |
0531ce1d XL |
1938 | "...", |
1939 | ); | |
1a4d82fc | 1940 | |
f9f354fc XL |
1941 | debug!("report_sub_sup_conflict: var_origin={:?}", var_origin); |
1942 | debug!("report_sub_sup_conflict: sub_region={:?}", sub_region); | |
1943 | debug!("report_sub_sup_conflict: sub_origin={:?}", sub_origin); | |
1944 | debug!("report_sub_sup_conflict: sup_region={:?}", sup_region); | |
1945 | debug!("report_sub_sup_conflict: sup_origin={:?}", sup_origin); | |
1946 | ||
ba9703b0 XL |
1947 | if let (&infer::Subtype(ref sup_trace), &infer::Subtype(ref sub_trace)) = |
1948 | (&sup_origin, &sub_origin) | |
1949 | { | |
ba9703b0 XL |
1950 | debug!("report_sub_sup_conflict: sup_trace={:?}", sup_trace); |
1951 | debug!("report_sub_sup_conflict: sub_trace={:?}", sub_trace); | |
1952 | debug!("report_sub_sup_conflict: sup_trace.values={:?}", sup_trace.values); | |
1953 | debug!("report_sub_sup_conflict: sub_trace.values={:?}", sub_trace.values); | |
1954 | ||
1955 | if let (Some((sup_expected, sup_found)), Some((sub_expected, sub_found))) = | |
1956 | (self.values_str(&sup_trace.values), self.values_str(&sub_trace.values)) | |
1957 | { | |
1958 | if sub_expected == sup_expected && sub_found == sup_found { | |
1959 | note_and_explain_region( | |
1960 | self.tcx, | |
ba9703b0 XL |
1961 | &mut err, |
1962 | "...but the lifetime must also be valid for ", | |
1963 | sub_region, | |
1964 | "...", | |
1965 | ); | |
1966 | err.span_note( | |
1967 | sup_trace.cause.span, | |
1968 | &format!("...so that the {}", sup_trace.cause.as_requirement_str()), | |
1969 | ); | |
dfeec247 | 1970 | |
ba9703b0 XL |
1971 | err.note_expected_found(&"", sup_expected, &"", sup_found); |
1972 | err.emit(); | |
1973 | return; | |
2c00a5a8 XL |
1974 | } |
1975 | } | |
2c00a5a8 XL |
1976 | } |
1977 | ||
9cc50fc6 | 1978 | self.note_region_origin(&mut err, &sup_origin); |
1a4d82fc | 1979 | |
dfeec247 XL |
1980 | note_and_explain_region( |
1981 | self.tcx, | |
0531ce1d | 1982 | &mut err, |
1a4d82fc JJ |
1983 | "but, the lifetime must be valid for ", |
1984 | sub_region, | |
0531ce1d XL |
1985 | "...", |
1986 | ); | |
1a4d82fc | 1987 | |
9cc50fc6 SL |
1988 | self.note_region_origin(&mut err, &sub_origin); |
1989 | err.emit(); | |
1a4d82fc | 1990 | } |
1a4d82fc JJ |
1991 | } |
1992 | ||
dc9dc135 | 1993 | impl<'a, 'tcx> InferCtxt<'a, 'tcx> { |
0531ce1d XL |
1994 | fn report_inference_failure( |
1995 | &self, | |
1996 | var_origin: RegionVariableOrigin, | |
1997 | ) -> DiagnosticBuilder<'tcx> { | |
62682a34 | 1998 | let br_string = |br: ty::BoundRegion| { |
532ac7d7 XL |
1999 | let mut s = match br { |
2000 | ty::BrNamed(_, name) => name.to_string(), | |
2001 | _ => String::new(), | |
2002 | }; | |
62682a34 SL |
2003 | if !s.is_empty() { |
2004 | s.push_str(" "); | |
2005 | } | |
2006 | s | |
2007 | }; | |
1a4d82fc | 2008 | let var_description = match var_origin { |
b7449926 | 2009 | infer::MiscVariable(_) => String::new(), |
1a4d82fc JJ |
2010 | infer::PatternRegion(_) => " for pattern".to_string(), |
2011 | infer::AddrOfRegion(_) => " for borrow expression".to_string(), | |
1a4d82fc JJ |
2012 | infer::Autoref(_) => " for autoref".to_string(), |
2013 | infer::Coercion(_) => " for automatic coercion".to_string(), | |
2014 | infer::LateBoundRegion(_, br, infer::FnCall) => { | |
0531ce1d | 2015 | format!(" for lifetime parameter {}in function call", br_string(br)) |
1a4d82fc JJ |
2016 | } |
2017 | infer::LateBoundRegion(_, br, infer::HigherRankedType) => { | |
62682a34 | 2018 | format!(" for lifetime parameter {}in generic type", br_string(br)) |
1a4d82fc | 2019 | } |
0531ce1d XL |
2020 | infer::LateBoundRegion(_, br, infer::AssocTypeProjection(def_id)) => format!( |
2021 | " for lifetime parameter {}in trait containing associated type `{}`", | |
2022 | br_string(br), | |
8faf50e0 | 2023 | self.tcx.associated_item(def_id).ident |
0531ce1d XL |
2024 | ), |
2025 | infer::EarlyBoundRegion(_, name) => format!(" for lifetime parameter `{}`", name), | |
1a4d82fc | 2026 | infer::BoundRegionInCoherence(name) => { |
0531ce1d | 2027 | format!(" for lifetime parameter `{}` in coherence check", name) |
1a4d82fc JJ |
2028 | } |
2029 | infer::UpvarRegion(ref upvar_id, _) => { | |
dc9dc135 | 2030 | let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id); |
ea8adc8c | 2031 | format!(" for capture of `{}` by closure", var_name) |
1a4d82fc | 2032 | } |
abe05a73 | 2033 | infer::NLL(..) => bug!("NLL variable found in lexical phase"), |
1a4d82fc JJ |
2034 | }; |
2035 | ||
0531ce1d XL |
2036 | struct_span_err!( |
2037 | self.tcx.sess, | |
2038 | var_origin.span(), | |
2039 | E0495, | |
2040 | "cannot infer an appropriate lifetime{} \ | |
2041 | due to conflicting requirements", | |
2042 | var_description | |
2043 | ) | |
1a4d82fc | 2044 | } |
1a4d82fc JJ |
2045 | } |
2046 | ||
ff7c6d11 | 2047 | enum FailureCode { |
e74abb32 | 2048 | Error0038(DefId), |
ff7c6d11 XL |
2049 | Error0317(&'static str), |
2050 | Error0580(&'static str), | |
2051 | Error0308(&'static str), | |
2052 | Error0644(&'static str), | |
2053 | } | |
2054 | ||
74b04a01 XL |
2055 | trait ObligationCauseExt<'tcx> { |
2056 | fn as_failure_code(&self, terr: &TypeError<'tcx>) -> FailureCode; | |
2057 | fn as_requirement_str(&self) -> &'static str; | |
2058 | } | |
2059 | ||
2060 | impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { | |
ff7c6d11 XL |
2061 | fn as_failure_code(&self, terr: &TypeError<'tcx>) -> FailureCode { |
2062 | use self::FailureCode::*; | |
9fa01778 | 2063 | use crate::traits::ObligationCauseCode::*; |
476ff2be | 2064 | match self.code { |
ff7c6d11 | 2065 | CompareImplMethodObligation { .. } => Error0308("method not compatible with trait"), |
dfeec247 XL |
2066 | CompareImplTypeObligation { .. } => Error0308("type not compatible with trait"), |
2067 | MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => { | |
e1599b0c | 2068 | Error0308(match source { |
dfeec247 XL |
2069 | hir::MatchSource::IfLetDesugar { .. } => { |
2070 | "`if let` arms have incompatible types" | |
2071 | } | |
e1599b0c XL |
2072 | hir::MatchSource::TryDesugar => { |
2073 | "try expression alternatives have incompatible types" | |
2074 | } | |
dfeec247 XL |
2075 | _ => "`match` arms have incompatible types", |
2076 | }) | |
2077 | } | |
2078 | IfExpression { .. } => Error0308("`if` and `else` have incompatible types"), | |
2079 | IfExpressionWithNoElse => Error0317("`if` may be missing an `else` clause"), | |
2080 | MainFunctionType => Error0580("`main` function has wrong type"), | |
2081 | StartFunctionType => Error0308("`#[start]` function has wrong type"), | |
ff7c6d11 | 2082 | IntrinsicType => Error0308("intrinsic has wrong type"), |
e1599b0c | 2083 | MethodReceiver => Error0308("mismatched `self` parameter type"), |
ff7c6d11 XL |
2084 | |
2085 | // In the case where we have no more specific thing to | |
2086 | // say, also take a look at the error code, maybe we can | |
2087 | // tailor to that. | |
2088 | _ => match terr { | |
0531ce1d XL |
2089 | TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() => { |
2090 | Error0644("closure/generator type that references itself") | |
2091 | } | |
e1599b0c XL |
2092 | TypeError::IntrinsicCast => { |
2093 | Error0308("cannot coerce intrinsics to function pointers") | |
2094 | } | |
dfeec247 | 2095 | TypeError::ObjectUnsafeCoercion(did) => Error0038(*did), |
0531ce1d XL |
2096 | _ => Error0308("mismatched types"), |
2097 | }, | |
476ff2be SL |
2098 | } |
2099 | } | |
2100 | ||
2101 | fn as_requirement_str(&self) -> &'static str { | |
9fa01778 | 2102 | use crate::traits::ObligationCauseCode::*; |
476ff2be SL |
2103 | match self.code { |
2104 | CompareImplMethodObligation { .. } => "method type is compatible with trait", | |
dfeec247 | 2105 | CompareImplTypeObligation { .. } => "associated type is compatible with trait", |
476ff2be | 2106 | ExprAssignable => "expression is assignable", |
e1599b0c | 2107 | MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => match source { |
0531ce1d | 2108 | hir::MatchSource::IfLetDesugar { .. } => "`if let` arms have compatible types", |
dfeec247 | 2109 | _ => "`match` arms have compatible types", |
476ff2be | 2110 | }, |
dfeec247 XL |
2111 | IfExpression { .. } => "`if` and `else` have incompatible types", |
2112 | IfExpressionWithNoElse => "`if` missing an `else` returns `()`", | |
476ff2be | 2113 | MainFunctionType => "`main` function has the correct type", |
dfeec247 | 2114 | StartFunctionType => "`#[start]` function has the correct type", |
476ff2be SL |
2115 | IntrinsicType => "intrinsic has the correct type", |
2116 | MethodReceiver => "method receiver has the correct type", | |
2117 | _ => "types are compatible", | |
2118 | } | |
2119 | } | |
2120 | } | |
dfeec247 XL |
2121 | |
2122 | /// This is a bare signal of what kind of type we're dealing with. `ty::TyKind` tracks | |
2123 | /// extra information about each type, but we only care about the category. | |
2124 | #[derive(Clone, Copy, PartialEq, Eq, Hash)] | |
ba9703b0 | 2125 | pub enum TyCategory { |
dfeec247 XL |
2126 | Closure, |
2127 | Opaque, | |
2128 | Generator, | |
2129 | Foreign, | |
2130 | } | |
2131 | ||
2132 | impl TyCategory { | |
2133 | fn descr(&self) -> &'static str { | |
2134 | match self { | |
2135 | Self::Closure => "closure", | |
2136 | Self::Opaque => "opaque type", | |
2137 | Self::Generator => "generator", | |
2138 | Self::Foreign => "foreign type", | |
2139 | } | |
2140 | } | |
2141 | ||
2142 | pub fn from_ty(ty: Ty<'_>) -> Option<(Self, DefId)> { | |
2143 | match ty.kind { | |
2144 | ty::Closure(def_id, _) => Some((Self::Closure, def_id)), | |
2145 | ty::Opaque(def_id, _) => Some((Self::Opaque, def_id)), | |
2146 | ty::Generator(def_id, ..) => Some((Self::Generator, def_id)), | |
2147 | ty::Foreign(def_id) => Some((Self::Foreign, def_id)), | |
2148 | _ => None, | |
2149 | } | |
2150 | } | |
2151 | } |