]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/typeck/check/vtable.rs
/*! -> //!
[rust.git] / src / librustc / middle / typeck / check / vtable.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 middle::subst::{SelfSpace, FnSpace};
12 use middle::traits;
13 use middle::traits::{SelectionError, OutputTypeParameterMismatch, Overflow, Unimplemented};
14 use middle::traits::{Obligation, obligation_for_builtin_bound};
15 use middle::traits::{FulfillmentError, CodeSelectionError, CodeAmbiguity};
16 use middle::traits::{ObligationCause};
17 use middle::ty::{mod, Ty};
18 use middle::typeck::check::{FnCtxt,
19                             structurally_resolved_type};
20 use middle::typeck::infer;
21 use std::rc::Rc;
22 use syntax::ast;
23 use syntax::codemap::Span;
24 use util::common::ErrorReported;
25 use util::ppaux::{UserString, Repr, ty_to_string};
26
27 pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
28                                    cast_expr: &ast::Expr,
29                                    source_expr: &ast::Expr,
30                                    target_object_ty: Ty<'tcx>)
31 {
32     debug!("check_object_cast(cast_expr={}, target_object_ty={})",
33            cast_expr.repr(fcx.tcx()),
34            target_object_ty.repr(fcx.tcx()));
35
36     // Look up vtables for the type we're casting to,
37     // passing in the source and target type.  The source
38     // must be a pointer type suitable to the object sigil,
39     // e.g.: `&x as &Trait` or `box x as Box<Trait>`
40     let source_ty = fcx.expr_ty(source_expr);
41     let source_ty = structurally_resolved_type(fcx, source_expr.span, source_ty);
42     debug!("source_ty={}", source_ty.repr(fcx.tcx()));
43     match (&source_ty.sty, &target_object_ty.sty) {
44         (&ty::ty_uniq(referent_ty), &ty::ty_uniq(object_trait_ty)) => {
45             let object_trait = object_trait(&object_trait_ty);
46
47             // Ensure that if ~T is cast to ~Trait, then T : Trait
48             push_cast_obligation(fcx, cast_expr, object_trait, referent_ty);
49             check_object_safety(fcx.tcx(), object_trait, source_expr.span);
50         }
51
52         (&ty::ty_rptr(referent_region, ty::mt { ty: referent_ty,
53                                                 mutbl: referent_mutbl }),
54          &ty::ty_rptr(target_region, ty::mt { ty: object_trait_ty,
55                                               mutbl: target_mutbl })) =>
56         {
57             let object_trait = object_trait(&object_trait_ty);
58             if !mutability_allowed(referent_mutbl, target_mutbl) {
59                 fcx.tcx().sess.span_err(source_expr.span,
60                                         "types differ in mutability");
61             } else {
62                 // Ensure that if &'a T is cast to &'b Trait, then T : Trait
63                 push_cast_obligation(fcx, cast_expr,
64                                      object_trait,
65                                      referent_ty);
66
67                 // Ensure that if &'a T is cast to &'b Trait, then 'b <= 'a
68                 infer::mk_subr(fcx.infcx(),
69                                infer::RelateObjectBound(source_expr.span),
70                                target_region,
71                                referent_region);
72
73                 check_object_safety(fcx.tcx(), object_trait, source_expr.span);
74             }
75         }
76
77         (_, &ty::ty_uniq(..)) => {
78             fcx.ccx.tcx.sess.span_err(
79                 source_expr.span,
80                 format!("can only cast an boxed pointer \
81                          to a boxed object, not a {}",
82                         ty::ty_sort_string(fcx.tcx(), source_ty)).as_slice());
83         }
84
85         (_, &ty::ty_rptr(..)) => {
86             fcx.ccx.tcx.sess.span_err(
87                 source_expr.span,
88                 format!("can only cast a &-pointer \
89                          to an &-object, not a {}",
90                         ty::ty_sort_string(fcx.tcx(), source_ty)).as_slice());
91         }
92
93         _ => {
94             fcx.tcx().sess.span_bug(
95                 source_expr.span,
96                 "expected object type");
97         }
98     }
99
100     fn object_trait<'a, 'tcx>(t: &'a Ty<'tcx>) -> &'a ty::TyTrait<'tcx> {
101         match t.sty {
102             ty::ty_trait(ref ty_trait) => &**ty_trait,
103             _ => panic!("expected ty_trait")
104         }
105     }
106
107     fn mutability_allowed(a_mutbl: ast::Mutability,
108                           b_mutbl: ast::Mutability)
109                           -> bool {
110         a_mutbl == b_mutbl ||
111             (a_mutbl == ast::MutMutable && b_mutbl == ast::MutImmutable)
112     }
113
114     fn push_cast_obligation<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
115                                       cast_expr: &ast::Expr,
116                                       object_trait: &ty::TyTrait<'tcx>,
117                                       referent_ty: Ty<'tcx>) {
118         let object_trait_ref =
119             register_object_cast_obligations(fcx,
120                                              cast_expr.span,
121                                              object_trait,
122                                              referent_ty);
123
124         // Finally record the object_trait_ref for use during trans
125         // (it would prob be better not to do this, but it's just kind
126         // of a pain to have to reconstruct it).
127         fcx.write_object_cast(cast_expr.id, object_trait_ref);
128     }
129 }
130
131 // Check that a trait is 'object-safe'. This should be checked whenever a trait object
132 // is created (by casting or coercion, etc.). A trait is object-safe if all its
133 // methods are object-safe. A trait method is object-safe if it does not take
134 // self by value, has no type parameters and does not use the `Self` type, except
135 // in self position.
136 pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>,
137                                  object_trait: &ty::TyTrait<'tcx>,
138                                  span: Span) {
139     // Skip the fn_once lang item trait since only the compiler should call
140     // `call_once` which is the method which takes self by value. What could go
141     // wrong?
142     match tcx.lang_items.fn_once_trait() {
143         Some(def_id) if def_id == object_trait.principal.def_id => return,
144         _ => {}
145     }
146
147     let trait_items = ty::trait_items(tcx, object_trait.principal.def_id);
148
149     let mut errors = Vec::new();
150     for item in trait_items.iter() {
151         match *item {
152             ty::MethodTraitItem(ref m) => {
153                 errors.push(check_object_safety_of_method(tcx, &**m))
154             }
155             ty::TypeTraitItem(_) => {}
156         }
157     }
158
159     let mut errors = errors.iter().flat_map(|x| x.iter()).peekable();
160     if errors.peek().is_some() {
161         let trait_name = ty::item_path_str(tcx, object_trait.principal.def_id);
162         span_err!(tcx.sess, span, E0038,
163             "cannot convert to a trait object because trait `{}` is not object-safe",
164             trait_name);
165
166         for msg in errors {
167             tcx.sess.note(msg.as_slice());
168         }
169     }
170
171     /// Returns a vec of error messages. If hte vec is empty - no errors!
172     ///
173     /// There are some limitations to calling functions through an object, because (a) the self
174     /// type is not known (that's the whole point of a trait instance, after all, to obscure the
175     /// self type) and (b) the call must go through a vtable and hence cannot be monomorphized.
176     fn check_object_safety_of_method<'tcx>(tcx: &ty::ctxt<'tcx>,
177                                            method: &ty::Method<'tcx>)
178                                            -> Vec<String> {
179         let mut msgs = Vec::new();
180
181         let method_name = method.name.repr(tcx);
182
183         match method.explicit_self {
184             ty::ByValueExplicitSelfCategory => { // reason (a) above
185                 msgs.push(format!("cannot call a method (`{}`) with a by-value \
186                                    receiver through a trait object", method_name))
187             }
188
189             ty::StaticExplicitSelfCategory => {
190                 // Static methods are always object-safe since they
191                 // can't be called through a trait object
192                 return msgs
193             }
194             ty::ByReferenceExplicitSelfCategory(..) |
195             ty::ByBoxExplicitSelfCategory => {}
196         }
197
198         // reason (a) above
199         let check_for_self_ty = |ty| {
200             if ty::type_has_self(ty) {
201                 Some(format!(
202                     "cannot call a method (`{}`) whose type contains \
203                      a self-type (`{}`) through a trait object",
204                     method_name, ty_to_string(tcx, ty)))
205             } else {
206                 None
207             }
208         };
209         let ref sig = method.fty.sig;
210         for &input_ty in sig.inputs[1..].iter() {
211             match check_for_self_ty(input_ty) {
212                 Some(msg) => msgs.push(msg),
213                 _ => {}
214             }
215         }
216         if let ty::FnConverging(result_type) = sig.output {
217             match check_for_self_ty(result_type) {
218                 Some(msg) => msgs.push(msg),
219                 _ => {}
220             }
221         }
222
223         if method.generics.has_type_params(FnSpace) {
224             // reason (b) above
225             msgs.push(format!("cannot call a generic method (`{}`) through a trait object",
226                               method_name));
227         }
228
229         msgs
230     }
231 }
232
233 pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
234                                                   span: Span,
235                                                   object_trait: &ty::TyTrait<'tcx>,
236                                                   referent_ty: Ty<'tcx>)
237                                                   -> Rc<ty::TraitRef<'tcx>>
238 {
239     // We can only make objects from sized types.
240     let sized_obligation =
241         traits::obligation_for_builtin_bound(
242             fcx.tcx(),
243             traits::ObligationCause::new(span, traits::ObjectSized),
244             referent_ty,
245             ty::BoundSized);
246     match sized_obligation {
247         Ok(sized_obligation) => {
248             fcx.register_obligation(sized_obligation);
249         }
250         Err(ErrorReported) => { }
251     }
252
253     // This is just for better error reporting. Kinda goofy. The object type stuff
254     // needs some refactoring so there is a more convenient type to pass around.
255     let object_trait_ty =
256         ty::mk_trait(fcx.tcx(),
257                      object_trait.principal.clone(),
258                      object_trait.bounds);
259
260     debug!("register_object_cast_obligations: referent_ty={} object_trait_ty={}",
261            referent_ty.repr(fcx.tcx()),
262            object_trait_ty.repr(fcx.tcx()));
263
264     // Take the type parameters from the object type, but set
265     // the Self type (which is unknown, for the object type)
266     // to be the type we are casting from.
267     let mut object_substs = object_trait.principal.substs.clone();
268     assert!(object_substs.self_ty().is_none());
269     object_substs.types.push(SelfSpace, referent_ty);
270
271     // Create the obligation for casting from T to Trait.
272     let object_trait_ref =
273         Rc::new(ty::TraitRef { def_id: object_trait.principal.def_id,
274                                substs: object_substs });
275     let object_obligation =
276         Obligation::new(
277             ObligationCause::new(span,
278                                  traits::ObjectCastObligation(object_trait_ty)),
279             object_trait_ref.clone());
280     fcx.register_obligation(object_obligation);
281
282     // Create additional obligations for all the various builtin
283     // bounds attached to the object cast. (In other words, if the
284     // object type is Foo+Send, this would create an obligation
285     // for the Send check.)
286     for builtin_bound in object_trait.bounds.builtin_bounds.iter() {
287             let obligation = obligation_for_builtin_bound(
288                 fcx.tcx(),
289                 ObligationCause::new(span,
290                                      traits::ObjectCastObligation(object_trait_ty)),
291                 referent_ty,
292                 builtin_bound);
293             match obligation {
294                 Ok(obligation) => fcx.register_obligation(obligation),
295                 _ => {}
296             }
297     }
298
299     object_trait_ref
300 }
301
302 pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) {
303     debug!("select_all_fcx_obligations_or_error");
304
305     let mut fulfillment_cx = fcx.inh.fulfillment_cx.borrow_mut();
306     let r = fulfillment_cx.select_all_or_error(fcx.infcx(),
307                                                &fcx.inh.param_env,
308                                                fcx);
309     match r {
310         Ok(()) => { }
311         Err(errors) => { report_fulfillment_errors(fcx, &errors); }
312     }
313 }
314
315 fn resolve_trait_ref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, obligation: &Obligation<'tcx>)
316                                -> (Rc<ty::TraitRef<'tcx>>, Ty<'tcx>)
317 {
318     let trait_ref =
319         fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(
320             &*obligation.trait_ref);
321     let self_ty =
322         trait_ref.substs.self_ty().unwrap();
323     (Rc::new(trait_ref), self_ty)
324 }
325
326 pub fn report_fulfillment_errors<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
327                                            errors: &Vec<FulfillmentError<'tcx>>) {
328     for error in errors.iter() {
329         report_fulfillment_error(fcx, error);
330     }
331 }
332
333 pub fn report_fulfillment_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
334                                           error: &FulfillmentError<'tcx>) {
335     match error.code {
336         CodeSelectionError(ref e) => {
337             report_selection_error(fcx, &error.obligation, e);
338         }
339         CodeAmbiguity => {
340             maybe_report_ambiguity(fcx, &error.obligation);
341         }
342     }
343 }
344
345 pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
346                                         obligation: &Obligation<'tcx>,
347                                         error: &SelectionError<'tcx>)
348 {
349     match *error {
350         Overflow => {
351             let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation);
352             fcx.tcx().sess.span_err(
353                 obligation.cause.span,
354                 format!(
355                     "overflow evaluating the trait `{}` for the type `{}`",
356                     trait_ref.user_string(fcx.tcx()),
357                     self_ty.user_string(fcx.tcx())).as_slice());
358             note_obligation_cause(fcx, obligation);
359         }
360         Unimplemented => {
361             let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation);
362             if !ty::type_is_error(self_ty) {
363                 fcx.tcx().sess.span_err(
364                     obligation.cause.span,
365                     format!(
366                         "the trait `{}` is not implemented for the type `{}`",
367                         trait_ref.user_string(fcx.tcx()),
368                         self_ty.user_string(fcx.tcx())).as_slice());
369                 note_obligation_cause(fcx, obligation);
370             }
371         }
372         OutputTypeParameterMismatch(ref expected_trait_ref, ref e) => {
373             let expected_trait_ref =
374                 fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(
375                     &**expected_trait_ref);
376             let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation);
377             if !ty::type_is_error(self_ty) {
378                 fcx.tcx().sess.span_err(
379                     obligation.cause.span,
380                     format!(
381                         "type mismatch: the type `{}` implements the trait `{}`, \
382                          but the trait `{}` is required ({})",
383                         self_ty.user_string(fcx.tcx()),
384                         expected_trait_ref.user_string(fcx.tcx()),
385                         trait_ref.user_string(fcx.tcx()),
386                         ty::type_err_to_str(fcx.tcx(), e)).as_slice());
387                 note_obligation_cause(fcx, obligation);
388             }
389         }
390     }
391 }
392
393 pub fn maybe_report_ambiguity<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
394                                         obligation: &Obligation<'tcx>) {
395     // Unable to successfully determine, probably means
396     // insufficient type information, but could mean
397     // ambiguous impls. The latter *ought* to be a
398     // coherence violation, so we don't report it here.
399     let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation);
400     debug!("maybe_report_ambiguity(trait_ref={}, self_ty={}, obligation={})",
401            trait_ref.repr(fcx.tcx()),
402            self_ty.repr(fcx.tcx()),
403            obligation.repr(fcx.tcx()));
404     let all_types = &trait_ref.substs.types;
405     if all_types.iter().any(|&t| ty::type_is_error(t)) {
406     } else if all_types.iter().any(|&t| ty::type_needs_infer(t)) {
407         // This is kind of a hack: it frequently happens that some earlier
408         // error prevents types from being fully inferred, and then we get
409         // a bunch of uninteresting errors saying something like "<generic
410         // #0> doesn't implement Sized".  It may even be true that we
411         // could just skip over all checks where the self-ty is an
412         // inference variable, but I was afraid that there might be an
413         // inference variable created, registered as an obligation, and
414         // then never forced by writeback, and hence by skipping here we'd
415         // be ignoring the fact that we don't KNOW the type works
416         // out. Though even that would probably be harmless, given that
417         // we're only talking about builtin traits, which are known to be
418         // inhabited. But in any case I just threw in this check for
419         // has_errors() to be sure that compilation isn't happening
420         // anyway. In that case, why inundate the user.
421         if !fcx.tcx().sess.has_errors() {
422             if fcx.ccx.tcx.lang_items.sized_trait()
423                   .map_or(false, |sized_id| sized_id == trait_ref.def_id) {
424                 fcx.tcx().sess.span_err(
425                     obligation.cause.span,
426                     format!(
427                         "unable to infer enough type information about `{}`; type annotations \
428                          required",
429                         self_ty.user_string(fcx.tcx())).as_slice());
430             } else {
431                 fcx.tcx().sess.span_err(
432                     obligation.cause.span,
433                     format!(
434                         "unable to infer enough type information to \
435                          locate the impl of the trait `{}` for \
436                          the type `{}`; type annotations required",
437                         trait_ref.user_string(fcx.tcx()),
438                         self_ty.user_string(fcx.tcx())).as_slice());
439                 note_obligation_cause(fcx, obligation);
440             }
441         }
442     } else if !fcx.tcx().sess.has_errors() {
443          // Ambiguity. Coherence should have reported an error.
444         fcx.tcx().sess.span_bug(
445             obligation.cause.span,
446             format!(
447                 "coherence failed to report ambiguity: \
448                  cannot locate the impl of the trait `{}` for \
449                  the type `{}`",
450                 trait_ref.user_string(fcx.tcx()),
451                 self_ty.user_string(fcx.tcx())).as_slice());
452     }
453 }
454
455 /// Select as many obligations as we can at present.
456 pub fn select_fcx_obligations_where_possible(fcx: &FnCtxt) {
457
458     match
459         fcx.inh.fulfillment_cx
460         .borrow_mut()
461         .select_where_possible(fcx.infcx(), &fcx.inh.param_env, fcx)
462     {
463         Ok(()) => { }
464         Err(errors) => { report_fulfillment_errors(fcx, &errors); }
465     }
466 }
467
468 /// Try to select any fcx obligation that we haven't tried yet, in an effort to improve inference.
469 /// You could just call `select_fcx_obligations_where_possible` except that it leads to repeated
470 /// work.
471 pub fn select_new_fcx_obligations(fcx: &FnCtxt) {
472     match
473         fcx.inh.fulfillment_cx
474         .borrow_mut()
475         .select_new_obligations(fcx.infcx(), &fcx.inh.param_env, fcx)
476     {
477         Ok(()) => { }
478         Err(errors) => { report_fulfillment_errors(fcx, &errors); }
479     }
480 }
481
482 fn note_obligation_cause<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
483                                    obligation: &Obligation<'tcx>) {
484     let tcx = fcx.tcx();
485     let trait_name = ty::item_path_str(tcx, obligation.trait_ref.def_id);
486     match obligation.cause.code {
487         traits::MiscObligation => { }
488         traits::ItemObligation(item_def_id) => {
489             let item_name = ty::item_path_str(tcx, item_def_id);
490             tcx.sess.span_note(
491                 obligation.cause.span,
492                 format!(
493                     "the trait `{}` must be implemented because it is required by `{}`",
494                     trait_name,
495                     item_name).as_slice());
496         }
497         traits::ObjectCastObligation(object_ty) => {
498             tcx.sess.span_note(
499                 obligation.cause.span,
500                 format!(
501                     "the trait `{}` must be implemented for the cast \
502                      to the object type `{}`",
503                     trait_name,
504                     fcx.infcx().ty_to_string(object_ty)).as_slice());
505         }
506         traits::RepeatVec => {
507             tcx.sess.span_note(
508                 obligation.cause.span,
509                 "the `Copy` trait is required because the \
510                  repeated element will be copied");
511         }
512         traits::VariableType(_) => {
513             tcx.sess.span_note(
514                 obligation.cause.span,
515                 "all local variables must have a statically known size");
516         }
517         traits::ReturnType => {
518             tcx.sess.span_note(
519                 obligation.cause.span,
520                 "the return type of a function must have a \
521                  statically known size");
522         }
523         traits::AssignmentLhsSized => {
524             tcx.sess.span_note(
525                 obligation.cause.span,
526                 "the left-hand-side of an assignment must have a statically known size");
527         }
528         traits::StructInitializerSized => {
529             tcx.sess.span_note(
530                 obligation.cause.span,
531                 "structs must have a statically known size to be initialized");
532         }
533         traits::DropTrait => {
534             span_note!(tcx.sess, obligation.cause.span,
535                       "cannot implement a destructor on a \
536                       structure or enumeration that does not satisfy Send");
537             span_help!(tcx.sess, obligation.cause.span,
538                        "use \"#[unsafe_destructor]\" on the implementation \
539                        to force the compiler to allow this");
540         }
541         traits::ClosureCapture(var_id, closure_span) => {
542             let name = ty::local_var_name_str(tcx, var_id);
543             span_note!(tcx.sess, closure_span,
544                        "the closure that captures `{}` requires that all captured variables \"
545                        implement the trait `{}`",
546                        name,
547                        trait_name);
548         }
549         traits::FieldSized => {
550             span_note!(tcx.sess, obligation.cause.span,
551                        "only the last field of a struct or enum variant \
552                        may have a dynamically sized type")
553         }
554         traits::ObjectSized => {
555             span_note!(tcx.sess, obligation.cause.span,
556                        "only sized types can be made into objects");
557         }
558     }
559 }