parent
05b6df49b8
commit
c07ae16de1
|
@ -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 */ }
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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| {
|
|
@ -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()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue