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`. // Checks that the type `actual` can be coerced to `expected`.
fn assign(fcx: @fn_ctxt, sp: span, expected: ty::t, expr: @ast::expr) { fn coerce(fcx: @fn_ctxt, sp: span, expected: ty::t, expr: @ast::expr) {
let expr_ty = fcx.expr_ty(expr); let expr_ty = fcx.expr_ty(expr);
match fcx.mk_assignty(expr, expr_ty, expected) { match fcx.mk_assignty(expr, expr_ty, expected) {
result::Ok(()) => { /* ok */ } result::Ok(()) => { /* ok */ }

View File

@ -812,7 +812,7 @@ impl @fn_ctxt {
fn mk_assignty(expr: @ast::expr, sub: ty::t, sup: ty::t) fn mk_assignty(expr: @ast::expr, sub: ty::t, sup: ty::t)
-> Result<(), ty::type_err> -> 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(()), Ok(None) => result::Ok(()),
Err(ref e) => result::Err((*e)), Err(ref e) => result::Err((*e)),
Ok(Some(adjustment)) => { Ok(Some(adjustment)) => {
@ -823,7 +823,7 @@ impl @fn_ctxt {
} }
fn can_mk_assignty(sub: ty::t, sup: ty::t) -> Result<(), ty::type_err> { 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, 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, fcx: @fn_ctxt, expr: @ast::expr,
expected: ty::t) -> bool expected: ty::t) -> bool
{ {
do check_expr_with_unifier(fcx, expr, Some(expected)) { 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 // mismatch error happens in here
bot |= check_expr_assignable_to_type( bot |= check_expr_coercable_to_type(
fcx, *arg, formal_ty); fcx, *arg, formal_ty);
} }
@ -1243,7 +1243,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
-> bool { -> bool {
let mut bot = check_expr(fcx, lhs); let mut bot = check_expr(fcx, lhs);
let lhs_type = fcx.expr_ty(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)); fcx.write_ty(id, ty::mk_nil(fcx.ccx.tcx));
return bot; return bot;
} }
@ -1739,7 +1739,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
ty::lookup_field_type( ty::lookup_field_type(
tcx, class_id, field_id, substitutions); tcx, class_id, field_id, substitutions);
bot |= bot |=
check_expr_assignable_to_type( check_expr_coercable_to_type(
fcx, fcx,
field.node.expr, field.node.expr,
expected_field_type); 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, fn check_decl_initializer(fcx: @fn_ctxt, nid: ast::node_id,
init: @ast::expr) -> bool { init: @ast::expr) -> bool {
let lty = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, init.span, nid)); 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 { 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 // conform to the same interface, though it performs a similar
// function. // function.
enum Assign = CombineFields; pub enum Coerce = CombineFields;
impl Assign { impl Coerce {
fn tys(a: ty::t, b: ty::t) -> ares { fn tys(&self, a: ty::t, b: ty::t) -> ares {
debug!("Assign.tys(%s => %s)", debug!("Coerce.tys(%s => %s)",
a.inf_str(self.infcx), a.inf_str(self.infcx),
b.inf_str(self.infcx)); b.inf_str(self.infcx));
let _r = indenter(); let _indent = indenter();
let r = match (&ty::get(a).sty, &ty::get(b).sty) {
debug!("Assign.tys: copying first type"); (&ty::ty_bot, _) => {
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, _) => {
Ok(None) 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_a = self.infcx.get(a_id);
let nde_b = self.infcx.get(b_id); let nde_b = self.infcx.get(b_id);
let a_bounds = nde_a.possible_types; 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 a_bnd = option::or(a_bounds.ub, a_bounds.lb);
let b_bnd = option::or(b_bounds.lb, b_bounds.ub); 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 nde_a = self.infcx.get(a_id);
let a_bounds = nde_a.possible_types; let a_bounds = nde_a.possible_types;
let a_bnd = option::or(a_bounds.ub, a_bounds.lb); 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 nde_b = self.infcx.get(b_id);
let b_bounds = nde_b.possible_types; let b_bounds = nde_b.possible_types;
let b_bnd = option::or(b_bounds.lb, b_bounds.ub); 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 move r
} }
} }
priv impl Assign { impl Coerce {
fn assign_tys_or_sub( fn coerce_tys_or_sub(
a: ty::t, b: ty::t, &self,
+a_bnd: Option<ty::t>, +b_bnd: Option<ty::t>) -> ares { +a: ty::t,
+b: ty::t,
debug!("Assign.assign_tys_or_sub(%s => %s, %s => %s)", +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.inf_str(self.infcx), b.inf_str(self.infcx),
a_bnd.inf_str(self.infcx), b_bnd.inf_str(self.infcx)); a_bnd.inf_str(self.infcx), b_bnd.inf_str(self.infcx));
let _r = indenter(); let _r = indenter();
@ -167,59 +163,58 @@ priv impl Assign {
match (a_bnd, b_bnd) { match (a_bnd, b_bnd) {
(Some(a_bnd), Some(b_bnd)) => { (Some(a_bnd), Some(b_bnd)) => {
match (/*bad*/copy ty::get(a_bnd).sty, match (&ty::get(a_bnd).sty, &ty::get(b_bnd).sty) {
/*bad*/copy ty::get(b_bnd).sty) {
// check for a case where a non-region pointer (@, ~) is // check for a case where a non-region pointer (@, ~) is
// being assigned to a region pointer: // being coerceed to a region pointer:
(ty::ty_box(_), ty::ty_rptr(r_b, mt_b)) => { (&ty::ty_box(_), &ty::ty_rptr(r_b, mt_b)) => {
let nr_b = ty::mk_box(self.infcx.tcx, let nr_b = ty::mk_box(self.infcx.tcx,
ty::mt {ty: mt_b.ty, ty::mt {ty: mt_b.ty,
mutbl: m_const}); mutbl: m_const});
self.try_assign(1, ty::AutoPtr, self.try_coerce(1, ty::AutoPtr,
a, nr_b, a, nr_b,
mt_b.mutbl, r_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, let nr_b = ty::mk_uniq(self.infcx.tcx,
ty::mt {ty: mt_b.ty, ty::mt {ty: mt_b.ty,
mutbl: m_const}); mutbl: m_const});
self.try_assign(1, ty::AutoPtr, self.try_coerce(1, ty::AutoPtr,
a, nr_b, a, nr_b,
mt_b.mutbl, r_b) mt_b.mutbl, r_b)
} }
(ty::ty_estr(vs_a), (&ty::ty_estr(vs_a),
ty::ty_estr(ty::vstore_slice(r_b))) &ty::ty_estr(ty::vstore_slice(r_b)))
if is_borrowable(vs_a) => { if is_borrowable(vs_a) => {
let nr_b = ty::mk_estr(self.infcx.tcx, 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, a, nr_b,
m_imm, r_b) m_imm, r_b)
} }
(ty::ty_evec(_, vs_a), (&ty::ty_evec(_, vs_a),
ty::ty_evec(mt_b, ty::vstore_slice(r_b))) &ty::ty_evec(mt_b, ty::vstore_slice(r_b)))
if is_borrowable(vs_a) => { if is_borrowable(vs_a) => {
let nr_b = ty::mk_evec(self.infcx.tcx, let nr_b = ty::mk_evec(self.infcx.tcx,
ty::mt {ty: mt_b.ty, ty::mt {ty: mt_b.ty,
mutbl: m_const}, mutbl: m_const},
vs_a); vs_a);
self.try_assign(0, ty::AutoBorrowVec, self.try_coerce(0, ty::AutoBorrowVec,
a, nr_b, a, nr_b,
mt_b.mutbl, r_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) => { if borrowable_protos(a_f.meta.proto, b_f.meta.proto) => {
let nr_b = ty::mk_fn(self.infcx.tcx, ty::FnTyBase { let nr_b = ty::mk_fn(self.infcx.tcx, ty::FnTyBase {
meta: ty::FnMeta {proto: a_f.meta.proto, meta: ty::FnMeta {proto: a_f.meta.proto,
..b_f.meta}, ..b_f.meta},
sig: copy b_f.sig 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) 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 => { if a_f.meta.proto == ast::ProtoBare => {
let b1_f = ty::FnTyBase { let b1_f = ty::FnTyBase {
meta: ty::FnMeta {proto: ast::ProtoBare, meta: ty::FnMeta {proto: ast::ProtoBare,
@ -229,49 +224,50 @@ priv impl Assign {
// Eventually we will need to add some sort of // Eventually we will need to add some sort of
// adjustment here so that trans can add an // adjustment here so that trans can add an
// extra NULL env pointer: // 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: // check for &T being coerced to *T:
(ty::ty_rptr(_, ref a_t), ty::ty_ptr(ref b_t)) => { (&ty::ty_rptr(_, ref a_t), &ty::ty_ptr(ref b_t)) => {
to_ares(Sub(*self).mts(*a_t, *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 // if insufficient bounds were available, just follow
// normal subtype rules: // 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 /// this function checks that `a <: nr_b`. In that case, the
/// assignment is permitted, so it constructs a fresh region /// coercement is permitted, so it constructs a fresh region
/// variable `r_a >= r_b` and returns a corresponding assignment /// variable `r_a >= r_b` and returns a corresponding coercement
/// record. See the discussion at the top of this file for more /// record. See the discussion at the top of this file for more
/// details. /// details.
fn try_assign(autoderefs: uint, fn try_coerce(&self,
autoderefs: uint,
kind: ty::AutoRefKind, kind: ty::AutoRefKind,
a: ty::t, a: ty::t,
nr_b: ty::t, nr_b: ty::t,
m: ast::mutability, m: ast::mutability,
r_b: ty::Region) -> ares { r_b: ty::Region) -> ares
{
debug!("try_assign(a=%s, nr_b=%s, m=%?, r_b=%s)", debug!("try_coerce(a=%s, nr_b=%s, m=%?, r_b=%s)",
a.inf_str(self.infcx), a.inf_str(self.infcx),
nr_b.inf_str(self.infcx), nr_b.inf_str(self.infcx),
m, m,
r_b.inf_str(self.infcx)); r_b.inf_str(self.infcx));
do indent { do indent {
let sub = Sub(*self); let sub = Sub(**self);
do sub.tys(a, nr_b).chain |_t| { do sub.tys(a, nr_b).chain |_t| {
let r_a = self.infcx.next_region_var_nb(self.span); let r_a = self.infcx.next_region_var_nb(self.span);
do sub.contraregions(r_a, r_b).chain |_r| { 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 words, `GLB(A, B)` where `A` and `B` are variables will often result
in `A` and `B` being merged and the result being `A`. 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 We have a notion of assignability which differs somewhat from
subtyping; in particular it may cause region borrowing to occur. See 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 ### 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::IntVarValue;
use middle::ty; use middle::ty;
use middle::typeck::check::regionmanip::{replace_bound_regions_in_fn_sig}; 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::combine::{CombineFields, eq_tys};
use middle::typeck::infer::glb::Glb; use middle::typeck::infer::glb::Glb;
use middle::typeck::infer::lub::Lub; use middle::typeck::infer::lub::Lub;
@ -293,17 +293,15 @@ export new_infer_ctxt;
export mk_subty, can_mk_subty; export mk_subty, can_mk_subty;
export mk_subr; export mk_subr;
export mk_eqty; 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 resolve_nested_tvar, resolve_rvar, resolve_ivar, resolve_all;
export force_tvar, force_rvar, force_ivar, force_all; export force_tvar, force_rvar, force_ivar, force_all;
export resolve_and_force_all_but_regions, not_regions; export resolve_and_force_all_but_regions, not_regions;
export resolve_type, resolve_region; export resolve_type, resolve_region;
export resolve_borrowings; export resolve_borrowings;
export cres, fres, fixup_err, fixup_err_to_str; export cres, fres, fixup_err, fixup_err_to_str;
export assignment;
export root, to_str; export root, to_str;
export int_ty_set_all; export int_ty_set_all;
export assignment;
export combine; export combine;
export glb; export glb;
export integral; export integral;
@ -312,6 +310,7 @@ export lub;
export region_inference; export region_inference;
export resolve; export resolve;
export sub; export sub;
export coercion;
export to_str; export to_str;
export unify; export unify;
export uok; export uok;
@ -323,8 +322,7 @@ export infer_ctxt;
export fixup_err; export fixup_err;
export IntVarValue, IntType, UintType; export IntVarValue, IntType, UintType;
#[legacy_exports] mod coercion;
mod assignment;
#[legacy_exports] #[legacy_exports]
mod combine; mod combine;
#[legacy_exports] #[legacy_exports]
@ -458,22 +456,22 @@ fn mk_eqty(cx: @InferCtxt, a_is_expected: bool, span: span,
}.to_ures() }.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 { 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 indent {
do cx.commit { 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 { fn can_mk_coercety(cx: @InferCtxt, a: ty::t, b: ty::t) -> ures {
debug!("can_mk_assignty(%s -> %s)", a.inf_str(cx), b.inf_str(cx)); debug!("can_mk_coercety(%s -> %s)", a.inf_str(cx), b.inf_str(cx));
do indent { do indent {
do cx.probe { do cx.probe {
let span = ast_util::dummy_sp(); 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() }.to_ures()
} }