rustc_typeck: use FnCtxt in coercion, instead of mimicking a combiner.

This commit is contained in:
Eduard Burtescu 2015-01-17 22:44:42 +02:00
parent f9f3ba5920
commit 6a478bdfd2
3 changed files with 66 additions and 88 deletions

View file

@ -60,10 +60,11 @@
//! sort of a minor point so I've opted to leave it for later---after all
//! we may want to adjust precisely when coercions occur.
use middle::infer::{cres, Coercion, InferCtxt, TypeOrigin, TypeTrace};
use middle::infer::combine::{CombineFields, Combine};
use middle::infer::sub::Sub;
use check::FnCtxt;
use middle::infer::{self, cres, Coercion, TypeTrace};
use middle::infer::combine::Combine;
use middle::infer::sub::Sub;
use middle::subst;
use middle::ty::{AutoPtr, AutoDerefRef, AdjustDerefRef, AutoUnsize, AutoUnsafe};
use middle::ty::{mt};
@ -74,21 +75,31 @@ use util::ppaux::Repr;
use syntax::ast;
// Note: Coerce is not actually a combiner, in that it does not
// conform to the same interface, though it performs a similar
// function.
pub struct Coerce<'f, 'tcx: 'f>(pub CombineFields<'f, 'tcx>);
struct Coerce<'a, 'tcx: 'a> {
fcx: &'a FnCtxt<'a, 'tcx>,
trace: TypeTrace<'tcx>
}
type CoerceResult<'tcx> = cres<'tcx, Option<ty::AutoAdjustment<'tcx>>>;
impl<'f, 'tcx> Coerce<'f, 'tcx> {
pub fn get_ref<'a>(&'a self) -> &'a CombineFields<'f, 'tcx> {
let Coerce(ref v) = *self; v
}
fn tcx(&self) -> &ty::ctxt<'tcx> {
self.get_ref().infcx.tcx
self.fcx.tcx()
}
pub fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
fn subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
let sub = Sub(self.fcx.infcx().combine_fields(false, self.trace.clone()));
try!(sub.tys(a, b));
Ok(None) // No coercion required.
}
fn unpack_actual_value<T, F>(&self, a: Ty<'tcx>, f: F) -> T where
F: FnOnce(Ty<'tcx>) -> T,
{
f(self.fcx.infcx().shallow_resolve(a))
}
fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
debug!("Coerce.tys({} => {})",
a.repr(self.tcx()),
b.repr(self.tcx()));
@ -179,25 +190,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
})
}
pub fn subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
match Sub(self.get_ref().clone()).tys(a, b) {
Ok(_) => Ok(None), // No coercion required.
Err(ref e) => Err(*e)
}
}
pub fn unpack_actual_value<T, F>(&self, a: Ty<'tcx>, f: F) -> T where
F: FnOnce(Ty<'tcx>) -> T,
{
f(self.get_ref().infcx.shallow_resolve(a))
}
// ~T -> &T or &mut T -> &T (including where T = [U] or str)
pub fn coerce_borrowed_pointer(&self,
a: Ty<'tcx>,
b: Ty<'tcx>,
mutbl_b: ast::Mutability)
-> CoerceResult<'tcx> {
fn coerce_borrowed_pointer(&self,
a: Ty<'tcx>,
b: Ty<'tcx>,
mutbl_b: ast::Mutability)
-> CoerceResult<'tcx> {
debug!("coerce_borrowed_pointer(a={}, b={})",
a.repr(self.tcx()),
b.repr(self.tcx()));
@ -208,9 +206,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// to type check, we will construct the type that `&M*expr` would
// yield.
let sub = Sub(self.get_ref().clone());
let coercion = Coercion(self.get_ref().trace.clone());
let r_borrow = self.get_ref().infcx.next_region_var(coercion);
let coercion = Coercion(self.trace.clone());
let r_borrow = self.fcx.infcx().next_region_var(coercion);
let inner_ty = match a.sty {
ty::ty_uniq(_) => return Err(ty::terr_mismatch),
@ -220,15 +217,14 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
}
mt_a.ty
}
_ => {
return self.subtype(a, b);
}
_ => return self.subtype(a, b)
};
let a_borrowed = ty::mk_rptr(self.tcx(),
self.tcx().mk_region(r_borrow),
mt {ty: inner_ty, mutbl: mutbl_b});
try!(sub.tys(a_borrowed, b));
try!(self.subtype(a_borrowed, b));
if let Err(original_err) = self.subtype(a_borrowed, b) {
Ok(Some(AdjustDerefRef(AutoDerefRef {
autoderefs: 1,
@ -253,8 +249,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// we can't unify [T] with U. But to properly support DST, we need to allow
// that, at which point we will need extra checks on b here.
let sub = Sub(self.get_ref().clone());
match (&a.sty, &b.sty) {
(&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_rptr(_, mt_b)) => {
self.unpack_actual_value(t_a, |a| {
@ -264,12 +258,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
return Err(ty::terr_mutability);
}
let coercion = Coercion(self.get_ref().trace.clone());
let r_borrow = self.get_ref().infcx.next_region_var(coercion);
let coercion = Coercion(self.trace.clone());
let r_borrow = self.fcx.infcx().next_region_var(coercion);
let ty = ty::mk_rptr(self.tcx(),
self.tcx().mk_region(r_borrow),
ty::mt{ty: ty, mutbl: mt_b.mutbl});
try!(self.get_ref().infcx.try(|_| sub.tys(ty, b)));
try!(self.fcx.infcx().try(|_| self.subtype(ty, b)));
debug!("Success, coerced with AutoDerefRef(1, \
AutoPtr(AutoUnsize({:?})))", kind);
Ok(Some(AdjustDerefRef(AutoDerefRef {
@ -292,7 +286,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
let ty = ty::mk_ptr(self.tcx(),
ty::mt{ty: ty, mutbl: mt_b.mutbl});
try!(self.get_ref().infcx.try(|_| sub.tys(ty, b)));
try!(self.fcx.infcx().try(|_| self.subtype(ty, b)));
debug!("Success, coerced with AutoDerefRef(1, \
AutoPtr(AutoUnsize({:?})))", kind);
Ok(Some(AdjustDerefRef(AutoDerefRef {
@ -310,7 +304,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
match self.unsize_ty(t_a, a, t_b) {
Some((ty, kind)) => {
let ty = ty::mk_uniq(self.tcx(), ty);
try!(self.get_ref().infcx.try(|_| sub.tys(ty, b)));
try!(self.fcx.infcx().try(|_| self.subtype(ty, b)));
debug!("Success, coerced with AutoDerefRef(1, \
AutoUnsizeUniq({:?}))", kind);
Ok(Some(AdjustDerefRef(AutoDerefRef {
@ -362,12 +356,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
let ty_substs_b = substs_b.types.get_slice(subst::TypeSpace);
assert!(ty_substs_a.len() == ty_substs_b.len());
let sub = Sub(self.get_ref().clone());
let mut result = None;
let mut tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate();
for (i, (tp_a, tp_b)) in tps {
if self.get_ref().infcx.try(|_| sub.tys(*tp_a, *tp_b)).is_ok() {
if self.fcx.infcx().try(|_| self.subtype(*tp_a, *tp_b)).is_ok() {
continue;
}
match
@ -380,7 +372,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
let mut new_substs = substs_a.clone();
new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp;
let ty = ty::mk_struct(tcx, did_a, tcx.mk_substs(new_substs));
if self.get_ref().infcx.try(|_| sub.tys(ty, ty_b)).is_err() {
if self.fcx.infcx().try(|_| self.subtype(ty, ty_b)).is_err() {
debug!("Unsized type parameter '{}', but still \
could not match types {} and {}",
ppaux::ty_to_string(tcx, *tp_a),
@ -416,8 +408,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
a.repr(tcx),
b.repr(tcx), b_mutbl);
let coercion = Coercion(self.get_ref().trace.clone());
let r_a = self.get_ref().infcx.next_region_var(coercion);
let coercion = Coercion(self.trace.clone());
let r_a = self.fcx.infcx().next_region_var(coercion);
self.coerce_object(a, b, b_mutbl,
|tr| ty::mk_rptr(tcx, tcx.mk_region(r_a),
@ -501,11 +493,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
})
}
pub fn coerce_unsafe_ptr(&self,
a: Ty<'tcx>,
b: Ty<'tcx>,
mutbl_b: ast::Mutability)
-> CoerceResult<'tcx> {
fn coerce_unsafe_ptr(&self,
a: Ty<'tcx>,
b: Ty<'tcx>,
mutbl_b: ast::Mutability)
-> CoerceResult<'tcx> {
debug!("coerce_unsafe_ptr(a={}, b={})",
a.repr(self.tcx()),
b.repr(self.tcx()));
@ -534,21 +526,25 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
}
}
pub type CoerceResult<'tcx> = cres<'tcx, Option<ty::AutoAdjustment<'tcx>>>;
pub fn mk_coercety<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
a_is_expected: bool,
origin: TypeOrigin,
pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
expr: &ast::Expr,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> CoerceResult<'tcx> {
debug!("mk_coercety({} -> {})", a.repr(cx.tcx), b.repr(cx.tcx));
indent(|| {
cx.commit_if_ok(|| {
let trace = TypeTrace::types(origin, a_is_expected, a, b);
Coerce(cx.combine_fields(a_is_expected, trace)).tys(a, b)
-> cres<'tcx, ()> {
debug!("mk_assignty({} -> {})", a.repr(fcx.tcx()), b.repr(fcx.tcx()));
let adjustment = try!(indent(|| {
fcx.infcx().commit_if_ok(|| {
let origin = infer::ExprAssignable(expr.span);
Coerce {
fcx: fcx,
trace: infer::TypeTrace::types(origin, false, a, b)
}.coerce(a, b)
})
})
}));
if let Some(adjustment) = adjustment {
fcx.write_adjustment(expr.id, expr.span, adjustment);
}
Ok(())
}
fn can_coerce_mutbls(from_mutbl: ast::Mutability,

View file

@ -9,7 +9,7 @@
// except according to those terms.
use check::FnCtxt;
use check::{coercion, FnCtxt};
use middle::ty::{self, Ty};
use middle::infer;
@ -62,7 +62,7 @@ pub fn coerce<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span,
expr_ty.repr(fcx.ccx.tcx));
let expr_ty = fcx.resolve_type_vars_if_possible(expr_ty);
let expected = fcx.resolve_type_vars_if_possible(expected);
match fcx.mk_assignty(expr, expr_ty, expected) {
match coercion::mk_assignty(fcx, expr, expr_ty, expected) {
Ok(()) => { /* ok */ }
Err(ref err) => {
fcx.report_mismatched_types(sp, expected, expr_ty, err);

View file

@ -1726,24 +1726,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
infer::mk_subty(self.infcx(), a_is_expected, origin, sub, sup)
}
pub fn mk_assignty(&self,
expr: &ast::Expr,
sub: Ty<'tcx>,
sup: Ty<'tcx>)
-> Result<(), ty::type_err<'tcx>> {
match try!(coercion::mk_coercety(self.infcx(),
false,
infer::ExprAssignable(expr.span),
sub,
sup)) {
None => {}
Some(adjustment) => {
self.write_adjustment(expr.id, expr.span, adjustment);
}
}
Ok(())
}
pub fn mk_eqty(&self,
a_is_expected: bool,
origin: infer::TypeOrigin,