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