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::{self, ObjectSafetyViolation, MethodViolationCode};
13 use middle::traits::{Obligation, ObligationCause};
14 use middle::traits::report_fulfillment_errors;
15 use middle::ty::{self, 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 span_err!(fcx.tcx().sess, source_expr.span, E0188,
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 span_err!(fcx.ccx.tcx.sess, source_expr.span, E0189,
74 "can only cast a boxed pointer \
75 to a boxed object, not a {}",
76 ty::ty_sort_string(fcx.tcx(), source_ty));
79 (_, &ty::ty_rptr(..)) => {
80 span_err!(fcx.ccx.tcx.sess, source_expr.span, E0190,
81 "can only cast a &-pointer \
82 to an &-object, not a {}",
83 ty::ty_sort_string(fcx.tcx(), source_ty));
87 fcx.tcx().sess.span_bug(
89 "expected object type");
93 fn object_trait<'a, 'tcx>(t: &'a Ty<'tcx>) -> &'a ty::TyTrait<'tcx> {
95 ty::ty_trait(ref ty_trait) => &**ty_trait,
96 _ => panic!("expected ty_trait")
100 fn mutability_allowed(a_mutbl: ast::Mutability,
101 b_mutbl: ast::Mutability)
103 a_mutbl == b_mutbl ||
104 (a_mutbl == ast::MutMutable && b_mutbl == ast::MutImmutable)
107 fn push_cast_obligation<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
108 cast_expr: &ast::Expr,
109 object_trait: &ty::TyTrait<'tcx>,
110 referent_ty: Ty<'tcx>) {
111 let object_trait_ref =
112 register_object_cast_obligations(fcx,
117 // Finally record the object_trait_ref for use during trans
118 // (it would prob be better not to do this, but it's just kind
119 // of a pain to have to reconstruct it).
120 fcx.write_object_cast(cast_expr.id, object_trait_ref);
124 // Check that a trait is 'object-safe'. This should be checked whenever a trait object
125 // is created (by casting or coercion, etc.). A trait is object-safe if all its
126 // methods are object-safe. A trait method is object-safe if it does not take
127 // self by value, has no type parameters and does not use the `Self` type, except
129 pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>,
130 object_trait: &ty::TyTrait<'tcx>,
133 let object_trait_ref =
134 object_trait.principal_trait_ref_with_self_ty(tcx, tcx.types.err);
136 if traits::is_object_safe(tcx, object_trait_ref.clone()) {
140 span_err!(tcx.sess, span, E0038,
141 "cannot convert to a trait object because trait `{}` is not object-safe",
142 ty::item_path_str(tcx, object_trait_ref.def_id()));
144 let violations = traits::object_safety_violations(tcx, object_trait_ref.clone());
145 for violation in violations {
147 ObjectSafetyViolation::SizedSelf => {
150 "the trait cannot require that `Self : Sized`");
153 ObjectSafetyViolation::Method(method, MethodViolationCode::ByValueSelf) => {
156 &format!("method `{}` has a receiver type of `Self`, \
157 which cannot be used with a trait object",
158 method.name.user_string(tcx)));
161 ObjectSafetyViolation::Method(method, MethodViolationCode::StaticMethod) => {
164 &format!("method `{}` has no receiver",
165 method.name.user_string(tcx)));
168 ObjectSafetyViolation::Method(method, MethodViolationCode::ReferencesSelf) => {
171 &format!("method `{}` references the `Self` type \
172 in its arguments or return type",
173 method.name.user_string(tcx)));
176 ObjectSafetyViolation::Method(method, MethodViolationCode::Generic) => {
179 &format!("method `{}` has generic type parameters",
180 method.name.user_string(tcx)));
186 pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
188 object_trait: &ty::TyTrait<'tcx>,
189 referent_ty: Ty<'tcx>)
190 -> ty::PolyTraitRef<'tcx>
192 // We can only make objects from sized types.
193 fcx.register_builtin_bound(
196 traits::ObligationCause::new(span, fcx.body_id, traits::ObjectSized));
198 // This is just for better error reporting. Kinda goofy. The object type stuff
199 // needs some refactoring so there is a more convenient type to pass around.
200 let object_trait_ty =
201 ty::mk_trait(fcx.tcx(),
202 object_trait.principal.clone(),
203 object_trait.bounds.clone());
205 debug!("register_object_cast_obligations: referent_ty={} object_trait_ty={}",
206 referent_ty.repr(fcx.tcx()),
207 object_trait_ty.repr(fcx.tcx()));
209 let cause = ObligationCause::new(span,
211 traits::ObjectCastObligation(object_trait_ty));
213 // Create the obligation for casting from T to Trait.
214 let object_trait_ref =
215 object_trait.principal_trait_ref_with_self_ty(fcx.tcx(), referent_ty);
216 let object_obligation =
217 Obligation::new(cause.clone(), object_trait_ref.as_predicate());
218 fcx.register_predicate(object_obligation);
220 // Create additional obligations for all the various builtin
221 // bounds attached to the object cast. (In other words, if the
222 // object type is Foo+Send, this would create an obligation
223 // for the Send check.)
224 for builtin_bound in &object_trait.bounds.builtin_bounds {
225 fcx.register_builtin_bound(
231 // Create obligations for the projection predicates.
232 let projection_bounds =
233 object_trait.projection_bounds_with_self_ty(fcx.tcx(), referent_ty);
234 for projection_bound in &projection_bounds {
235 let projection_obligation =
236 Obligation::new(cause.clone(), projection_bound.as_predicate());
237 fcx.register_predicate(projection_obligation);
240 // Finally, check that there IS a projection predicate for every associated type.
241 check_object_type_binds_all_associated_types(fcx.tcx(),
248 fn check_object_type_binds_all_associated_types<'tcx>(tcx: &ty::ctxt<'tcx>,
250 object_trait: &ty::TyTrait<'tcx>)
252 let object_trait_ref =
253 object_trait.principal_trait_ref_with_self_ty(tcx, tcx.types.err);
255 let mut associated_types: FnvHashSet<(ast::DefId, ast::Name)> =
256 traits::supertraits(tcx, object_trait_ref.clone())
258 let trait_def = ty::lookup_trait_def(tcx, tr.def_id());
259 trait_def.associated_type_names
262 .map(move |associated_type_name| (tr.def_id(), associated_type_name))
266 for projection_bound in &object_trait.bounds.projection_bounds {
267 let pair = (projection_bound.0.projection_ty.trait_ref.def_id,
268 projection_bound.0.projection_ty.item_name);
269 associated_types.remove(&pair);
272 for (trait_def_id, name) in associated_types {
273 span_err!(tcx.sess, span, E0191,
274 "the value of the associated type `{}` (from the trait `{}`) must be specified",
275 name.user_string(tcx),
276 ty::item_path_str(tcx, trait_def_id));
280 pub fn select_all_fcx_obligations_and_apply_defaults(fcx: &FnCtxt) {
281 debug!("select_all_fcx_obligations_and_apply_defaults");
283 select_fcx_obligations_where_possible(fcx);
284 fcx.default_type_parameters();
285 select_fcx_obligations_where_possible(fcx);
288 pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) {
289 debug!("select_all_fcx_obligations_or_error");
291 // upvar inference should have ensured that all deferrred call
292 // resolutions are handled by now.
293 assert!(fcx.inh.deferred_call_resolutions.borrow().is_empty());
295 select_all_fcx_obligations_and_apply_defaults(fcx);
296 let mut fulfillment_cx = fcx.inh.fulfillment_cx.borrow_mut();
297 let r = fulfillment_cx.select_all_or_error(fcx.infcx(), fcx);
300 Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); }
304 /// Select as many obligations as we can at present.
305 pub fn select_fcx_obligations_where_possible(fcx: &FnCtxt)
308 fcx.inh.fulfillment_cx
310 .select_where_possible(fcx.infcx(), fcx)
313 Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); }
317 /// Try to select any fcx obligation that we haven't tried yet, in an effort to improve inference.
318 /// You could just call `select_fcx_obligations_where_possible` except that it leads to repeated
320 pub fn select_new_fcx_obligations(fcx: &FnCtxt) {
322 fcx.inh.fulfillment_cx
324 .select_new_obligations(fcx.infcx(), fcx)
327 Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); }