]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | //! Error Reporting Code for the inference engine | |
12 | //! | |
13 | //! Because of the way inference, and in particular region inference, | |
14 | //! works, it often happens that errors are not detected until far after | |
15 | //! the relevant line of code has been type-checked. Therefore, there is | |
16 | //! an elaborate system to track why a particular constraint in the | |
17 | //! inference graph arose so that we can explain to the user what gave | |
18 | //! rise to a particular error. | |
19 | //! | |
20 | //! The basis of the system are the "origin" types. An "origin" is the | |
21 | //! reason that a constraint or inference variable arose. There are | |
22 | //! different "origin" enums for different kinds of constraints/variables | |
23 | //! (e.g., `TypeOrigin`, `RegionVariableOrigin`). An origin always has | |
24 | //! a span, but also more information so that we can generate a meaningful | |
25 | //! error message. | |
26 | //! | |
3b2f2976 | 27 | //! Having a catalog of all the different reasons an error can arise is |
1a4d82fc JJ |
28 | //! also useful for other reasons, like cross-referencing FAQs etc, though |
29 | //! we are not really taking advantage of this yet. | |
30 | //! | |
31 | //! # Region Inference | |
32 | //! | |
33 | //! Region inference is particularly tricky because it always succeeds "in | |
34 | //! the moment" and simply registers a constraint. Then, at the end, we | |
35 | //! can compute the full graph and report errors, so we need to be able to | |
36 | //! store and later report what gave rise to the conflicting constraints. | |
37 | //! | |
38 | //! # Subtype Trace | |
39 | //! | |
40 | //! Determining whether `T1 <: T2` often involves a number of subtypes and | |
41 | //! subconstraints along the way. A "TypeTrace" is an extended version | |
42 | //! of an origin that traces the types and other values that were being | |
43 | //! compared. It is not necessarily comprehensive (in fact, at the time of | |
44 | //! this writing it only tracks the root values being compared) but I'd | |
45 | //! like to extend it to include significant "waypoints". For example, if | |
46 | //! you are comparing `(T1, T2) <: (T3, T4)`, and the problem is that `T2 | |
47 | //! <: T4` fails, I'd like the trace to include enough information to say | |
48 | //! "in the 2nd element of the tuple". Similarly, failures when comparing | |
49 | //! arguments or return types in fn types should be able to cite the | |
50 | //! specific position, etc. | |
51 | //! | |
52 | //! # Reality vs plan | |
53 | //! | |
54 | //! Of course, there is still a LOT of code in typeck that has yet to be | |
55 | //! ported to this system, and which relies on string concatenation at the | |
56 | //! time of error detection. | |
57 | ||
abe05a73 | 58 | use super::lexical_region_resolve::RegionResolutionError; |
0bf4aa26 XL |
59 | use super::region_constraints::GenericKind; |
60 | use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs}; | |
61 | use infer::{self, SuppressRegionErrors}; | |
e9174d1e | 62 | |
0bf4aa26 | 63 | use errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString}; |
54a0048b | 64 | use hir; |
54a0048b | 65 | use hir::def_id::DefId; |
0bf4aa26 | 66 | use hir::Node; |
62682a34 | 67 | use middle::region; |
0bf4aa26 | 68 | use std::{cmp, fmt}; |
7cac9316 | 69 | use syntax::ast::DUMMY_NODE_ID; |
32a655c1 | 70 | use syntax_pos::{Pos, Span}; |
0bf4aa26 XL |
71 | use traits::{ObligationCause, ObligationCauseCode}; |
72 | use ty::error::TypeError; | |
73 | use ty::{self, subst::Subst, Region, Ty, TyCtxt, TyKind, TypeFoldable}; | |
1a4d82fc | 74 | |
8bb4bdeb XL |
75 | mod note; |
76 | ||
041b39d2 | 77 | mod need_type_info; |
3b2f2976 | 78 | |
ff7c6d11 | 79 | pub mod nice_region_error; |
041b39d2 | 80 | |
a7813a04 | 81 | impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { |
0531ce1d XL |
82 | pub fn note_and_explain_region( |
83 | self, | |
84 | region_scope_tree: ®ion::ScopeTree, | |
0bf4aa26 | 85 | err: &mut DiagnosticBuilder<'_>, |
0531ce1d XL |
86 | prefix: &str, |
87 | region: ty::Region<'tcx>, | |
88 | suffix: &str, | |
89 | ) { | |
9e0c209e | 90 | let (description, span) = match *region { |
c1a9b12d SL |
91 | ty::ReScope(scope) => { |
92 | let new_string; | |
93 | let unknown_scope = || { | |
0531ce1d XL |
94 | format!( |
95 | "{}unknown scope: {:?}{}. Please report a bug.", | |
96 | prefix, scope, suffix | |
97 | ) | |
c1a9b12d | 98 | }; |
ea8adc8c XL |
99 | let span = scope.span(self, region_scope_tree); |
100 | let tag = match self.hir.find(scope.node_id(self, region_scope_tree)) { | |
b7449926 XL |
101 | Some(Node::Block(_)) => "block", |
102 | Some(Node::Expr(expr)) => match expr.node { | |
8faf50e0 XL |
103 | hir::ExprKind::Call(..) => "call", |
104 | hir::ExprKind::MethodCall(..) => "method call", | |
105 | hir::ExprKind::Match(.., hir::MatchSource::IfLetDesugar { .. }) => "if let", | |
106 | hir::ExprKind::Match(.., hir::MatchSource::WhileLetDesugar) => "while let", | |
107 | hir::ExprKind::Match(.., hir::MatchSource::ForLoopDesugar) => "for", | |
108 | hir::ExprKind::Match(..) => "match", | |
c1a9b12d SL |
109 | _ => "expression", |
110 | }, | |
b7449926 XL |
111 | Some(Node::Stmt(_)) => "statement", |
112 | Some(Node::Item(it)) => Self::item_scope_tag(&it), | |
113 | Some(Node::TraitItem(it)) => Self::trait_item_scope_tag(&it), | |
114 | Some(Node::ImplItem(it)) => Self::impl_item_scope_tag(&it), | |
c1a9b12d | 115 | Some(_) | None => { |
9cc50fc6 SL |
116 | err.span_note(span, &unknown_scope()); |
117 | return; | |
c1a9b12d SL |
118 | } |
119 | }; | |
b7449926 XL |
120 | let scope_decorated_tag = match scope.data { |
121 | region::ScopeData::Node => tag, | |
122 | region::ScopeData::CallSite => "scope of call-site for function", | |
123 | region::ScopeData::Arguments => "scope of function body", | |
124 | region::ScopeData::Destruction => { | |
c1a9b12d SL |
125 | new_string = format!("destruction scope surrounding {}", tag); |
126 | &new_string[..] | |
127 | } | |
b7449926 | 128 | region::ScopeData::Remainder(first_statement_index) => { |
0531ce1d XL |
129 | new_string = format!( |
130 | "block suffix following statement {}", | |
b7449926 | 131 | first_statement_index.index() |
0531ce1d | 132 | ); |
c1a9b12d SL |
133 | &new_string[..] |
134 | } | |
135 | }; | |
0531ce1d | 136 | self.explain_span(scope_decorated_tag, span) |
c1a9b12d | 137 | } |
62682a34 | 138 | |
0531ce1d XL |
139 | ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic => { |
140 | self.msg_span_from_free_region(region) | |
62682a34 | 141 | } |
62682a34 | 142 | |
c1a9b12d | 143 | ty::ReEmpty => ("the empty lifetime".to_owned(), None), |
62682a34 | 144 | |
0bf4aa26 | 145 | // FIXME(#13998) RePlaceholder should probably print like |
e9174d1e SL |
146 | // ReFree rather than dumping Debug output on the user. |
147 | // | |
148 | // We shouldn't really be having unification failures with ReVar | |
149 | // and ReLateBound though. | |
0bf4aa26 | 150 | ty::RePlaceholder(..) | ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => { |
c1a9b12d SL |
151 | (format!("lifetime {:?}", region), None) |
152 | } | |
ff7c6d11 XL |
153 | |
154 | // We shouldn't encounter an error message with ReClosureBound. | |
0bf4aa26 | 155 | ty::ReCanonical(..) | ty::ReClosureBound(..) => { |
0531ce1d XL |
156 | bug!("encountered unexpected ReClosureBound: {:?}", region,); |
157 | } | |
158 | }; | |
159 | ||
160 | TyCtxt::emit_msg_span(err, prefix, description, span, suffix); | |
161 | } | |
162 | ||
163 | pub fn note_and_explain_free_region( | |
164 | self, | |
0bf4aa26 | 165 | err: &mut DiagnosticBuilder<'_>, |
0531ce1d XL |
166 | prefix: &str, |
167 | region: ty::Region<'tcx>, | |
168 | suffix: &str, | |
169 | ) { | |
170 | let (description, span) = self.msg_span_from_free_region(region); | |
171 | ||
172 | TyCtxt::emit_msg_span(err, prefix, description, span, suffix); | |
173 | } | |
174 | ||
175 | fn msg_span_from_free_region(self, region: ty::Region<'tcx>) -> (String, Option<Span>) { | |
176 | match *region { | |
0bf4aa26 | 177 | ty::ReEarlyBound(_) | ty::ReFree(_) => { |
0531ce1d | 178 | self.msg_span_from_early_bound_and_free_regions(region) |
0bf4aa26 | 179 | } |
0531ce1d XL |
180 | ty::ReStatic => ("the static lifetime".to_owned(), None), |
181 | _ => bug!("{:?}", region), | |
182 | } | |
183 | } | |
184 | ||
185 | fn msg_span_from_early_bound_and_free_regions( | |
186 | self, | |
187 | region: ty::Region<'tcx>, | |
188 | ) -> (String, Option<Span>) { | |
b7449926 | 189 | let cm = self.sess.source_map(); |
8faf50e0 | 190 | |
0531ce1d XL |
191 | let scope = region.free_region_binding_scope(self); |
192 | let node = self.hir.as_local_node_id(scope).unwrap_or(DUMMY_NODE_ID); | |
0531ce1d | 193 | let tag = match self.hir.find(node) { |
b7449926 XL |
194 | Some(Node::Block(_)) | Some(Node::Expr(_)) => "body", |
195 | Some(Node::Item(it)) => Self::item_scope_tag(&it), | |
196 | Some(Node::TraitItem(it)) => Self::trait_item_scope_tag(&it), | |
197 | Some(Node::ImplItem(it)) => Self::impl_item_scope_tag(&it), | |
0bf4aa26 | 198 | _ => unreachable!(), |
0531ce1d XL |
199 | }; |
200 | let (prefix, span) = match *region { | |
8faf50e0 XL |
201 | ty::ReEarlyBound(ref br) => { |
202 | let mut sp = cm.def_span(self.hir.span(node)); | |
0bf4aa26 XL |
203 | if let Some(param) = self.hir |
204 | .get_generics(scope) | |
205 | .and_then(|generics| generics.get_named(&br.name)) | |
206 | { | |
8faf50e0 XL |
207 | sp = param.span; |
208 | } | |
209 | (format!("the lifetime {} as defined on", br.name), sp) | |
210 | } | |
211 | ty::ReFree(ty::FreeRegion { | |
0bf4aa26 XL |
212 | bound_region: ty::BoundRegion::BrNamed(_, ref name), |
213 | .. | |
8faf50e0 XL |
214 | }) => { |
215 | let mut sp = cm.def_span(self.hir.span(node)); | |
0bf4aa26 XL |
216 | if let Some(param) = self.hir |
217 | .get_generics(scope) | |
218 | .and_then(|generics| generics.get_named(&name)) | |
219 | { | |
8faf50e0 XL |
220 | sp = param.span; |
221 | } | |
222 | (format!("the lifetime {} as defined on", name), sp) | |
223 | } | |
0531ce1d XL |
224 | ty::ReFree(ref fr) => match fr.bound_region { |
225 | ty::BrAnon(idx) => ( | |
226 | format!("the anonymous lifetime #{} defined on", idx + 1), | |
227 | self.hir.span(node), | |
228 | ), | |
229 | ty::BrFresh(_) => ( | |
230 | "an anonymous lifetime defined on".to_owned(), | |
231 | self.hir.span(node), | |
232 | ), | |
233 | _ => ( | |
234 | format!("the lifetime {} as defined on", fr.bound_region), | |
8faf50e0 | 235 | cm.def_span(self.hir.span(node)), |
0531ce1d XL |
236 | ), |
237 | }, | |
238 | _ => bug!(), | |
c1a9b12d | 239 | }; |
0531ce1d XL |
240 | let (msg, opt_span) = self.explain_span(tag, span); |
241 | (format!("{} {}", prefix, msg), opt_span) | |
242 | } | |
243 | ||
244 | fn emit_msg_span( | |
0bf4aa26 | 245 | err: &mut DiagnosticBuilder<'_>, |
0531ce1d XL |
246 | prefix: &str, |
247 | description: String, | |
248 | span: Option<Span>, | |
249 | suffix: &str, | |
250 | ) { | |
c1a9b12d | 251 | let message = format!("{}{}{}", prefix, description, suffix); |
0531ce1d | 252 | |
c1a9b12d | 253 | if let Some(span) = span { |
9cc50fc6 | 254 | err.span_note(span, &message); |
c1a9b12d | 255 | } else { |
9cc50fc6 | 256 | err.note(&message); |
62682a34 | 257 | } |
62682a34 | 258 | } |
0531ce1d XL |
259 | |
260 | fn item_scope_tag(item: &hir::Item) -> &'static str { | |
261 | match item.node { | |
8faf50e0 XL |
262 | hir::ItemKind::Impl(..) => "impl", |
263 | hir::ItemKind::Struct(..) => "struct", | |
264 | hir::ItemKind::Union(..) => "union", | |
265 | hir::ItemKind::Enum(..) => "enum", | |
266 | hir::ItemKind::Trait(..) => "trait", | |
267 | hir::ItemKind::Fn(..) => "function body", | |
0531ce1d XL |
268 | _ => "item", |
269 | } | |
270 | } | |
271 | ||
272 | fn trait_item_scope_tag(item: &hir::TraitItem) -> &'static str { | |
273 | match item.node { | |
274 | hir::TraitItemKind::Method(..) => "method body", | |
275 | hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => "associated item", | |
276 | } | |
277 | } | |
278 | ||
279 | fn impl_item_scope_tag(item: &hir::ImplItem) -> &'static str { | |
280 | match item.node { | |
281 | hir::ImplItemKind::Method(..) => "method body", | |
0bf4aa26 XL |
282 | hir::ImplItemKind::Const(..) |
283 | | hir::ImplItemKind::Existential(..) | |
284 | | hir::ImplItemKind::Type(..) => "associated item", | |
0531ce1d XL |
285 | } |
286 | } | |
287 | ||
288 | fn explain_span(self, heading: &str, span: Span) -> (String, Option<Span>) { | |
b7449926 | 289 | let lo = self.sess.source_map().lookup_char_pos_adj(span.lo()); |
0531ce1d XL |
290 | ( |
291 | format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize() + 1), | |
292 | Some(span), | |
293 | ) | |
294 | } | |
62682a34 | 295 | } |
1a4d82fc | 296 | |
a7813a04 | 297 | impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { |
0531ce1d XL |
298 | pub fn report_region_errors( |
299 | &self, | |
300 | region_scope_tree: ®ion::ScopeTree, | |
301 | errors: &Vec<RegionResolutionError<'tcx>>, | |
0bf4aa26 | 302 | suppress: SuppressRegionErrors, |
0531ce1d | 303 | ) { |
0bf4aa26 XL |
304 | debug!( |
305 | "report_region_errors(): {} errors to start, suppress = {:?}", | |
306 | errors.len(), | |
307 | suppress | |
308 | ); | |
309 | ||
310 | if suppress.suppressed() { | |
311 | return; | |
abe05a73 XL |
312 | } |
313 | ||
54a0048b SL |
314 | // try to pre-process the errors, which will group some of them |
315 | // together into a `ProcessedErrors` group: | |
32a655c1 | 316 | let errors = self.process_errors(errors); |
54a0048b | 317 | |
0531ce1d XL |
318 | debug!( |
319 | "report_region_errors: {} errors after preprocessing", | |
320 | errors.len() | |
321 | ); | |
54a0048b | 322 | |
85aaf69f | 323 | for error in errors { |
c30ab7b3 | 324 | debug!("report_region_errors: error = {:?}", error); |
1a4d82fc | 325 | |
ff7c6d11 | 326 | if !self.try_report_nice_region_error(&error) { |
abe05a73 XL |
327 | match error.clone() { |
328 | // These errors could indicate all manner of different | |
329 | // problems with many different solutions. Rather | |
330 | // than generate a "one size fits all" error, what we | |
331 | // attempt to do is go through a number of specific | |
332 | // scenarios and try to find the best way to present | |
333 | // the error. If all of these fails, we fall back to a rather | |
334 | // general bit of code that displays the error information | |
335 | RegionResolutionError::ConcreteFailure(origin, sub, sup) => { | |
0531ce1d XL |
336 | self.report_concrete_failure(region_scope_tree, origin, sub, sup) |
337 | .emit(); | |
abe05a73 XL |
338 | } |
339 | ||
ff7c6d11 XL |
340 | RegionResolutionError::GenericBoundFailure(origin, param_ty, sub) => { |
341 | self.report_generic_bound_failure( | |
342 | region_scope_tree, | |
343 | origin.span(), | |
344 | Some(origin), | |
345 | param_ty, | |
346 | sub, | |
347 | ); | |
abe05a73 XL |
348 | } |
349 | ||
0531ce1d XL |
350 | RegionResolutionError::SubSupConflict( |
351 | var_origin, | |
352 | sub_origin, | |
353 | sub_r, | |
354 | sup_origin, | |
355 | sup_r, | |
356 | ) => { | |
357 | self.report_sub_sup_conflict( | |
358 | region_scope_tree, | |
359 | var_origin, | |
360 | sub_origin, | |
361 | sub_r, | |
362 | sup_origin, | |
363 | sup_r, | |
364 | ); | |
abe05a73 XL |
365 | } |
366 | } | |
1a4d82fc JJ |
367 | } |
368 | } | |
369 | } | |
370 | ||
371 | // This method goes through all the errors and try to group certain types | |
372 | // of error together, for the purpose of suggesting explicit lifetime | |
373 | // parameters to the user. This is done so that we can have a more | |
374 | // complete view of what lifetimes should be the same. | |
375 | // If the return value is an empty vector, it means that processing | |
54a0048b SL |
376 | // failed (so the return value of this method should not be used). |
377 | // | |
378 | // The method also attempts to weed out messages that seem like | |
379 | // duplicates that will be unhelpful to the end-user. But | |
380 | // obviously it never weeds out ALL errors. | |
0531ce1d XL |
381 | fn process_errors( |
382 | &self, | |
383 | errors: &Vec<RegionResolutionError<'tcx>>, | |
384 | ) -> Vec<RegionResolutionError<'tcx>> { | |
1a4d82fc | 385 | debug!("process_errors()"); |
54a0048b | 386 | |
32a655c1 SL |
387 | // We want to avoid reporting generic-bound failures if we can |
388 | // avoid it: these have a very high rate of being unhelpful in | |
389 | // practice. This is because they are basically secondary | |
390 | // checks that test the state of the region graph after the | |
391 | // rest of inference is done, and the other kinds of errors | |
392 | // indicate that the region constraint graph is internally | |
393 | // inconsistent, so these test results are likely to be | |
394 | // meaningless. | |
395 | // | |
396 | // Therefore, we filter them out of the list unless they are | |
397 | // the only thing in the list. | |
398 | ||
399 | let is_bound_failure = |e: &RegionResolutionError<'tcx>| match *e { | |
abe05a73 | 400 | RegionResolutionError::GenericBoundFailure(..) => true, |
0531ce1d XL |
401 | RegionResolutionError::ConcreteFailure(..) |
402 | | RegionResolutionError::SubSupConflict(..) => false, | |
32a655c1 | 403 | }; |
1a4d82fc | 404 | |
ea8adc8c | 405 | let mut errors = if errors.iter().all(|e| is_bound_failure(e)) { |
32a655c1 SL |
406 | errors.clone() |
407 | } else { | |
0531ce1d | 408 | errors |
0bf4aa26 XL |
409 | .iter() |
410 | .filter(|&e| !is_bound_failure(e)) | |
411 | .cloned() | |
412 | .collect() | |
ea8adc8c XL |
413 | }; |
414 | ||
415 | // sort the errors by span, for better error message stability. | |
416 | errors.sort_by_key(|u| match *u { | |
abe05a73 XL |
417 | RegionResolutionError::ConcreteFailure(ref sro, _, _) => sro.span(), |
418 | RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(), | |
419 | RegionResolutionError::SubSupConflict(ref rvo, _, _, _, _) => rvo.span(), | |
ea8adc8c XL |
420 | }); |
421 | errors | |
1a4d82fc JJ |
422 | } |
423 | ||
e9174d1e | 424 | /// Adds a note if the types come from similarly named crates |
0531ce1d XL |
425 | fn check_and_note_conflicting_crates( |
426 | &self, | |
0bf4aa26 | 427 | err: &mut DiagnosticBuilder<'_>, |
0531ce1d XL |
428 | terr: &TypeError<'tcx>, |
429 | sp: Span, | |
430 | ) { | |
0bf4aa26 | 431 | let report_path_match = |err: &mut DiagnosticBuilder<'_>, did1: DefId, did2: DefId| { |
e9174d1e SL |
432 | // Only external crates, if either is from a local |
433 | // module we could have false positives | |
434 | if !(did1.is_local() || did2.is_local()) && did1.krate != did2.krate { | |
54a0048b SL |
435 | let exp_path = self.tcx.item_path_str(did1); |
436 | let found_path = self.tcx.item_path_str(did2); | |
041b39d2 XL |
437 | let exp_abs_path = self.tcx.absolute_item_path_str(did1); |
438 | let found_abs_path = self.tcx.absolute_item_path_str(did2); | |
54a0048b | 439 | // We compare strings because DefPath can be different |
e9174d1e | 440 | // for imported and non-imported crates |
0531ce1d | 441 | if exp_path == found_path || exp_abs_path == found_abs_path { |
ea8adc8c | 442 | let crate_name = self.tcx.crate_name(did1.krate); |
0531ce1d XL |
443 | err.span_note( |
444 | sp, | |
445 | &format!( | |
446 | "Perhaps two different versions \ | |
447 | of crate `{}` are being used?", | |
448 | crate_name | |
449 | ), | |
450 | ); | |
e9174d1e SL |
451 | } |
452 | } | |
453 | }; | |
454 | match *terr { | |
455 | TypeError::Sorts(ref exp_found) => { | |
456 | // if they are both "path types", there's a chance of ambiguity | |
457 | // due to different versions of the same crate | |
0bf4aa26 XL |
458 | if let (&ty::Adt(exp_adt, _), &ty::Adt(found_adt, _)) |
459 | = (&exp_found.expected.sty, &exp_found.found.sty) | |
460 | { | |
461 | report_path_match(err, exp_adt.did, found_adt.did); | |
e9174d1e | 462 | } |
0531ce1d | 463 | } |
e9174d1e | 464 | TypeError::Traits(ref exp_found) => { |
9cc50fc6 | 465 | report_path_match(err, exp_found.expected, exp_found.found); |
0531ce1d XL |
466 | } |
467 | _ => (), // FIXME(#22750) handle traits and stuff | |
e9174d1e SL |
468 | } |
469 | } | |
470 | ||
0531ce1d | 471 | fn note_error_origin(&self, err: &mut DiagnosticBuilder<'tcx>, cause: &ObligationCause<'tcx>) { |
476ff2be SL |
472 | match cause.code { |
473 | ObligationCauseCode::MatchExpressionArm { arm_span, source } => match source { | |
0531ce1d | 474 | hir::MatchSource::IfLetDesugar { .. } => { |
ff7c6d11 | 475 | let msg = "`if let` arm with an incompatible type"; |
b7449926 | 476 | if self.tcx.sess.source_map().is_multiline(arm_span) { |
ff7c6d11 XL |
477 | err.span_note(arm_span, msg); |
478 | } else { | |
479 | err.span_label(arm_span, msg); | |
480 | } | |
0bf4aa26 XL |
481 | } |
482 | hir::MatchSource::TryDesugar => {} | |
5bcae85e | 483 | _ => { |
ff7c6d11 | 484 | let msg = "match arm with an incompatible type"; |
b7449926 | 485 | if self.tcx.sess.source_map().is_multiline(arm_span) { |
ff7c6d11 XL |
486 | err.span_note(arm_span, msg); |
487 | } else { | |
488 | err.span_label(arm_span, msg); | |
489 | } | |
5bcae85e SL |
490 | } |
491 | }, | |
0531ce1d | 492 | _ => (), |
5bcae85e SL |
493 | } |
494 | } | |
495 | ||
cc61c64b XL |
496 | /// Given that `other_ty` is the same as a type argument for `name` in `sub`, populate `value` |
497 | /// highlighting `name` and every type argument that isn't at `pos` (which is `other_ty`), and | |
498 | /// populate `other_value` with `other_ty`. | |
499 | /// | |
500 | /// ```text | |
501 | /// Foo<Bar<Qux>> | |
502 | /// ^^^^--------^ this is highlighted | |
503 | /// | | | |
504 | /// | this type argument is exactly the same as the other type, not highlighted | |
505 | /// this is highlighted | |
506 | /// Bar<Qux> | |
507 | /// -------- this type is the same as a type argument in the other type, not highlighted | |
508 | /// ``` | |
0531ce1d XL |
509 | fn highlight_outer( |
510 | &self, | |
511 | value: &mut DiagnosticStyledString, | |
512 | other_value: &mut DiagnosticStyledString, | |
513 | name: String, | |
514 | sub: &ty::subst::Substs<'tcx>, | |
515 | pos: usize, | |
516 | other_ty: &Ty<'tcx>, | |
517 | ) { | |
cc61c64b XL |
518 | // `value` and `other_value` hold two incomplete type representation for display. |
519 | // `name` is the path of both types being compared. `sub` | |
520 | value.push_highlighted(name); | |
521 | let len = sub.len(); | |
522 | if len > 0 { | |
523 | value.push_highlighted("<"); | |
524 | } | |
525 | ||
b7449926 | 526 | // Output the lifetimes for the first type |
0531ce1d XL |
527 | let lifetimes = sub.regions() |
528 | .map(|lifetime| { | |
8faf50e0 | 529 | let s = lifetime.to_string(); |
0531ce1d XL |
530 | if s.is_empty() { |
531 | "'_".to_string() | |
532 | } else { | |
533 | s | |
534 | } | |
535 | }) | |
536 | .collect::<Vec<_>>() | |
537 | .join(", "); | |
cc61c64b XL |
538 | if !lifetimes.is_empty() { |
539 | if sub.regions().count() < len { | |
540 | value.push_normal(lifetimes + &", "); | |
541 | } else { | |
542 | value.push_normal(lifetimes); | |
543 | } | |
544 | } | |
545 | ||
546 | // Highlight all the type arguments that aren't at `pos` and compare the type argument at | |
547 | // `pos` and `other_ty`. | |
548 | for (i, type_arg) in sub.types().enumerate() { | |
549 | if i == pos { | |
550 | let values = self.cmp(type_arg, other_ty); | |
551 | value.0.extend((values.0).0); | |
552 | other_value.0.extend((values.1).0); | |
553 | } else { | |
8faf50e0 | 554 | value.push_highlighted(type_arg.to_string()); |
cc61c64b XL |
555 | } |
556 | ||
557 | if len > 0 && i != len - 1 { | |
558 | value.push_normal(", "); | |
559 | } | |
560 | //self.push_comma(&mut value, &mut other_value, len, i); | |
561 | } | |
562 | if len > 0 { | |
563 | value.push_highlighted(">"); | |
564 | } | |
565 | } | |
566 | ||
567 | /// If `other_ty` is the same as a type argument present in `sub`, highlight `path` in `t1_out`, | |
568 | /// as that is the difference to the other type. | |
569 | /// | |
570 | /// For the following code: | |
571 | /// | |
572 | /// ```norun | |
573 | /// let x: Foo<Bar<Qux>> = foo::<Bar<Qux>>(); | |
574 | /// ``` | |
575 | /// | |
576 | /// The type error output will behave in the following way: | |
577 | /// | |
578 | /// ```text | |
579 | /// Foo<Bar<Qux>> | |
580 | /// ^^^^--------^ this is highlighted | |
581 | /// | | | |
582 | /// | this type argument is exactly the same as the other type, not highlighted | |
583 | /// this is highlighted | |
584 | /// Bar<Qux> | |
585 | /// -------- this type is the same as a type argument in the other type, not highlighted | |
586 | /// ``` | |
0531ce1d XL |
587 | fn cmp_type_arg( |
588 | &self, | |
589 | mut t1_out: &mut DiagnosticStyledString, | |
590 | mut t2_out: &mut DiagnosticStyledString, | |
591 | path: String, | |
592 | sub: &ty::subst::Substs<'tcx>, | |
593 | other_path: String, | |
594 | other_ty: &Ty<'tcx>, | |
595 | ) -> Option<()> { | |
cc61c64b XL |
596 | for (i, ta) in sub.types().enumerate() { |
597 | if &ta == other_ty { | |
598 | self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty); | |
599 | return Some(()); | |
600 | } | |
b7449926 | 601 | if let &ty::Adt(def, _) = &ta.sty { |
cc61c64b XL |
602 | let path_ = self.tcx.item_path_str(def.did.clone()); |
603 | if path_ == other_path { | |
604 | self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty); | |
605 | return Some(()); | |
606 | } | |
607 | } | |
608 | } | |
609 | None | |
610 | } | |
611 | ||
612 | /// Add a `,` to the type representation only if it is appropriate. | |
0531ce1d XL |
613 | fn push_comma( |
614 | &self, | |
615 | value: &mut DiagnosticStyledString, | |
616 | other_value: &mut DiagnosticStyledString, | |
617 | len: usize, | |
618 | pos: usize, | |
619 | ) { | |
cc61c64b XL |
620 | if len > 0 && pos != len - 1 { |
621 | value.push_normal(", "); | |
622 | other_value.push_normal(", "); | |
623 | } | |
624 | } | |
625 | ||
8faf50e0 XL |
626 | /// For generic types with parameters with defaults, remove the parameters corresponding to |
627 | /// the defaults. This repeats a lot of the logic found in `PrintContext::parameterized`. | |
628 | fn strip_generic_default_params( | |
629 | &self, | |
630 | def_id: DefId, | |
0bf4aa26 | 631 | substs: &ty::subst::Substs<'tcx>, |
8faf50e0 XL |
632 | ) -> &'tcx ty::subst::Substs<'tcx> { |
633 | let generics = self.tcx.generics_of(def_id); | |
634 | let mut num_supplied_defaults = 0; | |
0bf4aa26 XL |
635 | let mut type_params = generics |
636 | .params | |
637 | .iter() | |
638 | .rev() | |
639 | .filter_map(|param| match param.kind { | |
640 | ty::GenericParamDefKind::Lifetime => None, | |
641 | ty::GenericParamDefKind::Type { has_default, .. } => { | |
642 | Some((param.def_id, has_default)) | |
643 | } | |
644 | }) | |
645 | .peekable(); | |
8faf50e0 XL |
646 | let has_default = { |
647 | let has_default = type_params.peek().map(|(_, has_default)| has_default); | |
648 | *has_default.unwrap_or(&false) | |
649 | }; | |
650 | if has_default { | |
651 | let types = substs.types().rev(); | |
652 | for ((def_id, has_default), actual) in type_params.zip(types) { | |
653 | if !has_default { | |
654 | break; | |
655 | } | |
656 | if self.tcx.type_of(def_id).subst(self.tcx, substs) != actual { | |
657 | break; | |
658 | } | |
659 | num_supplied_defaults += 1; | |
660 | } | |
661 | } | |
662 | let len = generics.params.len(); | |
663 | let mut generics = generics.clone(); | |
664 | generics.params.truncate(len - num_supplied_defaults); | |
665 | substs.truncate_to(self.tcx, &generics) | |
666 | } | |
667 | ||
cc61c64b XL |
668 | /// Compare two given types, eliding parts that are the same between them and highlighting |
669 | /// relevant differences, and return two representation of those types for highlighted printing. | |
0531ce1d | 670 | fn cmp(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> (DiagnosticStyledString, DiagnosticStyledString) { |
ff7c6d11 XL |
671 | fn equals<'tcx>(a: &Ty<'tcx>, b: &Ty<'tcx>) -> bool { |
672 | match (&a.sty, &b.sty) { | |
673 | (a, b) if *a == *b => true, | |
b7449926 XL |
674 | (&ty::Int(_), &ty::Infer(ty::InferTy::IntVar(_))) |
675 | | (&ty::Infer(ty::InferTy::IntVar(_)), &ty::Int(_)) | |
676 | | (&ty::Infer(ty::InferTy::IntVar(_)), &ty::Infer(ty::InferTy::IntVar(_))) | |
677 | | (&ty::Float(_), &ty::Infer(ty::InferTy::FloatVar(_))) | |
678 | | (&ty::Infer(ty::InferTy::FloatVar(_)), &ty::Float(_)) | |
0bf4aa26 XL |
679 | | (&ty::Infer(ty::InferTy::FloatVar(_)), &ty::Infer(ty::InferTy::FloatVar(_))) => { |
680 | true | |
681 | } | |
ff7c6d11 XL |
682 | _ => false, |
683 | } | |
684 | } | |
685 | ||
0531ce1d XL |
686 | fn push_ty_ref<'tcx>( |
687 | r: &ty::Region<'tcx>, | |
94b46f34 XL |
688 | ty: Ty<'tcx>, |
689 | mutbl: hir::Mutability, | |
0531ce1d XL |
690 | s: &mut DiagnosticStyledString, |
691 | ) { | |
8faf50e0 | 692 | let r = &r.to_string(); |
0531ce1d XL |
693 | s.push_highlighted(format!( |
694 | "&{}{}{}", | |
695 | r, | |
696 | if r == "" { "" } else { " " }, | |
0bf4aa26 | 697 | if mutbl == hir::MutMutable { "mut " } else { "" } |
0531ce1d | 698 | )); |
8faf50e0 | 699 | s.push_normal(ty.to_string()); |
ff7c6d11 XL |
700 | } |
701 | ||
cc61c64b | 702 | match (&t1.sty, &t2.sty) { |
b7449926 | 703 | (&ty::Adt(def1, sub1), &ty::Adt(def2, sub2)) => { |
8faf50e0 XL |
704 | let sub_no_defaults_1 = self.strip_generic_default_params(def1.did, sub1); |
705 | let sub_no_defaults_2 = self.strip_generic_default_params(def2.did, sub2); | |
cc61c64b XL |
706 | let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); |
707 | let path1 = self.tcx.item_path_str(def1.did.clone()); | |
708 | let path2 = self.tcx.item_path_str(def2.did.clone()); | |
709 | if def1.did == def2.did { | |
710 | // Easy case. Replace same types with `_` to shorten the output and highlight | |
711 | // the differing ones. | |
712 | // let x: Foo<Bar, Qux> = y::<Foo<Quz, Qux>>(); | |
713 | // Foo<Bar, _> | |
714 | // Foo<Quz, _> | |
715 | // --- ^ type argument elided | |
716 | // | | |
717 | // highlighted in output | |
718 | values.0.push_normal(path1); | |
719 | values.1.push_normal(path2); | |
720 | ||
8faf50e0 XL |
721 | // Avoid printing out default generic parameters that are common to both |
722 | // types. | |
723 | let len1 = sub_no_defaults_1.len(); | |
724 | let len2 = sub_no_defaults_2.len(); | |
725 | let common_len = cmp::min(len1, len2); | |
726 | let remainder1: Vec<_> = sub1.types().skip(common_len).collect(); | |
727 | let remainder2: Vec<_> = sub2.types().skip(common_len).collect(); | |
0bf4aa26 XL |
728 | let common_default_params = remainder1 |
729 | .iter() | |
730 | .rev() | |
731 | .zip(remainder2.iter().rev()) | |
732 | .filter(|(a, b)| a == b) | |
733 | .count(); | |
8faf50e0 XL |
734 | let len = sub1.len() - common_default_params; |
735 | ||
cc61c64b | 736 | // Only draw `<...>` if there're lifetime/type arguments. |
cc61c64b XL |
737 | if len > 0 { |
738 | values.0.push_normal("<"); | |
739 | values.1.push_normal("<"); | |
740 | } | |
741 | ||
0bf4aa26 | 742 | fn lifetime_display(lifetime: Region<'_>) -> String { |
8faf50e0 | 743 | let s = lifetime.to_string(); |
cc61c64b XL |
744 | if s.is_empty() { |
745 | "'_".to_string() | |
746 | } else { | |
747 | s | |
748 | } | |
749 | } | |
750 | // At one point we'd like to elide all lifetimes here, they are irrelevant for | |
751 | // all diagnostics that use this output | |
752 | // | |
753 | // Foo<'x, '_, Bar> | |
754 | // Foo<'y, '_, Qux> | |
755 | // ^^ ^^ --- type arguments are not elided | |
756 | // | | | |
757 | // | elided as they were the same | |
758 | // not elided, they were different, but irrelevant | |
759 | let lifetimes = sub1.regions().zip(sub2.regions()); | |
760 | for (i, lifetimes) in lifetimes.enumerate() { | |
761 | let l1 = lifetime_display(lifetimes.0); | |
762 | let l2 = lifetime_display(lifetimes.1); | |
763 | if l1 == l2 { | |
764 | values.0.push_normal("'_"); | |
765 | values.1.push_normal("'_"); | |
766 | } else { | |
767 | values.0.push_highlighted(l1); | |
768 | values.1.push_highlighted(l2); | |
769 | } | |
770 | self.push_comma(&mut values.0, &mut values.1, len, i); | |
771 | } | |
772 | ||
773 | // We're comparing two types with the same path, so we compare the type | |
774 | // arguments for both. If they are the same, do not highlight and elide from the | |
775 | // output. | |
776 | // Foo<_, Bar> | |
777 | // Foo<_, Qux> | |
778 | // ^ elided type as this type argument was the same in both sides | |
779 | let type_arguments = sub1.types().zip(sub2.types()); | |
8faf50e0 XL |
780 | let regions_len = sub1.regions().count(); |
781 | for (i, (ta1, ta2)) in type_arguments.take(len).enumerate() { | |
cc61c64b XL |
782 | let i = i + regions_len; |
783 | if ta1 == ta2 { | |
784 | values.0.push_normal("_"); | |
785 | values.1.push_normal("_"); | |
786 | } else { | |
787 | let (x1, x2) = self.cmp(ta1, ta2); | |
788 | (values.0).0.extend(x1.0); | |
789 | (values.1).0.extend(x2.0); | |
790 | } | |
791 | self.push_comma(&mut values.0, &mut values.1, len, i); | |
792 | } | |
793 | ||
794 | // Close the type argument bracket. | |
795 | // Only draw `<...>` if there're lifetime/type arguments. | |
796 | if len > 0 { | |
797 | values.0.push_normal(">"); | |
798 | values.1.push_normal(">"); | |
799 | } | |
800 | values | |
801 | } else { | |
802 | // Check for case: | |
803 | // let x: Foo<Bar<Qux> = foo::<Bar<Qux>>(); | |
804 | // Foo<Bar<Qux> | |
805 | // ------- this type argument is exactly the same as the other type | |
806 | // Bar<Qux> | |
0531ce1d XL |
807 | if self.cmp_type_arg( |
808 | &mut values.0, | |
809 | &mut values.1, | |
810 | path1.clone(), | |
8faf50e0 | 811 | sub_no_defaults_1, |
0531ce1d XL |
812 | path2.clone(), |
813 | &t2, | |
814 | ).is_some() | |
815 | { | |
cc61c64b XL |
816 | return values; |
817 | } | |
818 | // Check for case: | |
819 | // let x: Bar<Qux> = y:<Foo<Bar<Qux>>>(); | |
820 | // Bar<Qux> | |
821 | // Foo<Bar<Qux>> | |
822 | // ------- this type argument is exactly the same as the other type | |
8faf50e0 XL |
823 | if self.cmp_type_arg( |
824 | &mut values.1, | |
825 | &mut values.0, | |
826 | path2, | |
827 | sub_no_defaults_2, | |
828 | path1, | |
829 | &t1, | |
830 | ).is_some() | |
0531ce1d | 831 | { |
cc61c64b XL |
832 | return values; |
833 | } | |
834 | ||
835 | // We couldn't find anything in common, highlight everything. | |
836 | // let x: Bar<Qux> = y::<Foo<Zar>>(); | |
0531ce1d | 837 | ( |
8faf50e0 XL |
838 | DiagnosticStyledString::highlighted(t1.to_string()), |
839 | DiagnosticStyledString::highlighted(t2.to_string()), | |
0531ce1d | 840 | ) |
cc61c64b XL |
841 | } |
842 | } | |
ff7c6d11 | 843 | |
0531ce1d | 844 | // When finding T != &T, highlight only the borrow |
b7449926 | 845 | (&ty::Ref(r1, ref_ty1, mutbl1), _) if equals(&ref_ty1, &t2) => { |
ff7c6d11 | 846 | let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); |
94b46f34 | 847 | push_ty_ref(&r1, ref_ty1, mutbl1, &mut values.0); |
8faf50e0 | 848 | values.1.push_normal(t2.to_string()); |
ff7c6d11 XL |
849 | values |
850 | } | |
b7449926 | 851 | (_, &ty::Ref(r2, ref_ty2, mutbl2)) if equals(&t1, &ref_ty2) => { |
ff7c6d11 | 852 | let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); |
8faf50e0 | 853 | values.0.push_normal(t1.to_string()); |
94b46f34 | 854 | push_ty_ref(&r2, ref_ty2, mutbl2, &mut values.1); |
ff7c6d11 XL |
855 | values |
856 | } | |
857 | ||
858 | // When encountering &T != &mut T, highlight only the borrow | |
0bf4aa26 XL |
859 | (&ty::Ref(r1, ref_ty1, mutbl1), &ty::Ref(r2, ref_ty2, mutbl2)) |
860 | if equals(&ref_ty1, &ref_ty2) => | |
861 | { | |
ff7c6d11 | 862 | let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); |
94b46f34 XL |
863 | push_ty_ref(&r1, ref_ty1, mutbl1, &mut values.0); |
864 | push_ty_ref(&r2, ref_ty2, mutbl2, &mut values.1); | |
ff7c6d11 XL |
865 | values |
866 | } | |
867 | ||
cc61c64b XL |
868 | _ => { |
869 | if t1 == t2 { | |
870 | // The two types are the same, elide and don't highlight. | |
0531ce1d XL |
871 | ( |
872 | DiagnosticStyledString::normal("_"), | |
873 | DiagnosticStyledString::normal("_"), | |
874 | ) | |
cc61c64b XL |
875 | } else { |
876 | // We couldn't find anything in common, highlight everything. | |
0531ce1d | 877 | ( |
8faf50e0 XL |
878 | DiagnosticStyledString::highlighted(t1.to_string()), |
879 | DiagnosticStyledString::highlighted(t2.to_string()), | |
0531ce1d | 880 | ) |
cc61c64b XL |
881 | } |
882 | } | |
883 | } | |
884 | } | |
885 | ||
0531ce1d XL |
886 | pub fn note_type_err( |
887 | &self, | |
888 | diag: &mut DiagnosticBuilder<'tcx>, | |
889 | cause: &ObligationCause<'tcx>, | |
890 | secondary_span: Option<(Span, String)>, | |
891 | mut values: Option<ValuePairs<'tcx>>, | |
892 | terr: &TypeError<'tcx>, | |
893 | ) { | |
ff7c6d11 XL |
894 | // For some types of errors, expected-found does not make |
895 | // sense, so just ignore the values we were given. | |
896 | match terr { | |
0531ce1d XL |
897 | TypeError::CyclicTy(_) => { |
898 | values = None; | |
899 | } | |
900 | _ => {} | |
ff7c6d11 XL |
901 | } |
902 | ||
abe05a73 XL |
903 | let (expected_found, exp_found, is_simple_error) = match values { |
904 | None => (None, None, false), | |
8bb4bdeb | 905 | Some(values) => { |
abe05a73 | 906 | let (is_simple_error, exp_found) = match values { |
8bb4bdeb | 907 | ValuePairs::Types(exp_found) => { |
0531ce1d XL |
908 | let is_simple_err = |
909 | exp_found.expected.is_primitive() && exp_found.found.is_primitive(); | |
abe05a73 XL |
910 | |
911 | (is_simple_err, Some(exp_found)) | |
8bb4bdeb | 912 | } |
abe05a73 | 913 | _ => (false, None), |
8bb4bdeb XL |
914 | }; |
915 | let vals = match self.values_str(&values) { | |
916 | Some((expected, found)) => Some((expected, found)), | |
917 | None => { | |
918 | // Derived error. Cancel the emitter. | |
919 | self.tcx.sess.diagnostic().cancel(diag); | |
0531ce1d | 920 | return; |
8bb4bdeb XL |
921 | } |
922 | }; | |
abe05a73 | 923 | (vals, exp_found, is_simple_error) |
5bcae85e SL |
924 | } |
925 | }; | |
926 | ||
2c00a5a8 | 927 | let span = cause.span(&self.tcx); |
5bcae85e | 928 | |
abe05a73 XL |
929 | diag.span_label(span, terr.to_string()); |
930 | if let Some((sp, msg)) = secondary_span { | |
931 | diag.span_label(sp, msg); | |
932 | } | |
933 | ||
5bcae85e | 934 | if let Some((expected, found)) = expected_found { |
8bb4bdeb | 935 | match (terr, is_simple_error, expected == found) { |
cc61c64b | 936 | (&TypeError::Sorts(ref values), false, true) => { |
8bb4bdeb | 937 | diag.note_expected_found_extra( |
0531ce1d XL |
938 | &"type", |
939 | expected, | |
940 | found, | |
8bb4bdeb | 941 | &format!(" ({})", values.expected.sort_string(self.tcx)), |
0531ce1d XL |
942 | &format!(" ({})", values.found.sort_string(self.tcx)), |
943 | ); | |
8bb4bdeb | 944 | } |
abe05a73 XL |
945 | (_, false, _) => { |
946 | if let Some(exp_found) = exp_found { | |
947 | let (def_id, ret_ty) = match exp_found.found.sty { | |
b7449926 | 948 | TyKind::FnDef(def, _) => { |
abe05a73 XL |
949 | (Some(def), Some(self.tcx.fn_sig(def).output())) |
950 | } | |
0531ce1d | 951 | _ => (None, None), |
abe05a73 XL |
952 | }; |
953 | ||
954 | let exp_is_struct = match exp_found.expected.sty { | |
b7449926 | 955 | TyKind::Adt(def, _) => def.is_struct(), |
0531ce1d | 956 | _ => false, |
abe05a73 XL |
957 | }; |
958 | ||
959 | if let (Some(def_id), Some(ret_ty)) = (def_id, ret_ty) { | |
83c7162d | 960 | if exp_is_struct && &exp_found.expected == ret_ty.skip_binder() { |
abe05a73 XL |
961 | let message = format!( |
962 | "did you mean `{}(/* fields */)`?", | |
963 | self.tcx.item_path_str(def_id) | |
964 | ); | |
2c00a5a8 | 965 | diag.span_label(span, message); |
abe05a73 XL |
966 | } |
967 | } | |
968 | } | |
969 | ||
cc61c64b | 970 | diag.note_expected_found(&"type", expected, found); |
9e0c209e | 971 | } |
8bb4bdeb | 972 | _ => (), |
5bcae85e SL |
973 | } |
974 | } | |
975 | ||
5bcae85e SL |
976 | self.check_and_note_conflicting_crates(diag, terr, span); |
977 | self.tcx.note_and_explain_type_err(diag, terr, span); | |
abe05a73 XL |
978 | |
979 | // It reads better to have the error origin as the final | |
980 | // thing. | |
981 | self.note_error_origin(diag, &cause); | |
5bcae85e SL |
982 | } |
983 | ||
0531ce1d XL |
984 | pub fn report_and_explain_type_error( |
985 | &self, | |
986 | trace: TypeTrace<'tcx>, | |
987 | terr: &TypeError<'tcx>, | |
988 | ) -> DiagnosticBuilder<'tcx> { | |
989 | debug!( | |
990 | "report_and_explain_type_error(trace={:?}, terr={:?})", | |
991 | trace, terr | |
992 | ); | |
abe05a73 | 993 | |
2c00a5a8 | 994 | let span = trace.cause.span(&self.tcx); |
ff7c6d11 XL |
995 | let failure_code = trace.cause.as_failure_code(terr); |
996 | let mut diag = match failure_code { | |
997 | FailureCode::Error0317(failure_str) => { | |
c30ab7b3 | 998 | struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str) |
32a655c1 | 999 | } |
ff7c6d11 | 1000 | FailureCode::Error0580(failure_str) => { |
32a655c1 SL |
1001 | struct_span_err!(self.tcx.sess, span, E0580, "{}", failure_str) |
1002 | } | |
ff7c6d11 | 1003 | FailureCode::Error0308(failure_str) => { |
c30ab7b3 | 1004 | struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str) |
32a655c1 | 1005 | } |
ff7c6d11 XL |
1006 | FailureCode::Error0644(failure_str) => { |
1007 | struct_span_err!(self.tcx.sess, span, E0644, "{}", failure_str) | |
1008 | } | |
c30ab7b3 | 1009 | }; |
476ff2be | 1010 | self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr); |
5bcae85e | 1011 | diag |
1a4d82fc JJ |
1012 | } |
1013 | ||
0531ce1d XL |
1014 | fn values_str( |
1015 | &self, | |
1016 | values: &ValuePairs<'tcx>, | |
1017 | ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { | |
1a4d82fc | 1018 | match *values { |
cc61c64b | 1019 | infer::Types(ref exp_found) => self.expected_found_str_ty(exp_found), |
0531ce1d | 1020 | infer::Regions(ref exp_found) => self.expected_found_str(exp_found), |
1a4d82fc | 1021 | infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found), |
5bcae85e | 1022 | infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found), |
1a4d82fc JJ |
1023 | } |
1024 | } | |
1025 | ||
0531ce1d XL |
1026 | fn expected_found_str_ty( |
1027 | &self, | |
1028 | exp_found: &ty::error::ExpectedFound<Ty<'tcx>>, | |
1029 | ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { | |
cc61c64b XL |
1030 | let exp_found = self.resolve_type_vars_if_possible(exp_found); |
1031 | if exp_found.references_error() { | |
1032 | return None; | |
1033 | } | |
1034 | ||
1035 | Some(self.cmp(exp_found.expected, exp_found.found)) | |
1036 | } | |
1037 | ||
1038 | /// Returns a string of the form "expected `{}`, found `{}`". | |
5bcae85e | 1039 | fn expected_found_str<T: fmt::Display + TypeFoldable<'tcx>>( |
1a4d82fc | 1040 | &self, |
0531ce1d XL |
1041 | exp_found: &ty::error::ExpectedFound<T>, |
1042 | ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { | |
5bcae85e SL |
1043 | let exp_found = self.resolve_type_vars_if_possible(exp_found); |
1044 | if exp_found.references_error() { | |
1a4d82fc JJ |
1045 | return None; |
1046 | } | |
1047 | ||
0531ce1d | 1048 | Some(( |
8faf50e0 XL |
1049 | DiagnosticStyledString::highlighted(exp_found.expected.to_string()), |
1050 | DiagnosticStyledString::highlighted(exp_found.found.to_string()), | |
0531ce1d | 1051 | )) |
1a4d82fc JJ |
1052 | } |
1053 | ||
0531ce1d XL |
1054 | pub fn report_generic_bound_failure( |
1055 | &self, | |
1056 | region_scope_tree: ®ion::ScopeTree, | |
1057 | span: Span, | |
1058 | origin: Option<SubregionOrigin<'tcx>>, | |
1059 | bound_kind: GenericKind<'tcx>, | |
1060 | sub: Region<'tcx>, | |
1061 | ) { | |
0bf4aa26 | 1062 | self.construct_generic_bound_failure(region_scope_tree, span, origin, bound_kind, sub) |
8faf50e0 XL |
1063 | .emit() |
1064 | } | |
1065 | ||
1066 | pub fn construct_generic_bound_failure( | |
1067 | &self, | |
1068 | region_scope_tree: ®ion::ScopeTree, | |
1069 | span: Span, | |
1070 | origin: Option<SubregionOrigin<'tcx>>, | |
1071 | bound_kind: GenericKind<'tcx>, | |
1072 | sub: Region<'tcx>, | |
0bf4aa26 | 1073 | ) -> DiagnosticBuilder<'a> { |
ea8adc8c XL |
1074 | // Attempt to obtain the span of the parameter so we can |
1075 | // suggest adding an explicit lifetime bound to it. | |
1076 | let type_param_span = match (self.in_progress_tables, bound_kind) { | |
1077 | (Some(ref table), GenericKind::Param(ref param)) => { | |
1078 | let table = table.borrow(); | |
1079 | table.local_id_root.and_then(|did| { | |
1080 | let generics = self.tcx.generics_of(did); | |
1081 | // Account for the case where `did` corresponds to `Self`, which doesn't have | |
1082 | // the expected type argument. | |
1083 | if !param.is_self() { | |
1084 | let type_param = generics.type_param(param, self.tcx); | |
1085 | let hir = &self.tcx.hir; | |
1086 | hir.as_local_node_id(type_param.def_id).map(|id| { | |
b7449926 | 1087 | // Get the `hir::Param` to verify whether it already has any bounds. |
ea8adc8c XL |
1088 | // We do this to avoid suggesting code that ends up as `T: 'a'b`, |
1089 | // instead we suggest `T: 'a + 'b` in that case. | |
8faf50e0 | 1090 | let mut has_bounds = false; |
b7449926 | 1091 | if let Node::GenericParam(ref param) = hir.get(id) { |
8faf50e0 XL |
1092 | has_bounds = !param.bounds.is_empty(); |
1093 | } | |
ea8adc8c XL |
1094 | let sp = hir.span(id); |
1095 | // `sp` only covers `T`, change it so that it covers | |
1096 | // `T:` when appropriate | |
8faf50e0 | 1097 | let sp = if has_bounds { |
0531ce1d XL |
1098 | sp.to(self.tcx |
1099 | .sess | |
b7449926 XL |
1100 | .source_map() |
1101 | .next_point(self.tcx.sess.source_map().next_point(sp))) | |
ea8adc8c XL |
1102 | } else { |
1103 | sp | |
1104 | }; | |
8faf50e0 | 1105 | (sp, has_bounds) |
ea8adc8c XL |
1106 | }) |
1107 | } else { | |
1108 | None | |
1109 | } | |
1110 | }) | |
1111 | } | |
1112 | _ => None, | |
1113 | }; | |
1a4d82fc JJ |
1114 | |
1115 | let labeled_user_string = match bound_kind { | |
0531ce1d XL |
1116 | GenericKind::Param(ref p) => format!("the parameter type `{}`", p), |
1117 | GenericKind::Projection(ref p) => format!("the associated type `{}`", p), | |
1a4d82fc JJ |
1118 | }; |
1119 | ||
ff7c6d11 | 1120 | if let Some(SubregionOrigin::CompareImplMethodObligation { |
0531ce1d XL |
1121 | span, |
1122 | item_name, | |
1123 | impl_item_def_id, | |
1124 | trait_item_def_id, | |
1125 | }) = origin | |
1126 | { | |
8faf50e0 | 1127 | return self.report_extra_impl_obligation( |
0531ce1d XL |
1128 | span, |
1129 | item_name, | |
1130 | impl_item_def_id, | |
1131 | trait_item_def_id, | |
1132 | &format!("`{}: {}`", bound_kind, sub), | |
8faf50e0 | 1133 | ); |
c30ab7b3 SL |
1134 | } |
1135 | ||
0531ce1d XL |
1136 | fn binding_suggestion<'tcx, S: fmt::Display>( |
1137 | err: &mut DiagnosticBuilder<'tcx>, | |
1138 | type_param_span: Option<(Span, bool)>, | |
1139 | bound_kind: GenericKind<'tcx>, | |
1140 | sub: S, | |
1141 | ) { | |
1142 | let consider = &format!( | |
1143 | "consider adding an explicit lifetime bound `{}: {}`...", | |
1144 | bound_kind, sub | |
1145 | ); | |
ea8adc8c | 1146 | if let Some((sp, has_lifetimes)) = type_param_span { |
0531ce1d | 1147 | let tail = if has_lifetimes { " + " } else { "" }; |
ea8adc8c | 1148 | let suggestion = format!("{}: {}{}", bound_kind, sub, tail); |
94b46f34 | 1149 | err.span_suggestion_short_with_applicability( |
0bf4aa26 XL |
1150 | sp, |
1151 | consider, | |
1152 | suggestion, | |
1153 | Applicability::MaybeIncorrect, // Issue #41966 | |
94b46f34 | 1154 | ); |
ea8adc8c XL |
1155 | } else { |
1156 | err.help(consider); | |
1157 | } | |
1158 | } | |
1159 | ||
9e0c209e | 1160 | let mut err = match *sub { |
0531ce1d XL |
1161 | ty::ReEarlyBound(_) |
1162 | | ty::ReFree(ty::FreeRegion { | |
1163 | bound_region: ty::BrNamed(..), | |
1164 | .. | |
1165 | }) => { | |
1a4d82fc | 1166 | // Does the required lifetime have a nice name we can print? |
0531ce1d XL |
1167 | let mut err = struct_span_err!( |
1168 | self.tcx.sess, | |
1169 | span, | |
1170 | E0309, | |
1171 | "{} may not live long enough", | |
1172 | labeled_user_string | |
1173 | ); | |
ea8adc8c | 1174 | binding_suggestion(&mut err, type_param_span, bound_kind, sub); |
9cc50fc6 | 1175 | err |
1a4d82fc JJ |
1176 | } |
1177 | ||
1178 | ty::ReStatic => { | |
1179 | // Does the required lifetime have a nice name we can print? | |
0531ce1d XL |
1180 | let mut err = struct_span_err!( |
1181 | self.tcx.sess, | |
1182 | span, | |
1183 | E0310, | |
1184 | "{} may not live long enough", | |
1185 | labeled_user_string | |
1186 | ); | |
ea8adc8c | 1187 | binding_suggestion(&mut err, type_param_span, bound_kind, "'static"); |
9cc50fc6 | 1188 | err |
1a4d82fc JJ |
1189 | } |
1190 | ||
1191 | _ => { | |
1192 | // If not, be less specific. | |
0531ce1d XL |
1193 | let mut err = struct_span_err!( |
1194 | self.tcx.sess, | |
1195 | span, | |
1196 | E0311, | |
1197 | "{} may not live long enough", | |
1198 | labeled_user_string | |
1199 | ); | |
1200 | err.help(&format!( | |
1201 | "consider adding an explicit lifetime bound for `{}`", | |
1202 | bound_kind | |
1203 | )); | |
c1a9b12d | 1204 | self.tcx.note_and_explain_region( |
ea8adc8c | 1205 | region_scope_tree, |
9cc50fc6 | 1206 | &mut err, |
c34b1796 | 1207 | &format!("{} must be valid for ", labeled_user_string), |
1a4d82fc | 1208 | sub, |
0531ce1d XL |
1209 | "...", |
1210 | ); | |
9cc50fc6 | 1211 | err |
1a4d82fc | 1212 | } |
9cc50fc6 | 1213 | }; |
e9174d1e | 1214 | |
ff7c6d11 XL |
1215 | if let Some(origin) = origin { |
1216 | self.note_region_origin(&mut err, &origin); | |
1217 | } | |
8faf50e0 | 1218 | err |
1a4d82fc JJ |
1219 | } |
1220 | ||
0531ce1d XL |
1221 | fn report_sub_sup_conflict( |
1222 | &self, | |
1223 | region_scope_tree: ®ion::ScopeTree, | |
1224 | var_origin: RegionVariableOrigin, | |
1225 | sub_origin: SubregionOrigin<'tcx>, | |
1226 | sub_region: Region<'tcx>, | |
1227 | sup_origin: SubregionOrigin<'tcx>, | |
1228 | sup_region: Region<'tcx>, | |
1229 | ) { | |
9cc50fc6 | 1230 | let mut err = self.report_inference_failure(var_origin); |
1a4d82fc | 1231 | |
0531ce1d XL |
1232 | self.tcx.note_and_explain_region( |
1233 | region_scope_tree, | |
1234 | &mut err, | |
1a4d82fc JJ |
1235 | "first, the lifetime cannot outlive ", |
1236 | sup_region, | |
0531ce1d XL |
1237 | "...", |
1238 | ); | |
1a4d82fc | 1239 | |
2c00a5a8 XL |
1240 | match (&sup_origin, &sub_origin) { |
1241 | (&infer::Subtype(ref sup_trace), &infer::Subtype(ref sub_trace)) => { | |
0531ce1d XL |
1242 | if let (Some((sup_expected, sup_found)), Some((sub_expected, sub_found))) = ( |
1243 | self.values_str(&sup_trace.values), | |
1244 | self.values_str(&sub_trace.values), | |
1245 | ) { | |
2c00a5a8 XL |
1246 | if sub_expected == sup_expected && sub_found == sup_found { |
1247 | self.tcx.note_and_explain_region( | |
1248 | region_scope_tree, | |
1249 | &mut err, | |
1250 | "...but the lifetime must also be valid for ", | |
1251 | sub_region, | |
1252 | "...", | |
1253 | ); | |
0531ce1d XL |
1254 | err.note(&format!( |
1255 | "...so that the {}:\nexpected {}\n found {}", | |
1256 | sup_trace.cause.as_requirement_str(), | |
1257 | sup_expected.content(), | |
1258 | sup_found.content() | |
1259 | )); | |
2c00a5a8 XL |
1260 | err.emit(); |
1261 | return; | |
1262 | } | |
1263 | } | |
1264 | } | |
1265 | _ => {} | |
1266 | } | |
1267 | ||
9cc50fc6 | 1268 | self.note_region_origin(&mut err, &sup_origin); |
1a4d82fc | 1269 | |
0531ce1d XL |
1270 | self.tcx.note_and_explain_region( |
1271 | region_scope_tree, | |
1272 | &mut err, | |
1a4d82fc JJ |
1273 | "but, the lifetime must be valid for ", |
1274 | sub_region, | |
0531ce1d XL |
1275 | "...", |
1276 | ); | |
1a4d82fc | 1277 | |
9cc50fc6 SL |
1278 | self.note_region_origin(&mut err, &sub_origin); |
1279 | err.emit(); | |
1a4d82fc | 1280 | } |
1a4d82fc JJ |
1281 | } |
1282 | ||
a7813a04 | 1283 | impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { |
0531ce1d XL |
1284 | fn report_inference_failure( |
1285 | &self, | |
1286 | var_origin: RegionVariableOrigin, | |
1287 | ) -> DiagnosticBuilder<'tcx> { | |
62682a34 SL |
1288 | let br_string = |br: ty::BoundRegion| { |
1289 | let mut s = br.to_string(); | |
1290 | if !s.is_empty() { | |
1291 | s.push_str(" "); | |
1292 | } | |
1293 | s | |
1294 | }; | |
1a4d82fc | 1295 | let var_description = match var_origin { |
b7449926 | 1296 | infer::MiscVariable(_) => String::new(), |
1a4d82fc JJ |
1297 | infer::PatternRegion(_) => " for pattern".to_string(), |
1298 | infer::AddrOfRegion(_) => " for borrow expression".to_string(), | |
1a4d82fc JJ |
1299 | infer::Autoref(_) => " for autoref".to_string(), |
1300 | infer::Coercion(_) => " for automatic coercion".to_string(), | |
1301 | infer::LateBoundRegion(_, br, infer::FnCall) => { | |
0531ce1d | 1302 | format!(" for lifetime parameter {}in function call", br_string(br)) |
1a4d82fc JJ |
1303 | } |
1304 | infer::LateBoundRegion(_, br, infer::HigherRankedType) => { | |
62682a34 | 1305 | format!(" for lifetime parameter {}in generic type", br_string(br)) |
1a4d82fc | 1306 | } |
0531ce1d XL |
1307 | infer::LateBoundRegion(_, br, infer::AssocTypeProjection(def_id)) => format!( |
1308 | " for lifetime parameter {}in trait containing associated type `{}`", | |
1309 | br_string(br), | |
8faf50e0 | 1310 | self.tcx.associated_item(def_id).ident |
0531ce1d XL |
1311 | ), |
1312 | infer::EarlyBoundRegion(_, name) => format!(" for lifetime parameter `{}`", name), | |
1a4d82fc | 1313 | infer::BoundRegionInCoherence(name) => { |
0531ce1d | 1314 | format!(" for lifetime parameter `{}` in coherence check", name) |
1a4d82fc JJ |
1315 | } |
1316 | infer::UpvarRegion(ref upvar_id, _) => { | |
ea8adc8c XL |
1317 | let var_node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_id); |
1318 | let var_name = self.tcx.hir.name(var_node_id); | |
1319 | format!(" for capture of `{}` by closure", var_name) | |
1a4d82fc | 1320 | } |
abe05a73 | 1321 | infer::NLL(..) => bug!("NLL variable found in lexical phase"), |
1a4d82fc JJ |
1322 | }; |
1323 | ||
0531ce1d XL |
1324 | struct_span_err!( |
1325 | self.tcx.sess, | |
1326 | var_origin.span(), | |
1327 | E0495, | |
1328 | "cannot infer an appropriate lifetime{} \ | |
1329 | due to conflicting requirements", | |
1330 | var_description | |
1331 | ) | |
1a4d82fc | 1332 | } |
1a4d82fc JJ |
1333 | } |
1334 | ||
ff7c6d11 XL |
1335 | enum FailureCode { |
1336 | Error0317(&'static str), | |
1337 | Error0580(&'static str), | |
1338 | Error0308(&'static str), | |
1339 | Error0644(&'static str), | |
1340 | } | |
1341 | ||
476ff2be | 1342 | impl<'tcx> ObligationCause<'tcx> { |
ff7c6d11 XL |
1343 | fn as_failure_code(&self, terr: &TypeError<'tcx>) -> FailureCode { |
1344 | use self::FailureCode::*; | |
476ff2be SL |
1345 | use traits::ObligationCauseCode::*; |
1346 | match self.code { | |
ff7c6d11 XL |
1347 | CompareImplMethodObligation { .. } => Error0308("method not compatible with trait"), |
1348 | MatchExpressionArm { source, .. } => Error0308(match source { | |
0bf4aa26 | 1349 | hir::MatchSource::IfLetDesugar { .. } => "`if let` arms have incompatible types", |
8faf50e0 XL |
1350 | hir::MatchSource::TryDesugar => { |
1351 | "try expression alternatives have incompatible types" | |
0bf4aa26 | 1352 | } |
476ff2be | 1353 | _ => "match arms have incompatible types", |
ff7c6d11 XL |
1354 | }), |
1355 | IfExpression => Error0308("if and else have incompatible types"), | |
1356 | IfExpressionWithNoElse => Error0317("if may be missing an else clause"), | |
ff7c6d11 XL |
1357 | MainFunctionType => Error0580("main function has wrong type"), |
1358 | StartFunctionType => Error0308("start function has wrong type"), | |
1359 | IntrinsicType => Error0308("intrinsic has wrong type"), | |
1360 | MethodReceiver => Error0308("mismatched method receiver"), | |
1361 | ||
1362 | // In the case where we have no more specific thing to | |
1363 | // say, also take a look at the error code, maybe we can | |
1364 | // tailor to that. | |
1365 | _ => match terr { | |
0531ce1d XL |
1366 | TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() => { |
1367 | Error0644("closure/generator type that references itself") | |
1368 | } | |
1369 | _ => Error0308("mismatched types"), | |
1370 | }, | |
476ff2be SL |
1371 | } |
1372 | } | |
1373 | ||
1374 | fn as_requirement_str(&self) -> &'static str { | |
1375 | use traits::ObligationCauseCode::*; | |
1376 | match self.code { | |
1377 | CompareImplMethodObligation { .. } => "method type is compatible with trait", | |
1378 | ExprAssignable => "expression is assignable", | |
1379 | MatchExpressionArm { source, .. } => match source { | |
0531ce1d | 1380 | hir::MatchSource::IfLetDesugar { .. } => "`if let` arms have compatible types", |
476ff2be SL |
1381 | _ => "match arms have compatible types", |
1382 | }, | |
1383 | IfExpression => "if and else have compatible types", | |
1384 | IfExpressionWithNoElse => "if missing an else returns ()", | |
476ff2be SL |
1385 | MainFunctionType => "`main` function has the correct type", |
1386 | StartFunctionType => "`start` function has the correct type", | |
1387 | IntrinsicType => "intrinsic has the correct type", | |
1388 | MethodReceiver => "method receiver has the correct type", | |
1389 | _ => "types are compatible", | |
1390 | } | |
1391 | } | |
1392 | } |