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.
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.
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};
18 use syntax::codemap::Span;
19 use util::nodemap::FnvHashSet;
20 use util::ppaux::{Repr, UserString};
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>)
27 debug!("check_object_cast(cast_expr={}, target_object_ty={})",
28 cast_expr.repr(fcx.tcx()),
29 target_object_ty.repr(fcx.tcx()));
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);
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);
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 })) =>
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");
57 // Ensure that if &'a T is cast to &'b Trait, then T : Trait
58 push_cast_obligation(fcx, cast_expr,
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),
68 check_object_safety(fcx.tcx(), object_trait, source_expr.span);
72 (_, &ty::ty_uniq(..)) => {
73 fcx.ccx.tcx.sess.span_err(
75 format!("can only cast an boxed pointer \
76 to a boxed object, not a {}",
77 ty::ty_sort_string(fcx.tcx(), source_ty))[]);
80 (_, &ty::ty_rptr(..)) => {
81 fcx.ccx.tcx.sess.span_err(
83 format!("can only cast a &-pointer \
84 to an &-object, not a {}",
85 ty::ty_sort_string(fcx.tcx(), source_ty))[]);
89 fcx.tcx().sess.span_bug(
91 "expected object type");
95 fn object_trait<'a, 'tcx>(t: &'a Ty<'tcx>) -> &'a ty::TyTrait<'tcx> {
97 ty::ty_trait(ref ty_trait) => &**ty_trait,
98 _ => panic!("expected ty_trait")
102 fn mutability_allowed(a_mutbl: ast::Mutability,
103 b_mutbl: ast::Mutability)
105 a_mutbl == b_mutbl ||
106 (a_mutbl == ast::MutMutable && b_mutbl == ast::MutImmutable)
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,
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);
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
131 pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>,
132 object_trait: &ty::TyTrait<'tcx>,
135 let object_trait_ref =
136 object_trait.principal_trait_ref_with_self_ty(tcx, tcx.types.err);
138 if traits::is_object_safe(tcx, object_trait_ref.clone()) {
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()));
146 let violations = traits::object_safety_violations(tcx, object_trait_ref.clone());
147 for violation in violations.into_iter() {
149 ObjectSafetyViolation::SizedSelf => {
152 "the trait cannot require that `Self : Sized`");
155 ObjectSafetyViolation::Method(method, MethodViolationCode::ByValueSelf) => {
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());
163 ObjectSafetyViolation::Method(method, MethodViolationCode::StaticMethod) => {
166 format!("method `{}` has no receiver",
167 method.name.user_string(tcx)).as_slice());
170 ObjectSafetyViolation::Method(method, MethodViolationCode::ReferencesSelf) => {
173 format!("method `{}` references the `Self` type \
174 in its arguments or return type",
175 method.name.user_string(tcx)).as_slice());
178 ObjectSafetyViolation::Method(method, MethodViolationCode::Generic) => {
181 format!("method `{}` has generic type parameters",
182 method.name.user_string(tcx)).as_slice());
188 pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
190 object_trait: &ty::TyTrait<'tcx>,
191 referent_ty: Ty<'tcx>)
192 -> ty::PolyTraitRef<'tcx>
194 // We can only make objects from sized types.
195 fcx.register_builtin_bound(
198 traits::ObligationCause::new(span, fcx.body_id, traits::ObjectSized));
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());
207 debug!("register_object_cast_obligations: referent_ty={} object_trait_ty={}",
208 referent_ty.repr(fcx.tcx()),
209 object_trait_ty.repr(fcx.tcx()));
211 let cause = ObligationCause::new(span,
213 traits::ObjectCastObligation(object_trait_ty));
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);
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(
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);
242 // Finally, check that there IS a projection predicate for every associated type.
243 check_object_type_binds_all_associated_types(fcx.tcx(),
250 fn check_object_type_binds_all_associated_types<'tcx>(tcx: &ty::ctxt<'tcx>,
252 object_trait: &ty::TyTrait<'tcx>)
254 let object_trait_ref =
255 object_trait.principal_trait_ref_with_self_ty(tcx, tcx.types.err);
257 let mut associated_types: FnvHashSet<(ast::DefId, ast::Name)> =
258 traits::supertraits(tcx, object_trait_ref.clone())
260 let trait_def = ty::lookup_trait_def(tcx, tr.def_id());
261 trait_def.associated_type_names
264 .map(move |associated_type_name| (tr.def_id(), associated_type_name))
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);
274 for (trait_def_id, name) in associated_types.into_iter() {
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());
283 pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) {
284 debug!("select_all_fcx_obligations_or_error");
286 select_fcx_obligations_where_possible(fcx);
287 fcx.default_type_parameters();
289 let mut fulfillment_cx = fcx.inh.fulfillment_cx.borrow_mut();
290 let r = fulfillment_cx.select_all_or_error(fcx.infcx(), fcx);
293 Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); }
297 /// Select as many obligations as we can at present.
298 pub fn select_fcx_obligations_where_possible(fcx: &FnCtxt)
301 fcx.inh.fulfillment_cx
303 .select_where_possible(fcx.infcx(), fcx)
306 Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); }
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
313 pub fn select_new_fcx_obligations(fcx: &FnCtxt) {
315 fcx.inh.fulfillment_cx
317 .select_new_obligations(fcx.infcx(), fcx)
320 Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); }