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