rename assign to coerce, remove some bad copies

r=brson
This commit is contained in:
Niko Matsakis 2013-01-22 11:06:20 -08:00
parent 05b6df49b8
commit c07ae16de1
4 changed files with 78 additions and 84 deletions

View File

@ -49,8 +49,8 @@ fn eqtype(fcx: @fn_ctxt, sp: span, expected: ty::t, actual: ty::t) {
}
}
// Checks that the type `actual` can be assigned to `expected`.
fn assign(fcx: @fn_ctxt, sp: span, expected: ty::t, expr: @ast::expr) {
// Checks that the type `actual` can be coerced to `expected`.
fn coerce(fcx: @fn_ctxt, sp: span, expected: ty::t, expr: @ast::expr) {
let expr_ty = fcx.expr_ty(expr);
match fcx.mk_assignty(expr, expr_ty, expected) {
result::Ok(()) => { /* ok */ }

View File

@ -812,7 +812,7 @@ impl @fn_ctxt {
fn mk_assignty(expr: @ast::expr, sub: ty::t, sup: ty::t)
-> Result<(), ty::type_err>
{
match infer::mk_assignty(self.infcx(), false, expr.span, sub, sup) {
match infer::mk_coercety(self.infcx(), false, expr.span, sub, sup) {
Ok(None) => result::Ok(()),
Err(ref e) => result::Err((*e)),
Ok(Some(adjustment)) => {
@ -823,7 +823,7 @@ impl @fn_ctxt {
}
fn can_mk_assignty(sub: ty::t, sup: ty::t) -> Result<(), ty::type_err> {
infer::can_mk_assignty(self.infcx(), sub, sup)
infer::can_mk_coercety(self.infcx(), sub, sup)
}
fn mk_eqty(a_is_expected: bool, span: span,
@ -986,12 +986,12 @@ fn check_expr_has_type(
}
}
fn check_expr_assignable_to_type(
fn check_expr_coercable_to_type(
fcx: @fn_ctxt, expr: @ast::expr,
expected: ty::t) -> bool
{
do check_expr_with_unifier(fcx, expr, Some(expected)) {
demand::assign(fcx, expr.span, expected, expr)
demand::coerce(fcx, expr.span, expected, expr)
}
}
@ -1225,7 +1225,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
}
// mismatch error happens in here
bot |= check_expr_assignable_to_type(
bot |= check_expr_coercable_to_type(
fcx, *arg, formal_ty);
}
@ -1243,7 +1243,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
-> bool {
let mut bot = check_expr(fcx, lhs);
let lhs_type = fcx.expr_ty(lhs);
bot |= check_expr_assignable_to_type(fcx, rhs, lhs_type);
bot |= check_expr_has_type(fcx, rhs, lhs_type);
fcx.write_ty(id, ty::mk_nil(fcx.ccx.tcx));
return bot;
}
@ -1739,7 +1739,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
ty::lookup_field_type(
tcx, class_id, field_id, substitutions);
bot |=
check_expr_assignable_to_type(
check_expr_coercable_to_type(
fcx,
field.node.expr,
expected_field_type);
@ -2552,7 +2552,7 @@ fn require_integral(fcx: @fn_ctxt, sp: span, t: ty::t) {
fn check_decl_initializer(fcx: @fn_ctxt, nid: ast::node_id,
init: @ast::expr) -> bool {
let lty = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, init.span, nid));
return check_expr_assignable_to_type(fcx, init, lty);
return check_expr_coercable_to_type(fcx, init, lty);
}
fn check_decl_local(fcx: @fn_ctxt, local: @ast::local) -> bool {

View File

@ -79,30 +79,23 @@ fn to_ares<T>(+c: cres<T>) -> ares {
}
}
// Note: Assign is not actually a combiner, in that it does not
// Note: Coerce is not actually a combiner, in that it does not
// conform to the same interface, though it performs a similar
// function.
enum Assign = CombineFields;
pub enum Coerce = CombineFields;
impl Assign {
fn tys(a: ty::t, b: ty::t) -> ares {
debug!("Assign.tys(%s => %s)",
impl Coerce {
fn tys(&self, a: ty::t, b: ty::t) -> ares {
debug!("Coerce.tys(%s => %s)",
a.inf_str(self.infcx),
b.inf_str(self.infcx));
let _r = indenter();
debug!("Assign.tys: copying first type");
let copy_a = copy ty::get(a).sty;
debug!("Assign.tys: copying second type");
let copy_b = copy ty::get(b).sty;
debug!("Assign.tys: performing match");
let r = match (copy_a, copy_b) {
(ty::ty_bot, _) => {
let _indent = indenter();
let r = match (&ty::get(a).sty, &ty::get(b).sty) {
(&ty::ty_bot, _) => {
Ok(None)
}
(ty::ty_infer(TyVar(a_id)), ty::ty_infer(TyVar(b_id))) => {
(&ty::ty_infer(TyVar(a_id)), &ty::ty_infer(TyVar(b_id))) => {
let nde_a = self.infcx.get(a_id);
let nde_b = self.infcx.get(b_id);
let a_bounds = nde_a.possible_types;
@ -110,42 +103,45 @@ impl Assign {
let a_bnd = option::or(a_bounds.ub, a_bounds.lb);
let b_bnd = option::or(b_bounds.lb, b_bounds.ub);
self.assign_tys_or_sub(a, b, a_bnd, b_bnd)
self.coerce_tys_or_sub(a, b, a_bnd, b_bnd)
}
(ty::ty_infer(TyVar(a_id)), _) => {
(&ty::ty_infer(TyVar(a_id)), _) => {
let nde_a = self.infcx.get(a_id);
let a_bounds = nde_a.possible_types;
let a_bnd = option::or(a_bounds.ub, a_bounds.lb);
self.assign_tys_or_sub(a, b, a_bnd, Some(b))
self.coerce_tys_or_sub(a, b, a_bnd, Some(b))
}
(_, ty::ty_infer(TyVar(b_id))) => {
(_, &ty::ty_infer(TyVar(b_id))) => {
let nde_b = self.infcx.get(b_id);
let b_bounds = nde_b.possible_types;
let b_bnd = option::or(b_bounds.lb, b_bounds.ub);
self.assign_tys_or_sub(a, b, Some(a), b_bnd)
self.coerce_tys_or_sub(a, b, Some(a), b_bnd)
}
(_, _) => {
self.assign_tys_or_sub(a, b, Some(a), Some(b))
self.coerce_tys_or_sub(a, b, Some(a), Some(b))
}
};
debug!("Assign.tys end");
debug!("Coerce.tys end");
move r
}
}
priv impl Assign {
fn assign_tys_or_sub(
a: ty::t, b: ty::t,
+a_bnd: Option<ty::t>, +b_bnd: Option<ty::t>) -> ares {
debug!("Assign.assign_tys_or_sub(%s => %s, %s => %s)",
impl Coerce {
fn coerce_tys_or_sub(
&self,
+a: ty::t,
+b: ty::t,
+a_bnd: Option<ty::t>,
+b_bnd: Option<ty::t>) -> ares
{
debug!("Coerce.coerce_tys_or_sub(%s => %s, %s => %s)",
a.inf_str(self.infcx), b.inf_str(self.infcx),
a_bnd.inf_str(self.infcx), b_bnd.inf_str(self.infcx));
let _r = indenter();
@ -167,59 +163,58 @@ priv impl Assign {
match (a_bnd, b_bnd) {
(Some(a_bnd), Some(b_bnd)) => {
match (/*bad*/copy ty::get(a_bnd).sty,
/*bad*/copy ty::get(b_bnd).sty) {
match (&ty::get(a_bnd).sty, &ty::get(b_bnd).sty) {
// check for a case where a non-region pointer (@, ~) is
// being assigned to a region pointer:
(ty::ty_box(_), ty::ty_rptr(r_b, mt_b)) => {
// being coerceed to a region pointer:
(&ty::ty_box(_), &ty::ty_rptr(r_b, mt_b)) => {
let nr_b = ty::mk_box(self.infcx.tcx,
ty::mt {ty: mt_b.ty,
mutbl: m_const});
self.try_assign(1, ty::AutoPtr,
self.try_coerce(1, ty::AutoPtr,
a, nr_b,
mt_b.mutbl, r_b)
}
(ty::ty_uniq(_), ty::ty_rptr(r_b, mt_b)) => {
(&ty::ty_uniq(_), &ty::ty_rptr(r_b, mt_b)) => {
let nr_b = ty::mk_uniq(self.infcx.tcx,
ty::mt {ty: mt_b.ty,
mutbl: m_const});
self.try_assign(1, ty::AutoPtr,
self.try_coerce(1, ty::AutoPtr,
a, nr_b,
mt_b.mutbl, r_b)
}
(ty::ty_estr(vs_a),
ty::ty_estr(ty::vstore_slice(r_b)))
(&ty::ty_estr(vs_a),
&ty::ty_estr(ty::vstore_slice(r_b)))
if is_borrowable(vs_a) => {
let nr_b = ty::mk_estr(self.infcx.tcx, vs_a);
self.try_assign(0, ty::AutoBorrowVec,
self.try_coerce(0, ty::AutoBorrowVec,
a, nr_b,
m_imm, r_b)
}
(ty::ty_evec(_, vs_a),
ty::ty_evec(mt_b, ty::vstore_slice(r_b)))
(&ty::ty_evec(_, vs_a),
&ty::ty_evec(mt_b, ty::vstore_slice(r_b)))
if is_borrowable(vs_a) => {
let nr_b = ty::mk_evec(self.infcx.tcx,
ty::mt {ty: mt_b.ty,
mutbl: m_const},
vs_a);
self.try_assign(0, ty::AutoBorrowVec,
self.try_coerce(0, ty::AutoBorrowVec,
a, nr_b,
mt_b.mutbl, r_b)
}
(ty::ty_fn(ref a_f), ty::ty_fn(ref b_f))
(&ty::ty_fn(ref a_f), &ty::ty_fn(ref b_f))
if borrowable_protos(a_f.meta.proto, b_f.meta.proto) => {
let nr_b = ty::mk_fn(self.infcx.tcx, ty::FnTyBase {
meta: ty::FnMeta {proto: a_f.meta.proto,
..b_f.meta},
sig: copy b_f.sig
});
self.try_assign(0, ty::AutoBorrowFn,
self.try_coerce(0, ty::AutoBorrowFn,
a, nr_b, m_imm, b_f.meta.region)
}
(ty::ty_fn(ref a_f), ty::ty_fn(ref b_f))
(&ty::ty_fn(ref a_f), &ty::ty_fn(ref b_f))
if a_f.meta.proto == ast::ProtoBare => {
let b1_f = ty::FnTyBase {
meta: ty::FnMeta {proto: ast::ProtoBare,
@ -229,49 +224,50 @@ priv impl Assign {
// Eventually we will need to add some sort of
// adjustment here so that trans can add an
// extra NULL env pointer:
to_ares(Sub(*self).fns(a_f, &b1_f))
to_ares(Sub(**self).fns(a_f, &b1_f))
}
// check for &T being assigned to *T:
(ty::ty_rptr(_, ref a_t), ty::ty_ptr(ref b_t)) => {
to_ares(Sub(*self).mts(*a_t, *b_t))
// check for &T being coerced to *T:
(&ty::ty_rptr(_, ref a_t), &ty::ty_ptr(ref b_t)) => {
to_ares(Sub(**self).mts(*a_t, *b_t))
}
// otherwise, assignment follows normal subtype rules:
// otherwise, coercement follows normal subtype rules:
_ => {
to_ares(Sub(*self).tys(a, b))
to_ares(Sub(**self).tys(a, b))
}
}
}
_ => {
// if insufficient bounds were available, just follow
// normal subtype rules:
to_ares(Sub(*self).tys(a, b))
to_ares(Sub(**self).tys(a, b))
}
}
}
/// Given an assignment from a type like `@a` to `&r_b/m nr_b`,
/// Given an coercement from a type like `@a` to `&r_b/m nr_b`,
/// this function checks that `a <: nr_b`. In that case, the
/// assignment is permitted, so it constructs a fresh region
/// variable `r_a >= r_b` and returns a corresponding assignment
/// coercement is permitted, so it constructs a fresh region
/// variable `r_a >= r_b` and returns a corresponding coercement
/// record. See the discussion at the top of this file for more
/// details.
fn try_assign(autoderefs: uint,
fn try_coerce(&self,
autoderefs: uint,
kind: ty::AutoRefKind,
a: ty::t,
nr_b: ty::t,
m: ast::mutability,
r_b: ty::Region) -> ares {
debug!("try_assign(a=%s, nr_b=%s, m=%?, r_b=%s)",
r_b: ty::Region) -> ares
{
debug!("try_coerce(a=%s, nr_b=%s, m=%?, r_b=%s)",
a.inf_str(self.infcx),
nr_b.inf_str(self.infcx),
m,
r_b.inf_str(self.infcx));
do indent {
let sub = Sub(*self);
let sub = Sub(**self);
do sub.tys(a, nr_b).chain |_t| {
let r_a = self.infcx.next_region_var_nb(self.span);
do sub.contraregions(r_a, r_b).chain |_r| {

View File

@ -217,11 +217,11 @@ when possible but otherwise merge the variables" strategy. In other
words, `GLB(A, B)` where `A` and `B` are variables will often result
in `A` and `B` being merged and the result being `A`.
## Type assignment
## Type coercion
We have a notion of assignability which differs somewhat from
subtyping; in particular it may cause region borrowing to occur. See
the big comment later in this file on Type Assignment for specifics.
the big comment later in this file on Type Coercion for specifics.
### In conclusion
@ -254,7 +254,7 @@ use middle::ty::{ty_int, ty_uint, get, terr_fn, TyVar, IntVar, FloatVar};
use middle::ty::IntVarValue;
use middle::ty;
use middle::typeck::check::regionmanip::{replace_bound_regions_in_fn_sig};
use middle::typeck::infer::assignment::Assign;
use middle::typeck::infer::coercion::Coerce;
use middle::typeck::infer::combine::{CombineFields, eq_tys};
use middle::typeck::infer::glb::Glb;
use middle::typeck::infer::lub::Lub;
@ -293,17 +293,15 @@ export new_infer_ctxt;
export mk_subty, can_mk_subty;
export mk_subr;
export mk_eqty;
export mk_assignty, can_mk_assignty;
export mk_coercety, can_mk_coercety;
export resolve_nested_tvar, resolve_rvar, resolve_ivar, resolve_all;
export force_tvar, force_rvar, force_ivar, force_all;
export resolve_and_force_all_but_regions, not_regions;
export resolve_type, resolve_region;
export resolve_borrowings;
export cres, fres, fixup_err, fixup_err_to_str;
export assignment;
export root, to_str;
export int_ty_set_all;
export assignment;
export combine;
export glb;
export integral;
@ -312,6 +310,7 @@ export lub;
export region_inference;
export resolve;
export sub;
export coercion;
export to_str;
export unify;
export uok;
@ -323,8 +322,7 @@ export infer_ctxt;
export fixup_err;
export IntVarValue, IntType, UintType;
#[legacy_exports]
mod assignment;
mod coercion;
#[legacy_exports]
mod combine;
#[legacy_exports]
@ -458,22 +456,22 @@ fn mk_eqty(cx: @InferCtxt, a_is_expected: bool, span: span,
}.to_ures()
}
fn mk_assignty(cx: @InferCtxt, a_is_expected: bool, span: span,
fn mk_coercety(cx: @InferCtxt, a_is_expected: bool, span: span,
a: ty::t, b: ty::t) -> ares {
debug!("mk_assignty(%s -> %s)", a.inf_str(cx), b.inf_str(cx));
debug!("mk_coercety(%s -> %s)", a.inf_str(cx), b.inf_str(cx));
do indent {
do cx.commit {
Assign(cx.combine_fields(a_is_expected, span)).tys(a, b)
Coerce(cx.combine_fields(a_is_expected, span)).tys(a, b)
}
}
}
fn can_mk_assignty(cx: @InferCtxt, a: ty::t, b: ty::t) -> ures {
debug!("can_mk_assignty(%s -> %s)", a.inf_str(cx), b.inf_str(cx));
fn can_mk_coercety(cx: @InferCtxt, a: ty::t, b: ty::t) -> ures {
debug!("can_mk_coercety(%s -> %s)", a.inf_str(cx), b.inf_str(cx));
do indent {
do cx.probe {
let span = ast_util::dummy_sp();
Assign(cx.combine_fields(true, span)).tys(a, b)
Coerce(cx.combine_fields(true, span)).tys(a, b)
}
}.to_ures()
}