]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/check/vtable.rs
doc: remove incomplete sentence
[rust.git] / src / librustc_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 check::{FnCtxt, structurally_resolved_type};
12 use middle::traits::{mod, ObjectSafetyViolation, MethodViolationCode};
13 use middle::traits::{Obligation, ObligationCause};
14 use middle::traits::report_fulfillment_errors;
15 use middle::ty::{mod, Ty, AsPredicate};
16 use middle::infer;
17 use syntax::ast;
18 use syntax::codemap::Span;
19 use util::nodemap::FnvHashSet;
20 use util::ppaux::{Repr, UserString};
21
22 pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
23                                    cast_expr: &ast::Expr,
24                                    source_expr: &ast::Expr,
25                                    target_object_ty: Ty<'tcx>)
26 {
27     debug!("check_object_cast(cast_expr={}, target_object_ty={})",
28            cast_expr.repr(fcx.tcx()),
29            target_object_ty.repr(fcx.tcx()));
30
31     // Look up vtables for the type we're casting to,
32     // passing in the source and target type.  The source
33     // must be a pointer type suitable to the object sigil,
34     // e.g.: `&x as &Trait` or `box x as Box<Trait>`
35     let source_ty = fcx.expr_ty(source_expr);
36     let source_ty = structurally_resolved_type(fcx, source_expr.span, source_ty);
37     debug!("source_ty={}", source_ty.repr(fcx.tcx()));
38     match (&source_ty.sty, &target_object_ty.sty) {
39         (&ty::ty_uniq(referent_ty), &ty::ty_uniq(object_trait_ty)) => {
40             let object_trait = object_trait(&object_trait_ty);
41
42             // Ensure that if ~T is cast to ~Trait, then T : Trait
43             push_cast_obligation(fcx, cast_expr, object_trait, referent_ty);
44             check_object_safety(fcx.tcx(), object_trait, source_expr.span);
45         }
46
47         (&ty::ty_rptr(referent_region, ty::mt { ty: referent_ty,
48                                                 mutbl: referent_mutbl }),
49          &ty::ty_rptr(target_region, ty::mt { ty: object_trait_ty,
50                                               mutbl: target_mutbl })) =>
51         {
52             let object_trait = object_trait(&object_trait_ty);
53             if !mutability_allowed(referent_mutbl, target_mutbl) {
54                 fcx.tcx().sess.span_err(source_expr.span,
55                                         "types differ in mutability");
56             } else {
57                 // Ensure that if &'a T is cast to &'b Trait, then T : Trait
58                 push_cast_obligation(fcx, cast_expr,
59                                      object_trait,
60                                      referent_ty);
61
62                 // Ensure that if &'a T is cast to &'b Trait, then 'b <= 'a
63                 infer::mk_subr(fcx.infcx(),
64                                infer::RelateObjectBound(source_expr.span),
65                                *target_region,
66                                *referent_region);
67
68                 check_object_safety(fcx.tcx(), object_trait, source_expr.span);
69             }
70         }
71
72         (_, &ty::ty_uniq(..)) => {
73             fcx.ccx.tcx.sess.span_err(
74                 source_expr.span,
75                 format!("can only cast an boxed pointer \
76                          to a boxed object, not a {}",
77                         ty::ty_sort_string(fcx.tcx(), source_ty))[]);
78         }
79
80         (_, &ty::ty_rptr(..)) => {
81             fcx.ccx.tcx.sess.span_err(
82                 source_expr.span,
83                 format!("can only cast a &-pointer \
84                          to an &-object, not a {}",
85                         ty::ty_sort_string(fcx.tcx(), source_ty))[]);
86         }
87
88         _ => {
89             fcx.tcx().sess.span_bug(
90                 source_expr.span,
91                 "expected object type");
92         }
93     }
94
95     fn object_trait<'a, 'tcx>(t: &'a Ty<'tcx>) -> &'a ty::TyTrait<'tcx> {
96         match t.sty {
97             ty::ty_trait(ref ty_trait) => &**ty_trait,
98             _ => panic!("expected ty_trait")
99         }
100     }
101
102     fn mutability_allowed(a_mutbl: ast::Mutability,
103                           b_mutbl: ast::Mutability)
104                           -> bool {
105         a_mutbl == b_mutbl ||
106             (a_mutbl == ast::MutMutable && b_mutbl == ast::MutImmutable)
107     }
108
109     fn push_cast_obligation<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
110                                       cast_expr: &ast::Expr,
111                                       object_trait: &ty::TyTrait<'tcx>,
112                                       referent_ty: Ty<'tcx>) {
113         let object_trait_ref =
114             register_object_cast_obligations(fcx,
115                                              cast_expr.span,
116                                              object_trait,
117                                              referent_ty);
118
119         // Finally record the object_trait_ref for use during trans
120         // (it would prob be better not to do this, but it's just kind
121         // of a pain to have to reconstruct it).
122         fcx.write_object_cast(cast_expr.id, object_trait_ref);
123     }
124 }
125
126 // Check that a trait is 'object-safe'. This should be checked whenever a trait object
127 // is created (by casting or coercion, etc.). A trait is object-safe if all its
128 // methods are object-safe. A trait method is object-safe if it does not take
129 // self by value, has no type parameters and does not use the `Self` type, except
130 // in self position.
131 pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>,
132                                  object_trait: &ty::TyTrait<'tcx>,
133                                  span: Span)
134 {
135     let object_trait_ref =
136         object_trait.principal_trait_ref_with_self_ty(tcx, tcx.types.err);
137
138     if traits::is_object_safe(tcx, object_trait_ref.clone()) {
139         return;
140     }
141
142     span_err!(tcx.sess, span, E0038,
143               "cannot convert to a trait object because trait `{}` is not object-safe",
144               ty::item_path_str(tcx, object_trait_ref.def_id()));
145
146     let violations = traits::object_safety_violations(tcx, object_trait_ref.clone());
147     for violation in violations.into_iter() {
148         match violation {
149             ObjectSafetyViolation::SizedSelf => {
150                 tcx.sess.span_note(
151                     span,
152                     "the trait cannot require that `Self : Sized`");
153             }
154
155             ObjectSafetyViolation::Method(method, MethodViolationCode::ByValueSelf) => {
156                 tcx.sess.span_note(
157                     span,
158                     format!("method `{}` has a receiver type of `Self`, \
159                              which cannot be used with a trait object",
160                             method.name.user_string(tcx)).as_slice());
161             }
162
163             ObjectSafetyViolation::Method(method, MethodViolationCode::StaticMethod) => {
164                 tcx.sess.span_note(
165                     span,
166                     format!("method `{}` has no receiver",
167                             method.name.user_string(tcx)).as_slice());
168             }
169
170             ObjectSafetyViolation::Method(method, MethodViolationCode::ReferencesSelf) => {
171                 tcx.sess.span_note(
172                     span,
173                     format!("method `{}` references the `Self` type \
174                              in its arguments or return type",
175                             method.name.user_string(tcx)).as_slice());
176             }
177
178             ObjectSafetyViolation::Method(method, MethodViolationCode::Generic) => {
179                 tcx.sess.span_note(
180                     span,
181                     format!("method `{}` has generic type parameters",
182                             method.name.user_string(tcx)).as_slice());
183             }
184         }
185     }
186 }
187
188 pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
189                                                   span: Span,
190                                                   object_trait: &ty::TyTrait<'tcx>,
191                                                   referent_ty: Ty<'tcx>)
192                                                   -> ty::PolyTraitRef<'tcx>
193 {
194     // We can only make objects from sized types.
195     fcx.register_builtin_bound(
196         referent_ty,
197         ty::BoundSized,
198         traits::ObligationCause::new(span, fcx.body_id, traits::ObjectSized));
199
200     // This is just for better error reporting. Kinda goofy. The object type stuff
201     // needs some refactoring so there is a more convenient type to pass around.
202     let object_trait_ty =
203         ty::mk_trait(fcx.tcx(),
204                      object_trait.principal.clone(),
205                      object_trait.bounds.clone());
206
207     debug!("register_object_cast_obligations: referent_ty={} object_trait_ty={}",
208            referent_ty.repr(fcx.tcx()),
209            object_trait_ty.repr(fcx.tcx()));
210
211     let cause = ObligationCause::new(span,
212                                      fcx.body_id,
213                                      traits::ObjectCastObligation(object_trait_ty));
214
215     // Create the obligation for casting from T to Trait.
216     let object_trait_ref =
217         object_trait.principal_trait_ref_with_self_ty(fcx.tcx(), referent_ty);
218     let object_obligation =
219         Obligation::new(cause.clone(), object_trait_ref.as_predicate());
220     fcx.register_predicate(object_obligation);
221
222     // Create additional obligations for all the various builtin
223     // bounds attached to the object cast. (In other words, if the
224     // object type is Foo+Send, this would create an obligation
225     // for the Send check.)
226     for builtin_bound in object_trait.bounds.builtin_bounds.iter() {
227         fcx.register_builtin_bound(
228             referent_ty,
229             builtin_bound,
230             cause.clone());
231     }
232
233     // Create obligations for the projection predicates.
234     let projection_bounds =
235         object_trait.projection_bounds_with_self_ty(fcx.tcx(), referent_ty);
236     for projection_bound in projection_bounds.iter() {
237         let projection_obligation =
238             Obligation::new(cause.clone(), projection_bound.as_predicate());
239         fcx.register_predicate(projection_obligation);
240     }
241
242     // Finally, check that there IS a projection predicate for every associated type.
243     check_object_type_binds_all_associated_types(fcx.tcx(),
244                                                  span,
245                                                  object_trait);
246
247     object_trait_ref
248 }
249
250 fn check_object_type_binds_all_associated_types<'tcx>(tcx: &ty::ctxt<'tcx>,
251                                                       span: Span,
252                                                       object_trait: &ty::TyTrait<'tcx>)
253 {
254     let object_trait_ref =
255         object_trait.principal_trait_ref_with_self_ty(tcx, tcx.types.err);
256
257     let mut associated_types: FnvHashSet<(ast::DefId, ast::Name)> =
258         traits::supertraits(tcx, object_trait_ref.clone())
259         .flat_map(|tr| {
260             let trait_def = ty::lookup_trait_def(tcx, tr.def_id());
261             trait_def.associated_type_names
262                 .clone()
263                 .into_iter()
264                 .map(move |associated_type_name| (tr.def_id(), associated_type_name))
265         })
266         .collect();
267
268     for projection_bound in object_trait.bounds.projection_bounds.iter() {
269         let pair = (projection_bound.0.projection_ty.trait_ref.def_id,
270                     projection_bound.0.projection_ty.item_name);
271         associated_types.remove(&pair);
272     }
273
274     for (trait_def_id, name) in associated_types.into_iter() {
275         tcx.sess.span_err(
276             span,
277             format!("the value of the associated type `{}` (from the trait `{}`) must be specified",
278                     name.user_string(tcx),
279                     ty::item_path_str(tcx, trait_def_id)).as_slice());
280     }
281 }
282
283 pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) {
284     debug!("select_all_fcx_obligations_or_error");
285
286     select_fcx_obligations_where_possible(fcx);
287     fcx.default_type_parameters();
288
289     let mut fulfillment_cx = fcx.inh.fulfillment_cx.borrow_mut();
290     let r = fulfillment_cx.select_all_or_error(fcx.infcx(), fcx);
291     match r {
292         Ok(()) => { }
293         Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); }
294     }
295 }
296
297 /// Select as many obligations as we can at present.
298 pub fn select_fcx_obligations_where_possible(fcx: &FnCtxt)
299 {
300     match
301         fcx.inh.fulfillment_cx
302         .borrow_mut()
303         .select_where_possible(fcx.infcx(), fcx)
304     {
305         Ok(()) => { }
306         Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); }
307     }
308 }
309
310 /// Try to select any fcx obligation that we haven't tried yet, in an effort to improve inference.
311 /// You could just call `select_fcx_obligations_where_possible` except that it leads to repeated
312 /// work.
313 pub fn select_new_fcx_obligations(fcx: &FnCtxt) {
314     match
315         fcx.inh.fulfillment_cx
316         .borrow_mut()
317         .select_new_obligations(fcx.infcx(), fcx)
318     {
319         Ok(()) => { }
320         Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); }
321     }
322 }
323