Skip to content

Commit d9393c2

Browse files
committed
Given <expr> as Box<Trait>, infer that Box<_> is expected type for <expr>.
1 parent 0ba9e1f commit d9393c2

File tree

1 file changed

+47
-62
lines changed

1 file changed

+47
-62
lines changed

src/librustc_typeck/check/vtable.rs

+47-62
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99
// except according to those terms.
1010

1111
use check::{FnCtxt, structurally_resolved_type};
12+
use check::demand;
1213
use middle::traits::{self, ObjectSafetyViolation, MethodViolationCode};
1314
use middle::traits::{Obligation, ObligationCause};
1415
use middle::traits::report_fulfillment_errors;
1516
use middle::ty::{self, Ty, AsPredicate};
16-
use middle::infer;
1717
use syntax::ast;
1818
use syntax::codemap::Span;
1919
use util::nodemap::FnvHashSet;
@@ -24,71 +24,63 @@ pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
2424
source_expr: &ast::Expr,
2525
target_object_ty: Ty<'tcx>)
2626
{
27+
let tcx = fcx.tcx();
2728
debug!("check_object_cast(cast_expr={}, target_object_ty={})",
28-
cast_expr.repr(fcx.tcx()),
29-
target_object_ty.repr(fcx.tcx()));
29+
cast_expr.repr(tcx),
30+
target_object_ty.repr(tcx));
3031

3132
// Look up vtables for the type we're casting to,
3233
// passing in the source and target type. The source
3334
// must be a pointer type suitable to the object sigil,
3435
// 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-
span_err!(fcx.tcx().sess, source_expr.span, E0188,
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-
}
7136

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));
37+
// First, construct a fresh type that we can feed into `<expr>`
38+
// within `<expr> as <type>` to inform type inference (e.g. to
39+
// tell it that we are expecting a `Box<_>` or an `&_`).
40+
let fresh_ty = fcx.infcx().next_ty_var();
41+
let (object_trait_ty, source_expected_ty) = match target_object_ty.sty {
42+
ty::ty_uniq(object_trait_ty) => {
43+
(object_trait_ty, ty::mk_uniq(fcx.tcx(), fresh_ty))
7744
}
78-
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));
45+
ty::ty_rptr(target_region, ty::mt { ty: object_trait_ty,
46+
mutbl: target_mutbl }) => {
47+
(object_trait_ty,
48+
ty::mk_rptr(fcx.tcx(),
49+
target_region, ty::mt { ty: fresh_ty,
50+
mutbl: target_mutbl }))
8451
}
85-
8652
_ => {
87-
fcx.tcx().sess.span_bug(
88-
source_expr.span,
89-
"expected object type");
53+
fcx.tcx().sess.span_bug(source_expr.span, "expected object type");
9054
}
91-
}
55+
};
56+
57+
let source_ty = fcx.expr_ty(source_expr);
58+
debug!("check_object_cast pre unify source_ty={}", source_ty.repr(tcx));
59+
60+
// This ensures that the source_ty <: source_expected_ty, which
61+
// will ensure e.g. that &'a T <: &'b T when doing `&'a T as &'b Trait`
62+
//
63+
// FIXME (pnkfelix): do we need to use suptype_with_fn in order to
64+
// override the error message emitted when the types do not work
65+
// out in the manner desired?
66+
demand::suptype(fcx, source_expr.span, source_expected_ty, source_ty);
67+
68+
debug!("check_object_cast postunify source_ty={}", source_ty.repr(tcx));
69+
let source_ty = structurally_resolved_type(fcx, source_expr.span, source_ty);
70+
debug!("check_object_cast resolveto source_ty={}", source_ty.repr(tcx));
71+
72+
let object_trait = object_trait(&object_trait_ty);
73+
74+
let referent_ty = match source_ty.sty {
75+
ty::ty_uniq(ty) => ty,
76+
ty::ty_rptr(_, ty::mt { ty, mutbl: _ }) => ty,
77+
_ => fcx.tcx().sess.span_bug(source_expr.span,
78+
"expected appropriate reference type"),
79+
};
80+
81+
// Ensure that if Ptr<T> is cast to Ptr<Trait>, then T : Trait.
82+
push_cast_obligation(fcx, cast_expr, object_trait, referent_ty);
83+
check_object_safety(tcx, object_trait, source_expr.span);
9284

9385
fn object_trait<'a, 'tcx>(t: &'a Ty<'tcx>) -> &'a ty::TyTrait<'tcx> {
9486
match t.sty {
@@ -97,13 +89,6 @@ pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
9789
}
9890
}
9991

100-
fn mutability_allowed(a_mutbl: ast::Mutability,
101-
b_mutbl: ast::Mutability)
102-
-> bool {
103-
a_mutbl == b_mutbl ||
104-
(a_mutbl == ast::MutMutable && b_mutbl == ast::MutImmutable)
105-
}
106-
10792
fn push_cast_obligation<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
10893
cast_expr: &ast::Expr,
10994
object_trait: &ty::TyTrait<'tcx>,

0 commit comments

Comments
 (0)