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