]> git.proxmox.com Git - rustc.git/blob - src/librustc/middle/traits/error_reporting.rs
Imported Upstream version 1.3.0+dfsg1
[rustc.git] / src / librustc / middle / traits / error_reporting.rs
1 // Copyright 2014 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 use super::{
12 FulfillmentError,
13 FulfillmentErrorCode,
14 MismatchedProjectionTypes,
15 Obligation,
16 ObligationCauseCode,
17 OutputTypeParameterMismatch,
18 TraitNotObjectSafe,
19 PredicateObligation,
20 SelectionError,
21 ObjectSafetyViolation,
22 MethodViolationCode,
23 object_safety_violations,
24 };
25
26 use fmt_macros::{Parser, Piece, Position};
27 use middle::infer::InferCtxt;
28 use middle::ty::{self, ToPredicate, HasTypeFlags, ToPolyTraitRef, TraitRef};
29 use middle::ty_fold::TypeFoldable;
30 use std::collections::HashMap;
31 use std::fmt;
32 use syntax::codemap::{DUMMY_SP, Span};
33 use syntax::attr::{AttributeMethods, AttrMetaMethods};
34
35 pub fn report_fulfillment_errors<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
36 errors: &Vec<FulfillmentError<'tcx>>) {
37 for error in errors {
38 report_fulfillment_error(infcx, error);
39 }
40 }
41
42 fn report_fulfillment_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
43 error: &FulfillmentError<'tcx>) {
44 match error.code {
45 FulfillmentErrorCode::CodeSelectionError(ref e) => {
46 report_selection_error(infcx, &error.obligation, e);
47 }
48 FulfillmentErrorCode::CodeProjectionError(ref e) => {
49 report_projection_error(infcx, &error.obligation, e);
50 }
51 FulfillmentErrorCode::CodeAmbiguity => {
52 maybe_report_ambiguity(infcx, &error.obligation);
53 }
54 }
55 }
56
57 pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
58 obligation: &PredicateObligation<'tcx>,
59 error: &MismatchedProjectionTypes<'tcx>)
60 {
61 let predicate =
62 infcx.resolve_type_vars_if_possible(&obligation.predicate);
63 // The TyError created by normalize_to_error can end up being unified
64 // into all obligations: for example, if our obligation is something
65 // like `$X = <() as Foo<$X>>::Out` and () does not implement Foo<_>,
66 // then $X will be unified with TyError, but the error still needs to be
67 // reported.
68 if !infcx.tcx.sess.has_errors() || !predicate.references_error() {
69 span_err!(infcx.tcx.sess, obligation.cause.span, E0271,
70 "type mismatch resolving `{}`: {}",
71 predicate,
72 error.err);
73 note_obligation_cause(infcx, obligation);
74 }
75 }
76
77 fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
78 trait_ref: &TraitRef<'tcx>,
79 span: Span) -> Option<String> {
80 let def_id = trait_ref.def_id;
81 let mut report = None;
82 for item in infcx.tcx.get_attrs(def_id).iter() {
83 if item.check_name("rustc_on_unimplemented") {
84 let err_sp = if item.meta().span == DUMMY_SP {
85 span
86 } else {
87 item.meta().span
88 };
89 let def = infcx.tcx.lookup_trait_def(def_id);
90 let trait_str = def.trait_ref.to_string();
91 if let Some(ref istring) = item.value_str() {
92 let mut generic_map = def.generics.types.iter_enumerated()
93 .map(|(param, i, gen)| {
94 (gen.name.as_str().to_string(),
95 trait_ref.substs.types.get(param, i)
96 .to_string())
97 }).collect::<HashMap<String, String>>();
98 generic_map.insert("Self".to_string(),
99 trait_ref.self_ty().to_string());
100 let parser = Parser::new(&istring);
101 let mut errored = false;
102 let err: String = parser.filter_map(|p| {
103 match p {
104 Piece::String(s) => Some(s),
105 Piece::NextArgument(a) => match a.position {
106 Position::ArgumentNamed(s) => match generic_map.get(s) {
107 Some(val) => Some(val),
108 None => {
109 span_err!(infcx.tcx.sess, err_sp, E0272,
110 "the #[rustc_on_unimplemented] \
111 attribute on \
112 trait definition for {} refers to \
113 non-existent type parameter {}",
114 trait_str, s);
115 errored = true;
116 None
117 }
118 },
119 _ => {
120 span_err!(infcx.tcx.sess, err_sp, E0273,
121 "the #[rustc_on_unimplemented] \
122 attribute on \
123 trait definition for {} must have named \
124 format arguments, \
125 eg `#[rustc_on_unimplemented = \
126 \"foo {{T}}\"]`",
127 trait_str);
128 errored = true;
129 None
130 }
131 }
132 }
133 }).collect();
134 // Report only if the format string checks out
135 if !errored {
136 report = Some(err);
137 }
138 } else {
139 span_err!(infcx.tcx.sess, err_sp, E0274,
140 "the #[rustc_on_unimplemented] attribute on \
141 trait definition for {} must have a value, \
142 eg `#[rustc_on_unimplemented = \"foo\"]`",
143 trait_str);
144 }
145 break;
146 }
147 }
148 report
149 }
150
151 /// Reports that an overflow has occurred and halts compilation. We
152 /// halt compilation unconditionally because it is important that
153 /// overflows never be masked -- they basically represent computations
154 /// whose result could not be truly determined and thus we can't say
155 /// if the program type checks or not -- and they are unusual
156 /// occurrences in any case.
157 pub fn report_overflow_error<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
158 obligation: &Obligation<'tcx, T>)
159 -> !
160 where T: fmt::Display + TypeFoldable<'tcx>
161 {
162 let predicate =
163 infcx.resolve_type_vars_if_possible(&obligation.predicate);
164 span_err!(infcx.tcx.sess, obligation.cause.span, E0275,
165 "overflow evaluating the requirement `{}`",
166 predicate);
167
168 suggest_new_overflow_limit(infcx.tcx, obligation.cause.span);
169
170 note_obligation_cause(infcx, obligation);
171
172 infcx.tcx.sess.abort_if_errors();
173 unreachable!();
174 }
175
176 pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
177 obligation: &PredicateObligation<'tcx>,
178 error: &SelectionError<'tcx>)
179 {
180 match *error {
181 SelectionError::Unimplemented => {
182 match &obligation.cause.code {
183 &ObligationCauseCode::CompareImplMethodObligation => {
184 span_err!(infcx.tcx.sess, obligation.cause.span, E0276,
185 "the requirement `{}` appears on the impl \
186 method but not on the corresponding trait method",
187 obligation.predicate);;
188 }
189 _ => {
190 match obligation.predicate {
191 ty::Predicate::Trait(ref trait_predicate) => {
192 let trait_predicate =
193 infcx.resolve_type_vars_if_possible(trait_predicate);
194
195 if !infcx.tcx.sess.has_errors() ||
196 !trait_predicate.references_error() {
197 let trait_ref = trait_predicate.to_poly_trait_ref();
198 span_err!(infcx.tcx.sess, obligation.cause.span, E0277,
199 "the trait `{}` is not implemented for the type `{}`",
200 trait_ref,
201 trait_ref.self_ty());
202 // Check if it has a custom "#[rustc_on_unimplemented]"
203 // error message, report with that message if it does
204 let custom_note = report_on_unimplemented(infcx, &trait_ref.0,
205 obligation.cause.span);
206 if let Some(s) = custom_note {
207 infcx.tcx.sess.span_note(obligation.cause.span,
208 &s);
209 }
210 }
211 }
212
213 ty::Predicate::Equate(ref predicate) => {
214 let predicate = infcx.resolve_type_vars_if_possible(predicate);
215 let err = infcx.equality_predicate(obligation.cause.span,
216 &predicate).err().unwrap();
217 span_err!(infcx.tcx.sess, obligation.cause.span, E0278,
218 "the requirement `{}` is not satisfied (`{}`)",
219 predicate,
220 err);
221 }
222
223 ty::Predicate::RegionOutlives(ref predicate) => {
224 let predicate = infcx.resolve_type_vars_if_possible(predicate);
225 let err = infcx.region_outlives_predicate(obligation.cause.span,
226 &predicate).err().unwrap();
227 span_err!(infcx.tcx.sess, obligation.cause.span, E0279,
228 "the requirement `{}` is not satisfied (`{}`)",
229 predicate,
230 err);
231 }
232
233 ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
234 let predicate =
235 infcx.resolve_type_vars_if_possible(&obligation.predicate);
236 span_err!(infcx.tcx.sess, obligation.cause.span, E0280,
237 "the requirement `{}` is not satisfied",
238 predicate);
239 }
240 }
241 }
242 }
243 }
244
245 OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, ref e) => {
246 let expected_trait_ref = infcx.resolve_type_vars_if_possible(&*expected_trait_ref);
247 let actual_trait_ref = infcx.resolve_type_vars_if_possible(&*actual_trait_ref);
248 if !actual_trait_ref.self_ty().references_error() {
249 span_err!(infcx.tcx.sess, obligation.cause.span, E0281,
250 "type mismatch: the type `{}` implements the trait `{}`, \
251 but the trait `{}` is required ({})",
252 expected_trait_ref.self_ty(),
253 expected_trait_ref,
254 actual_trait_ref,
255 e);
256 note_obligation_cause(infcx, obligation);
257 }
258 }
259
260 TraitNotObjectSafe(did) => {
261 span_err!(infcx.tcx.sess, obligation.cause.span, E0038,
262 "cannot convert to a trait object because trait `{}` is not object-safe",
263 infcx.tcx.item_path_str(did));
264
265 for violation in object_safety_violations(infcx.tcx, did) {
266 match violation {
267 ObjectSafetyViolation::SizedSelf => {
268 infcx.tcx.sess.span_note(
269 obligation.cause.span,
270 "the trait cannot require that `Self : Sized`");
271 }
272
273 ObjectSafetyViolation::SupertraitSelf => {
274 infcx.tcx.sess.span_note(
275 obligation.cause.span,
276 "the trait cannot use `Self` as a type parameter \
277 in the supertrait listing");
278 }
279
280 ObjectSafetyViolation::Method(method,
281 MethodViolationCode::StaticMethod) => {
282 infcx.tcx.sess.span_note(
283 obligation.cause.span,
284 &format!("method `{}` has no receiver",
285 method.name));
286 }
287
288 ObjectSafetyViolation::Method(method,
289 MethodViolationCode::ReferencesSelf) => {
290 infcx.tcx.sess.span_note(
291 obligation.cause.span,
292 &format!("method `{}` references the `Self` type \
293 in its arguments or return type",
294 method.name));
295 }
296
297 ObjectSafetyViolation::Method(method,
298 MethodViolationCode::Generic) => {
299 infcx.tcx.sess.span_note(
300 obligation.cause.span,
301 &format!("method `{}` has generic type parameters",
302 method.name));
303 }
304 }
305 }
306 }
307 }
308 }
309
310 pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
311 obligation: &PredicateObligation<'tcx>) {
312 // Unable to successfully determine, probably means
313 // insufficient type information, but could mean
314 // ambiguous impls. The latter *ought* to be a
315 // coherence violation, so we don't report it here.
316
317 let predicate = infcx.resolve_type_vars_if_possible(&obligation.predicate);
318
319 debug!("maybe_report_ambiguity(predicate={:?}, obligation={:?})",
320 predicate,
321 obligation);
322
323 match predicate {
324 ty::Predicate::Trait(ref data) => {
325 let trait_ref = data.to_poly_trait_ref();
326 let self_ty = trait_ref.self_ty();
327 let all_types = &trait_ref.substs().types;
328 if all_types.references_error() {
329 } else if all_types.needs_infer() {
330 // This is kind of a hack: it frequently happens that some earlier
331 // error prevents types from being fully inferred, and then we get
332 // a bunch of uninteresting errors saying something like "<generic
333 // #0> doesn't implement Sized". It may even be true that we
334 // could just skip over all checks where the self-ty is an
335 // inference variable, but I was afraid that there might be an
336 // inference variable created, registered as an obligation, and
337 // then never forced by writeback, and hence by skipping here we'd
338 // be ignoring the fact that we don't KNOW the type works
339 // out. Though even that would probably be harmless, given that
340 // we're only talking about builtin traits, which are known to be
341 // inhabited. But in any case I just threw in this check for
342 // has_errors() to be sure that compilation isn't happening
343 // anyway. In that case, why inundate the user.
344 if !infcx.tcx.sess.has_errors() {
345 if
346 infcx.tcx.lang_items.sized_trait()
347 .map_or(false, |sized_id| sized_id == trait_ref.def_id())
348 {
349 span_err!(infcx.tcx.sess, obligation.cause.span, E0282,
350 "unable to infer enough type information about `{}`; \
351 type annotations or generic parameter binding required",
352 self_ty);
353 } else {
354 span_err!(infcx.tcx.sess, obligation.cause.span, E0283,
355 "type annotations required: cannot resolve `{}`",
356 predicate);;
357 note_obligation_cause(infcx, obligation);
358 }
359 }
360 } else if !infcx.tcx.sess.has_errors() {
361 // Ambiguity. Coherence should have reported an error.
362 infcx.tcx.sess.span_bug(
363 obligation.cause.span,
364 &format!(
365 "coherence failed to report ambiguity: \
366 cannot locate the impl of the trait `{}` for \
367 the type `{}`",
368 trait_ref,
369 self_ty));
370 }
371 }
372
373 _ => {
374 if !infcx.tcx.sess.has_errors() {
375 span_err!(infcx.tcx.sess, obligation.cause.span, E0284,
376 "type annotations required: cannot resolve `{}`",
377 predicate);;
378 note_obligation_cause(infcx, obligation);
379 }
380 }
381 }
382 }
383
384 fn note_obligation_cause<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
385 obligation: &Obligation<'tcx, T>)
386 where T: fmt::Display
387 {
388 note_obligation_cause_code(infcx,
389 &obligation.predicate,
390 obligation.cause.span,
391 &obligation.cause.code);
392 }
393
394 fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
395 predicate: &T,
396 cause_span: Span,
397 cause_code: &ObligationCauseCode<'tcx>)
398 where T: fmt::Display
399 {
400 let tcx = infcx.tcx;
401 match *cause_code {
402 ObligationCauseCode::MiscObligation => { }
403 ObligationCauseCode::ItemObligation(item_def_id) => {
404 let item_name = tcx.item_path_str(item_def_id);
405 tcx.sess.span_note(
406 cause_span,
407 &format!("required by `{}`", item_name));
408 }
409 ObligationCauseCode::ObjectCastObligation(object_ty) => {
410 tcx.sess.span_note(
411 cause_span,
412 &format!(
413 "required for the cast to the object type `{}`",
414 infcx.ty_to_string(object_ty)));
415 }
416 ObligationCauseCode::RepeatVec => {
417 tcx.sess.span_note(
418 cause_span,
419 "the `Copy` trait is required because the \
420 repeated element will be copied");
421 }
422 ObligationCauseCode::VariableType(_) => {
423 tcx.sess.span_note(
424 cause_span,
425 "all local variables must have a statically known size");
426 }
427 ObligationCauseCode::ReturnType => {
428 tcx.sess.span_note(
429 cause_span,
430 "the return type of a function must have a \
431 statically known size");
432 }
433 ObligationCauseCode::AssignmentLhsSized => {
434 tcx.sess.span_note(
435 cause_span,
436 "the left-hand-side of an assignment must have a statically known size");
437 }
438 ObligationCauseCode::StructInitializerSized => {
439 tcx.sess.span_note(
440 cause_span,
441 "structs must have a statically known size to be initialized");
442 }
443 ObligationCauseCode::ClosureCapture(var_id, closure_span, builtin_bound) => {
444 let def_id = tcx.lang_items.from_builtin_kind(builtin_bound).unwrap();
445 let trait_name = tcx.item_path_str(def_id);
446 let name = tcx.local_var_name_str(var_id);
447 span_note!(tcx.sess, closure_span,
448 "the closure that captures `{}` requires that all captured variables \
449 implement the trait `{}`",
450 name,
451 trait_name);
452 }
453 ObligationCauseCode::FieldSized => {
454 span_note!(tcx.sess, cause_span,
455 "only the last field of a struct or enum variant \
456 may have a dynamically sized type")
457 }
458 ObligationCauseCode::SharedStatic => {
459 span_note!(tcx.sess, cause_span,
460 "shared static variables must have a type that implements `Sync`");
461 }
462 ObligationCauseCode::BuiltinDerivedObligation(ref data) => {
463 let parent_trait_ref = infcx.resolve_type_vars_if_possible(&data.parent_trait_ref);
464 span_note!(tcx.sess, cause_span,
465 "required because it appears within the type `{}`",
466 parent_trait_ref.0.self_ty());
467 let parent_predicate = parent_trait_ref.to_predicate();
468 note_obligation_cause_code(infcx, &parent_predicate, cause_span, &*data.parent_code);
469 }
470 ObligationCauseCode::ImplDerivedObligation(ref data) => {
471 let parent_trait_ref = infcx.resolve_type_vars_if_possible(&data.parent_trait_ref);
472 span_note!(tcx.sess, cause_span,
473 "required because of the requirements on the impl of `{}` for `{}`",
474 parent_trait_ref,
475 parent_trait_ref.0.self_ty());
476 let parent_predicate = parent_trait_ref.to_predicate();
477 note_obligation_cause_code(infcx, &parent_predicate, cause_span, &*data.parent_code);
478 }
479 ObligationCauseCode::CompareImplMethodObligation => {
480 span_note!(tcx.sess, cause_span,
481 "the requirement `{}` appears on the impl method \
482 but not on the corresponding trait method",
483 predicate);
484 }
485 }
486 }
487
488 pub fn suggest_new_overflow_limit(tcx: &ty::ctxt, span: Span) {
489 let current_limit = tcx.sess.recursion_limit.get();
490 let suggested_limit = current_limit * 2;
491 tcx.sess.span_note(
492 span,
493 &format!(
494 "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
495 suggested_limit));
496 }