1
Fork 0

Implement automatic overloaded dereference.

Closes #7141.
This commit is contained in:
Eduard Burtescu 2014-03-06 19:24:11 +02:00
parent cdc18b96d6
commit 20b4e159ed
33 changed files with 876 additions and 926 deletions

View file

@ -101,7 +101,7 @@ impl<T: Clone + Float> Cmplx<T> {
/// Convert a polar representation into a complex number.
#[inline]
pub fn from_polar(r: &T, theta: &T) -> Cmplx<T> {
Cmplx::new(r * theta.cos(), r * theta.sin())
Cmplx::new(*r * theta.cos(), *r * theta.sin())
}
}

View file

@ -21,7 +21,7 @@ use metadata::tydecode;
use metadata::tydecode::{DefIdSource, NominalType, TypeWithId, TypeParameter,
RegionParameter};
use metadata::tyencode;
use middle::typeck::{MethodCallee, MethodOrigin};
use middle::typeck::{MethodCall, MethodCallee, MethodOrigin};
use middle::{ty, typeck, moves};
use middle;
use util::ppaux::ty_to_str;
@ -1039,7 +1039,8 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
}
}
for &method in maps.method_map.borrow().get().find(&id).iter() {
let method_call = MethodCall::expr(id);
for &method in maps.method_map.borrow().get().find(&method_call).iter() {
ebml_w.tag(c::tag_table_method_map, |ebml_w| {
ebml_w.id(id);
ebml_w.tag(c::tag_table_val, |ebml_w| {
@ -1385,7 +1386,8 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext,
}
c::tag_table_method_map => {
let method = val_dsr.read_method_callee(xcx);
dcx.maps.method_map.borrow_mut().get().insert(id, method);
let method_call = MethodCall::expr(id);
dcx.maps.method_map.borrow_mut().get().insert(method_call, method);
}
c::tag_table_vtable_map => {
let vtable_res =

View file

@ -22,6 +22,7 @@ use mc = middle::mem_categorization;
use middle::borrowck::*;
use middle::moves;
use middle::ty;
use middle::typeck::MethodCall;
use std::vec_ng::Vec;
use syntax::ast;
use syntax::ast_util;
@ -838,11 +839,11 @@ fn check_loans_in_expr<'a>(this: &mut CheckLoanCtxt<'a>,
this.check_call(expr, None, expr.span, args.as_slice());
}
ast::ExprIndex(_, rval) | ast::ExprBinary(_, _, rval)
if method_map.get().contains_key(&expr.id) => {
if method_map.get().contains_key(&MethodCall::expr(expr.id)) => {
this.check_call(expr, None, expr.span, [rval]);
}
ast::ExprUnary(_, _) | ast::ExprIndex(_, _)
if method_map.get().contains_key(&expr.id) => {
if method_map.get().contains_key(&MethodCall::expr(expr.id)) => {
this.check_call(expr, None, expr.span, []);
}
ast::ExprInlineAsm(ref ia) => {

View file

@ -23,6 +23,7 @@ use middle::moves;
use middle::pat_util;
use middle::ty::{ty_region};
use middle::ty;
use middle::typeck::MethodCall;
use util::common::indenter;
use util::ppaux::{Repr};
@ -242,7 +243,7 @@ fn gather_loans_in_expr(this: &mut GatherLoanCtxt,
ast::ExprIndex(_, arg) |
ast::ExprBinary(_, _, arg)
if method_map.get().contains_key(&ex.id) => {
if method_map.get().contains_key(&MethodCall::expr(ex.id)) => {
// Arguments in method calls are always passed by ref.
//
// Currently these do not use adjustments, so we have to

View file

@ -556,7 +556,8 @@ impl BorrowckCtxt {
move_data::MoveExpr => {
let (expr_ty, expr_span) = match self.tcx.map.find(move.id) {
Some(ast_map::NodeExpr(expr)) => {
(ty::expr_ty_adjusted(self.tcx, expr), expr.span)
(ty::expr_ty_adjusted(self.tcx, expr,
self.method_map.borrow().get()), expr.span)
}
r => self.tcx.sess.bug(format!("MoveExpr({:?}) maps to {:?}, not Expr",
move.id, r))
@ -582,7 +583,8 @@ impl BorrowckCtxt {
move_data::Captured => {
let (expr_ty, expr_span) = match self.tcx.map.find(move.id) {
Some(ast_map::NodeExpr(expr)) => {
(ty::expr_ty_adjusted(self.tcx, expr), expr.span)
(ty::expr_ty_adjusted(self.tcx, expr,
self.method_map.borrow().get()), expr.span)
}
r => self.tcx.sess.bug(format!("Captured({:?}) maps to {:?}, not Expr",
move.id, r))
@ -922,8 +924,8 @@ impl mc::Typer for TcxTyper {
Ok(ty::node_id_to_type(self.tcx, id))
}
fn node_method_ty(&mut self, id: ast::NodeId) -> Option<ty::t> {
self.method_map.borrow().get().find(&id).map(|method| method.ty)
fn node_method_ty(&mut self, method_call: typeck::MethodCall) -> Option<ty::t> {
self.method_map.borrow().get().find(&method_call).map(|method| method.ty)
}
fn adjustment(&mut self, id: ast::NodeId) -> Option<@ty::AutoAdjustment> {
@ -932,7 +934,7 @@ impl mc::Typer for TcxTyper {
}
fn is_method_call(&mut self, id: ast::NodeId) -> bool {
self.method_map.borrow().get().contains_key(&id)
self.method_map.borrow().get().contains_key(&typeck::MethodCall::expr(id))
}
fn temporary_scope(&mut self, id: ast::NodeId) -> Option<ast::NodeId> {

View file

@ -523,7 +523,7 @@ impl CFGBuilder {
}
fn is_method_call(&self, expr: &ast::Expr) -> bool {
let method_map = self.method_map.borrow();
method_map.get().contains_key(&expr.id)
let method_call = typeck::MethodCall::expr(expr.id);
self.method_map.borrow().get().contains_key(&method_call)
}
}

View file

@ -117,8 +117,8 @@ pub fn check_expr(v: &mut CheckCrateVisitor,
}
ExprLit(lit) if ast_util::lit_is_str(lit) => {}
ExprBinary(..) | ExprUnary(..) => {
let method_map = method_map.borrow();
if method_map.get().contains_key(&e.id) {
let method_call = typeck::MethodCall::expr(e.id);
if method_map.borrow().get().contains_key(&method_call) {
sess.span_err(e.span, "user-defined operators are not \
allowed in constant expressions");
}

View file

@ -16,7 +16,7 @@ use middle::astencode;
use middle::ty;
use middle::typeck::astconv;
use middle;
use util::nodemap::{DefIdMap, NodeMap};
use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
use syntax::ast::*;
use syntax::parse::token::InternedString;
@ -136,7 +136,7 @@ pub fn lookup_variant_by_id(tcx: ty::ctxt,
}
let maps = astencode::Maps {
root_map: @RefCell::new(HashMap::new()),
method_map: @RefCell::new(NodeMap::new()),
method_map: @RefCell::new(FnvHashMap::new()),
vtable_map: @RefCell::new(NodeMap::new()),
capture_map: @RefCell::new(NodeMap::new())
};
@ -186,7 +186,7 @@ pub fn lookup_const_by_id(tcx: ty::ctxt, def_id: ast::DefId)
}
let maps = astencode::Maps {
root_map: @RefCell::new(HashMap::new()),
method_map: @RefCell::new(NodeMap::new()),
method_map: @RefCell::new(FnvHashMap::new()),
vtable_map: @RefCell::new(NodeMap::new()),
capture_map: @RefCell::new(NodeMap::new())
};

View file

@ -810,8 +810,8 @@ impl<'a, O:DataFlowOperator> PropagationContext<'a, O> {
}
fn is_method_call(&self, expr: &ast::Expr) -> bool {
let method_map = self.dfcx.method_map.borrow();
method_map.get().contains_key(&expr.id)
let method_call = typeck::MethodCall::expr(expr.id);
self.dfcx.method_map.borrow().get().contains_key(&method_call)
}
fn reset(&mut self, bits: &mut [uint]) {

View file

@ -92,9 +92,10 @@ impl MarkSymbolVisitor {
}
}
fn lookup_and_handle_method(&mut self, id: &ast::NodeId,
fn lookup_and_handle_method(&mut self, id: ast::NodeId,
span: codemap::Span) {
match self.method_map.borrow().get().find(id) {
let method_call = typeck::MethodCall::expr(id);
match self.method_map.borrow().get().find(&method_call) {
Some(method) => {
match method.origin {
typeck::MethodStatic(def_id) => {
@ -179,7 +180,7 @@ impl Visitor<()> for MarkSymbolVisitor {
fn visit_expr(&mut self, expr: &ast::Expr, _: ()) {
match expr.node {
ast::ExprMethodCall(..) => {
self.lookup_and_handle_method(&expr.id, expr.span);
self.lookup_and_handle_method(expr.id, expr.span);
}
_ => ()
}

View file

@ -12,7 +12,7 @@
/// `unsafe`.
use middle::ty;
use middle::typeck::MethodMap;
use middle::typeck::{MethodCall, MethodMap};
use util::ppaux;
use syntax::ast;
@ -138,7 +138,8 @@ impl Visitor<()> for EffectCheckVisitor {
fn visit_expr(&mut self, expr: &ast::Expr, _:()) {
match expr.node {
ast::ExprMethodCall(_, _, _) => {
let base_type = self.method_map.borrow().get().get(&expr.id).ty;
let method_call = MethodCall::expr(expr.id);
let base_type = self.method_map.borrow().get().get(&method_call).ty;
debug!("effect: method call case, base type is {}",
ppaux::ty_to_str(self.tcx, base_type));
if type_is_unsafe_function(base_type) {

View file

@ -267,7 +267,7 @@ pub fn check_expr(cx: &mut Context, e: &Expr) {
// Handle any kind bounds on type parameters
{
let method_map = cx.method_map.borrow();
let method = method_map.get().find(&e.id);
let method = method_map.get().find(&typeck::MethodCall::expr(e.id));
let node_type_substs = cx.tcx.node_type_substs.borrow();
let r = match method {
Some(method) => Some(&method.substs.tps),
@ -341,7 +341,8 @@ pub fn check_expr(cx: &mut Context, e: &Expr) {
match **adjustment {
ty::AutoObject(..) => {
let source_ty = ty::expr_ty(cx.tcx, e);
let target_ty = ty::expr_ty_adjusted(cx.tcx, e);
let target_ty = ty::expr_ty_adjusted(cx.tcx, e,
cx.method_map.borrow().get());
check_trait_cast(cx, source_ty, target_ty, e.span);
}
ty::AutoAddEnv(..) |

View file

@ -1491,7 +1491,8 @@ fn check_stability(cx: &Context, e: &ast::Expr) {
}
}
ast::ExprMethodCall(..) => {
match cx.method_map.borrow().get().find(&e.id) {
let method_call = typeck::MethodCall::expr(e.id);
match cx.method_map.borrow().get().find(&method_call) {
Some(method) => {
match method.origin {
typeck::MethodStatic(def_id) => {

View file

@ -63,6 +63,7 @@
#[allow(non_camel_case_types)];
use middle::ty;
use middle::typeck;
use util::ppaux::{ty_to_str, region_ptr_to_str, Repr};
use std::vec_ng::Vec;
@ -268,7 +269,7 @@ pub type McResult<T> = Result<T, ()>;
pub trait Typer {
fn tcx(&self) -> ty::ctxt;
fn node_ty(&mut self, id: ast::NodeId) -> McResult<ty::t>;
fn node_method_ty(&mut self, id: ast::NodeId) -> Option<ty::t>;
fn node_method_ty(&mut self, method_call: typeck::MethodCall) -> Option<ty::t>;
fn adjustment(&mut self, node_id: ast::NodeId) -> Option<@ty::AutoAdjustment>;
fn is_method_call(&mut self, id: ast::NodeId) -> bool;
fn temporary_scope(&mut self, rvalue_id: ast::NodeId) -> Option<ast::NodeId>;
@ -365,7 +366,8 @@ impl<TYPER:Typer> MemCategorizationContext<TYPER> {
fn expr_ty_adjusted(&mut self, expr: &ast::Expr) -> McResult<ty::t> {
let unadjusted_ty = if_ok!(self.expr_ty(expr));
let adjustment = self.adjustment(expr.id);
Ok(ty::adjust_ty(self.tcx(), expr.span, unadjusted_ty, adjustment))
Ok(ty::adjust_ty(self.tcx(), expr.span, expr.id, unadjusted_ty, adjustment,
|method_call| self.typer.node_method_ty(method_call)))
}
fn node_ty(&mut self, id: ast::NodeId) -> McResult<ty::t> {
@ -435,21 +437,11 @@ impl<TYPER:Typer> MemCategorizationContext<TYPER> {
let expr_ty = if_ok!(self.expr_ty(expr));
match expr.node {
ast::ExprUnary(ast::UnDeref, e_base) => {
let base_cmt = match self.typer.node_method_ty(expr.id) {
Some(method_ty) => {
let ref_ty = ty::ty_fn_ret(method_ty);
self.cat_rvalue_node(expr.id(), expr.span(), ref_ty)
}
None => if_ok!(self.cat_expr(e_base))
};
let base_cmt = if_ok!(self.cat_expr(e_base));
Ok(self.cat_deref(expr, base_cmt, 0))
}
ast::ExprField(base, f_name, _) => {
// Method calls are now a special syntactic form,
// so `a.b` should always be a field.
assert!(!self.typer.is_method_call(expr.id));
let base_cmt = if_ok!(self.cat_expr(base));
Ok(self.cat_field(expr, base_cmt, f_name, expr_ty))
}
@ -725,59 +717,64 @@ impl<TYPER:Typer> MemCategorizationContext<TYPER> {
// `()` (the empty tuple).
let opaque_ty = ty::mk_tup(self.tcx(), Vec::new());
return self.cat_deref_common(node, base_cmt, deref_cnt, opaque_ty);
self.cat_deref_common(node, base_cmt, deref_cnt, opaque_ty)
}
pub fn cat_deref<N:ast_node>(&mut self,
fn cat_deref<N:ast_node>(&mut self,
node: &N,
base_cmt: cmt,
deref_cnt: uint)
-> cmt {
let mt = match ty::deref(base_cmt.ty, true) {
Some(mt) => mt,
let method_call = typeck::MethodCall {
expr_id: node.id(),
autoderef: deref_cnt as u32
};
let method_ty = self.typer.node_method_ty(method_call);
debug!("cat_deref: method_call={:?} method_ty={}",
method_call, method_ty.map(|ty| ty.repr(self.tcx())));
let base_cmt = match method_ty {
Some(method_ty) => {
let ref_ty = ty::ty_fn_ret(method_ty);
self.cat_rvalue_node(node.id(), node.span(), ref_ty)
}
None => base_cmt
};
match ty::deref(base_cmt.ty, true) {
Some(mt) => self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty),
None => {
self.tcx().sess.span_bug(
node.span(),
format!("Explicit deref of non-derefable type: {}",
base_cmt.ty.repr(self.tcx())));
}
};
return self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty);
}
}
pub fn cat_deref_common<N:ast_node>(&mut self,
fn cat_deref_common<N:ast_node>(&mut self,
node: &N,
base_cmt: cmt,
deref_cnt: uint,
deref_ty: ty::t)
-> cmt {
match deref_kind(self.tcx(), base_cmt.ty) {
let (m, cat) = match deref_kind(self.tcx(), base_cmt.ty) {
deref_ptr(ptr) => {
// for unique ptrs, we inherit mutability from the
// owning reference.
let m = MutabilityCategory::from_pointer_kind(base_cmt.mutbl,
ptr);
@cmt_ {
id:node.id(),
span:node.span(),
cat:cat_deref(base_cmt, deref_cnt, ptr),
mutbl:m,
ty:deref_ty
(MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr),
cat_deref(base_cmt, deref_cnt, ptr))
}
}
deref_interior(interior) => {
let m = base_cmt.mutbl.inherit();
(base_cmt.mutbl.inherit(), cat_interior(base_cmt, interior))
}
};
@cmt_ {
id:node.id(),
span:node.span(),
cat:cat_interior(base_cmt, interior),
mutbl:m,
ty:deref_ty
}
}
id: node.id(),
span: node.span(),
cat: cat,
mutbl: m,
ty: deref_ty
}
}

View file

@ -130,7 +130,7 @@ and so on.
use middle::pat_util::{pat_bindings};
use middle::freevars;
use middle::ty;
use middle::typeck::MethodMap;
use middle::typeck::{MethodCall, MethodMap};
use util::ppaux;
use util::ppaux::Repr;
use util::common::indenter;
@ -281,12 +281,10 @@ impl VisitContext {
debug!("consume_expr(expr={})",
expr.repr(self.tcx));
let expr_ty = ty::expr_ty_adjusted(self.tcx, expr);
let expr_ty = ty::expr_ty_adjusted(self.tcx, expr,
self.method_map.borrow().get());
if ty::type_moves_by_default(self.tcx, expr_ty) {
{
let mut moves_map = self.move_maps.moves_map.borrow_mut();
moves_map.get().insert(expr.id);
}
self.move_maps.moves_map.borrow_mut().get().insert(expr.id);
self.use_expr(expr, Move);
} else {
self.use_expr(expr, Read);
@ -608,8 +606,8 @@ impl VisitContext {
receiver_expr: @Expr,
arg_exprs: &[@Expr])
-> bool {
let method_map = self.method_map.borrow();
if !method_map.get().contains_key(&expr.id) {
let method_call = MethodCall::expr(expr.id);
if !self.method_map.borrow().get().contains_key(&method_call) {
return false;
}

View file

@ -19,7 +19,7 @@ use metadata::csearch;
use middle::lint;
use middle::resolve;
use middle::ty;
use middle::typeck::{MethodMap, MethodOrigin, MethodParam};
use middle::typeck::{MethodCall, MethodMap, MethodOrigin, MethodParam};
use middle::typeck::{MethodStatic, MethodObject};
use util::nodemap::{NodeMap, NodeSet};
@ -772,28 +772,17 @@ impl<'a> Visitor<()> for PrivacyVisitor<'a> {
fn visit_expr(&mut self, expr: &ast::Expr, _: ()) {
match expr.node {
ast::ExprField(base, ident, _) => {
// Method calls are now a special syntactic form,
// so `a.b` should always be a field.
let method_map = self.method_map.borrow();
assert!(!method_map.get().contains_key(&expr.id));
// With type_autoderef, make sure we don't
// allow pointers to violate privacy
let t = ty::type_autoderef(ty::expr_ty(self.tcx, base));
match ty::get(t).sty {
match ty::get(ty::expr_ty_adjusted(self.tcx, base,
self.method_map.borrow().get())).sty {
ty::ty_struct(id, _) => {
self.check_field(expr.span, id, ident, None);
}
_ => {}
}
}
ast::ExprMethodCall(ident, _, ref args) => {
// see above
let t = ty::type_autoderef(ty::expr_ty(self.tcx,
*args.get(0)));
match ty::get(t).sty {
ty::ty_enum(_, _) | ty::ty_struct(_, _) => {
match self.method_map.borrow().get().find(&expr.id) {
ast::ExprMethodCall(ident, _, _) => {
let method_call = MethodCall::expr(expr.id);
match self.method_map.borrow().get().find(&method_call) {
None => {
self.tcx.sess.span_bug(expr.span,
"method call not in \
@ -805,9 +794,6 @@ impl<'a> Visitor<()> for PrivacyVisitor<'a> {
}
}
}
_ => {}
}
}
ast::ExprStruct(_, ref fields, _) => {
match ty::get(ty::expr_ty(self.tcx, expr)).sty {
ty::ty_struct(id, _) => {

View file

@ -149,24 +149,17 @@ impl Visitor<()> for MarkSymbolVisitor {
}
}
ast::ExprMethodCall(..) => {
match self.method_map.borrow().get().get(&expr.id).origin {
let method_call = typeck::MethodCall::expr(expr.id);
match self.method_map.borrow().get().get(&method_call).origin {
typeck::MethodStatic(def_id) => {
if is_local(def_id) {
if ReachableContext::
def_id_represents_local_inlined_item(
self.tcx,
def_id) {
{
let mut worklist = self.worklist
.borrow_mut();
worklist.get().push(def_id.node)
}
}
{
let mut reachable_symbols =
self.reachable_symbols.borrow_mut();
reachable_symbols.get().insert(def_id.node);
self.worklist.borrow_mut().get().push(def_id.node)
}
self.reachable_symbols.borrow_mut().get().insert(def_id.node);
}
}
_ => {}

View file

@ -50,10 +50,11 @@ pub fn trans_inline_asm<'a>(bcx: &'a Block<'a>, ia: &ast::InlineAsm)
let inputs = ia.inputs.map(|&(ref c, input)| {
constraints.push((*c).clone());
let in_datum = unpack_datum!(bcx, expr::trans(bcx, input));
unpack_result!(bcx, {
callee::trans_arg_expr(bcx,
callee::trans_arg_datum(bcx,
expr_ty(bcx, input),
input,
in_datum,
cleanup::CustomScope(temp_scope),
callee::DontAutorefArg)
})

View file

@ -44,6 +44,7 @@ use middle::ty;
use middle::subst::Subst;
use middle::typeck;
use middle::typeck::coherence::make_substs_for_receiver_types;
use middle::typeck::MethodCall;
use util::ppaux::Repr;
use middle::trans::type_::Type;
@ -120,7 +121,7 @@ fn trans<'a>(bcx: &'a Block<'a>, expr: &ast::Expr) -> Callee<'a> {
match def {
ast::DefFn(did, _) |
ast::DefStaticMethod(did, ast::FromImpl(_), _) => {
fn_callee(bcx, trans_fn_ref(bcx, did, ref_expr.id, false))
fn_callee(bcx, trans_fn_ref(bcx, did, ExprId(ref_expr.id)))
}
ast::DefStaticMethod(impl_did,
ast::FromTrait(trait_did),
@ -134,10 +135,10 @@ fn trans<'a>(bcx: &'a Block<'a>, expr: &ast::Expr) -> Callee<'a> {
assert!(ty::enum_variant_with_id(bcx.tcx(),
tid,
vid).args.len() > 0u);
fn_callee(bcx, trans_fn_ref(bcx, vid, ref_expr.id, false))
fn_callee(bcx, trans_fn_ref(bcx, vid, ExprId(ref_expr.id)))
}
ast::DefStruct(def_id) => {
fn_callee(bcx, trans_fn_ref(bcx, def_id, ref_expr.id, false))
fn_callee(bcx, trans_fn_ref(bcx, def_id, ExprId(ref_expr.id)))
}
ast::DefStatic(..) |
ast::DefArg(..) |
@ -160,9 +161,7 @@ fn trans<'a>(bcx: &'a Block<'a>, expr: &ast::Expr) -> Callee<'a> {
}
}
pub fn trans_fn_ref(bcx: &Block, def_id: ast::DefId,
ref_id: ast::NodeId, is_method: bool)
-> ValueRef {
pub fn trans_fn_ref(bcx: &Block, def_id: ast::DefId, node: ExprOrMethodCall) -> ValueRef {
/*!
*
* Translates a reference (with id `ref_id`) to the fn/method
@ -171,15 +170,18 @@ pub fn trans_fn_ref(bcx: &Block, def_id: ast::DefId,
let _icx = push_ctxt("trans_fn_ref");
let type_params = node_id_type_params(bcx, ref_id, is_method);
let vtables = node_vtables(bcx, ref_id);
debug!("trans_fn_ref(def_id={}, ref_id={:?}, type_params={}, vtables={})",
def_id.repr(bcx.tcx()), ref_id, type_params.repr(bcx.tcx()),
let type_params = node_id_type_params(bcx, node);
let vtables = match node {
ExprId(id) => node_vtables(bcx, id),
MethodCall(method_call) if method_call.autoderef == 0 => {
node_vtables(bcx, method_call.expr_id)
}
_ => None
};
debug!("trans_fn_ref(def_id={}, node={:?}, type_params={}, vtables={})",
def_id.repr(bcx.tcx()), node, type_params.repr(bcx.tcx()),
vtables.repr(bcx.tcx()));
trans_fn_ref_with_vtables(bcx,
def_id,
ref_id,
is_method,
trans_fn_ref_with_vtables(bcx, def_id, node,
type_params.as_slice(),
vtables)
}
@ -191,7 +193,7 @@ fn trans_fn_ref_with_vtables_to_callee<'a>(bcx: &'a Block<'a>,
vtables: Option<typeck::vtable_res>)
-> Callee<'a> {
Callee {bcx: bcx,
data: Fn(trans_fn_ref_with_vtables(bcx, def_id, ref_id, false,
data: Fn(trans_fn_ref_with_vtables(bcx, def_id, ExprId(ref_id),
type_params, vtables))}
}
@ -241,8 +243,7 @@ fn resolve_default_method_vtables(bcx: &Block,
pub fn trans_fn_ref_with_vtables(
bcx: &Block, //
def_id: ast::DefId, // def id of fn
ref_id: ast::NodeId, // node id of use of fn; may be zero if N/A
is_method: bool,
node: ExprOrMethodCall, // node id of use of fn; may be zero if N/A
type_params: &[ty::t], // values for fn's ty params
vtables: Option<typeck::vtable_res>) // vtables for the call
-> ValueRef {
@ -254,7 +255,7 @@ pub fn trans_fn_ref_with_vtables(
*
* - `bcx`: the current block where the reference to the fn occurs
* - `def_id`: def id of the fn or method item being referenced
* - `ref_id`: node id of the reference to the fn/method, if applicable.
* - `node`: node id of the reference to the fn/method, if applicable.
* This parameter may be zero; but, if so, the resulting value may not
* have the right type, so it must be cast before being used.
* - `type_params`: values for each of the fn/method's type parameters
@ -265,11 +266,11 @@ pub fn trans_fn_ref_with_vtables(
let ccx = bcx.ccx();
let tcx = ccx.tcx;
debug!("trans_fn_ref_with_vtables(bcx={}, def_id={}, ref_id={:?}, \
debug!("trans_fn_ref_with_vtables(bcx={}, def_id={}, node={:?}, \
type_params={}, vtables={})",
bcx.to_str(),
def_id.repr(bcx.tcx()),
ref_id,
node,
type_params.repr(bcx.tcx()),
vtables.repr(bcx.tcx()));
@ -380,19 +381,25 @@ pub fn trans_fn_ref_with_vtables(
// Should be either intra-crate or inlined.
assert_eq!(def_id.krate, ast::LOCAL_CRATE);
let ref_id = match node {
ExprId(id) if id != 0 => Some(id),
_ => None
};
let (val, must_cast) =
monomorphize::monomorphic_fn(ccx, def_id, &substs,
vtables, self_vtables,
Some(ref_id));
ref_id);
let mut val = val;
if must_cast && ref_id != 0 {
if must_cast && node != ExprId(0) {
// Monotype of the REFERENCE to the function (type params
// are subst'd)
let ref_ty = if is_method {
let t = bcx.ccx().maps.method_map.borrow().get().get(&ref_id).ty;
let ref_ty = match node {
ExprId(id) => node_id_type(bcx, id),
MethodCall(method_call) => {
let t = bcx.ccx().maps.method_map.borrow().get().get(&method_call).ty;
monomorphize_type(bcx, t)
} else {
node_id_type(bcx, ref_id)
}
};
val = PointerCast(
@ -472,13 +479,14 @@ pub fn trans_method_call<'a>(
-> &'a Block<'a> {
let _icx = push_ctxt("trans_method_call");
debug!("trans_method_call(call_ex={})", call_ex.repr(bcx.tcx()));
let method_ty = bcx.ccx().maps.method_map.borrow().get().get(&call_ex.id).ty;
let method_call = MethodCall::expr(call_ex.id);
let method_ty = bcx.ccx().maps.method_map.borrow().get().get(&method_call).ty;
trans_call_inner(
bcx,
Some(common::expr_info(call_ex)),
monomorphize_type(bcx, method_ty),
|cx, arg_cleanup_scope| {
meth::trans_method_callee(cx, call_ex.id, rcvr, arg_cleanup_scope)
meth::trans_method_callee(cx, method_call, Some(rcvr), arg_cleanup_scope)
},
args,
Some(dest)).bcx
@ -717,19 +725,16 @@ pub fn trans_call_inner<'a>(
assert!(dest.is_some());
let mut llargs = Vec::new();
bcx = trans_args(bcx, args, callee_ty, &mut llargs,
cleanup::CustomScope(arg_cleanup_scope), false);
fcx.pop_custom_cleanup_scope(arg_cleanup_scope);
let arg_tys = match args {
ArgExprs(a) => a.iter().map(|x| expr_ty(bcx, *x)).collect(),
_ => fail!("expected arg exprs.")
};
bcx = foreign::trans_native_call(bcx,
callee_ty,
llfn,
opt_llretslot.unwrap(),
llargs.as_slice(),
arg_tys);
bcx = trans_args(bcx, args, callee_ty, &mut llargs,
cleanup::CustomScope(arg_cleanup_scope), false);
fcx.pop_custom_cleanup_scope(arg_cleanup_scope);
bcx = foreign::trans_native_call(bcx, callee_ty,
llfn, opt_llretslot.unwrap(),
llargs.as_slice(), arg_tys);
}
// If the caller doesn't care about the result of this fn call,
@ -754,8 +759,7 @@ pub fn trans_call_inner<'a>(
pub enum CallArgs<'a> {
ArgExprs(&'a [@ast::Expr]),
// HACK used only by trans_overloaded_op.
ArgAutorefSecond(&'a ast::Expr, Option<&'a ast::Expr>),
ArgOverloadedOp(Datum<Expr>, Option<(Datum<Expr>, ast::NodeId)>),
ArgVals(&'a [ValueRef])
}
@ -778,40 +782,42 @@ fn trans_args<'a>(cx: &'a Block<'a>,
match args {
ArgExprs(arg_exprs) => {
let num_formal_args = arg_tys.len();
for (i, arg_expr) in arg_exprs.iter().enumerate() {
for (i, &arg_expr) in arg_exprs.iter().enumerate() {
if i == 0 && ignore_self {
continue;
}
let arg_ty = if i >= num_formal_args {
assert!(variadic);
expr_ty_adjusted(cx, *arg_expr)
expr_ty_adjusted(cx, arg_expr)
} else {
*arg_tys.get(i)
};
let arg_datum = unpack_datum!(bcx, expr::trans(bcx, arg_expr));
llargs.push(unpack_result!(bcx, {
trans_arg_expr(bcx, arg_ty, *arg_expr,
trans_arg_datum(bcx, arg_ty, arg_datum,
arg_cleanup_scope,
DontAutorefArg)
}));
}
}
ArgAutorefSecond(arg_expr, arg2) => {
ArgOverloadedOp(lhs, rhs) => {
assert!(!variadic);
llargs.push(unpack_result!(bcx, {
trans_arg_expr(bcx, *arg_tys.get(0), arg_expr,
trans_arg_datum(bcx, *arg_tys.get(0), lhs,
arg_cleanup_scope,
DontAutorefArg)
}));
match arg2 {
Some(arg2_expr) => {
match rhs {
Some((rhs, rhs_id)) => {
assert_eq!(arg_tys.len(), 2);
llargs.push(unpack_result!(bcx, {
trans_arg_expr(bcx, *arg_tys.get(1), arg2_expr,
trans_arg_datum(bcx, *arg_tys.get(1), rhs,
arg_cleanup_scope,
DoAutorefArg)
DoAutorefArg(rhs_id))
}));
}
None => assert_eq!(arg_tys.len(), 1)
@ -827,26 +833,23 @@ fn trans_args<'a>(cx: &'a Block<'a>,
pub enum AutorefArg {
DontAutorefArg,
DoAutorefArg
DoAutorefArg(ast::NodeId)
}
pub fn trans_arg_expr<'a>(
pub fn trans_arg_datum<'a>(
bcx: &'a Block<'a>,
formal_arg_ty: ty::t,
arg_expr: &ast::Expr,
arg_datum: Datum<Expr>,
arg_cleanup_scope: cleanup::ScopeId,
autoref_arg: AutorefArg)
-> Result<'a> {
let _icx = push_ctxt("trans_arg_expr");
let _icx = push_ctxt("trans_arg_datum");
let mut bcx = bcx;
let ccx = bcx.ccx();
debug!("trans_arg_expr(formal_arg_ty=({}), arg_expr={})",
formal_arg_ty.repr(bcx.tcx()),
arg_expr.repr(bcx.tcx()));
debug!("trans_arg_datum({})",
formal_arg_ty.repr(bcx.tcx()));
// translate the arg expr to a datum
let arg_datum = unpack_datum!(bcx, expr::trans(bcx, arg_expr));
let arg_datum_ty = arg_datum.ty;
debug!(" arg datum: {}", arg_datum.to_str(bcx.ccx()));
@ -864,11 +867,11 @@ pub fn trans_arg_expr<'a>(
} else {
// FIXME(#3548) use the adjustments table
match autoref_arg {
DoAutorefArg => {
DoAutorefArg(arg_id) => {
// We will pass argument by reference
// We want an lvalue, so that we can pass by reference and
let arg_datum = unpack_datum!(
bcx, arg_datum.to_lvalue_datum(bcx, "arg", arg_expr.id));
bcx, arg_datum.to_lvalue_datum(bcx, "arg", arg_id));
val = arg_datum.val;
}
DontAutorefArg => {
@ -898,6 +901,6 @@ pub fn trans_arg_expr<'a>(
}
}
debug!("--- trans_arg_expr passing {}", bcx.val_to_str(val));
return rslt(bcx, val);
debug!("--- trans_arg_datum passing {}", bcx.val_to_str(val));
rslt(bcx, val)
}

View file

@ -19,7 +19,7 @@ use middle::trans::base;
use middle::trans::build;
use middle::trans::callee;
use middle::trans::common;
use middle::trans::common::{Block, FunctionContext};
use middle::trans::common::{Block, FunctionContext, ExprId};
use middle::trans::glue;
use middle::trans::type_::Type;
use middle::ty;
@ -673,7 +673,7 @@ impl<'a> CleanupHelperMethods<'a> for FunctionContext<'a> {
// The exception handling personality function.
let def_id = common::langcall(pad_bcx, None, "", EhPersonalityLangItem);
let llpersonality = callee::trans_fn_ref(pad_bcx, def_id, 0, false);
let llpersonality = callee::trans_fn_ref(pad_bcx, def_id, ExprId(0));
// The only landing pad clause will be 'cleanup'
let llretval = build::LandingPad(pad_bcx, llretty, llpersonality, 1u);

View file

@ -805,22 +805,29 @@ pub fn expr_ty(bcx: &Block, ex: &ast::Expr) -> ty::t {
pub fn expr_ty_adjusted(bcx: &Block, ex: &ast::Expr) -> ty::t {
let tcx = bcx.tcx();
let t = ty::expr_ty_adjusted(tcx, ex);
let t = ty::expr_ty_adjusted(tcx, ex, bcx.ccx().maps.method_map.borrow().get());
monomorphize_type(bcx, t)
}
pub fn node_id_type_params(bcx: &Block, id: ast::NodeId, is_method: bool) -> Vec<ty::t> {
#[deriving(Eq)]
pub enum ExprOrMethodCall {
ExprId(ast::NodeId),
MethodCall(typeck::MethodCall)
}
pub fn node_id_type_params(bcx: &Block, node: ExprOrMethodCall) -> Vec<ty::t> {
let tcx = bcx.tcx();
let params = if is_method {
bcx.ccx().maps.method_map.borrow().get().get(&id).substs.tps.clone()
} else {
ty::node_id_to_type_params(tcx, id)
let params = match node {
ExprId(id) => ty::node_id_to_type_params(tcx, id),
MethodCall(method_call) => {
bcx.ccx().maps.method_map.borrow().get().get(&method_call).substs.tps.clone()
}
};
if !params.iter().all(|t| !ty::type_needs_infer(*t)) {
bcx.sess().bug(
format!("type parameters for node {} include inference types: {}",
id, params.map(|t| bcx.ty_to_str(*t)).connect(",")));
format!("type parameters for node {:?} include inference types: {}",
node, params.map(|t| bcx.ty_to_str(*t)).connect(",")));
}
match bcx.fcx.param_substs {

View file

@ -190,7 +190,8 @@ pub fn const_expr(cx: @CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef
let mut llconst = llconst;
let mut inlineable = inlineable;
let ety = ty::expr_ty(cx.tcx, e);
let ety_adjusted = ty::expr_ty_adjusted(cx.tcx, e);
let ety_adjusted = ty::expr_ty_adjusted(cx.tcx, e,
cx.maps.method_map.borrow().get());
let adjustment = {
let adjustments = cx.tcx.adjustments.borrow();
adjustments.get().find_copy(&e.id)
@ -422,7 +423,8 @@ fn const_expr_unadjusted(cx: @CrateContext, e: &ast::Expr,
}, true)
}
ast::ExprField(base, field, _) => {
let bt = ty::expr_ty_adjusted(cx.tcx, base);
let bt = ty::expr_ty_adjusted(cx.tcx, base,
cx.maps.method_map.borrow().get());
let brepr = adt::represent_type(cx, bt);
let (bv, inlineable) = const_expr(cx, base, is_local);
expr::with_field_tys(cx.tcx, bt, None, |discr, field_tys| {
@ -432,7 +434,8 @@ fn const_expr_unadjusted(cx: @CrateContext, e: &ast::Expr,
}
ast::ExprIndex(base, index) => {
let bt = ty::expr_ty_adjusted(cx.tcx, base);
let bt = ty::expr_ty_adjusted(cx.tcx, base,
cx.maps.method_map.borrow().get());
let (bv, inlineable) = const_expr(cx, base, is_local);
let iv = match const_eval::eval_const_expr(cx.tcx, index) {
const_eval::const_int(i) => i as u64,

View file

@ -64,6 +64,7 @@ use middle::ty::struct_fields;
use middle::ty::{AutoBorrowObj, AutoDerefRef, AutoAddEnv, AutoObject, AutoUnsafe};
use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn};
use middle::ty;
use middle::typeck::MethodCall;
use util::common::indenter;
use util::ppaux::Repr;
use util::nodemap::NodeMap;
@ -211,8 +212,11 @@ fn apply_adjustments<'a>(bcx: &'a Block<'a>,
unpack_datum!(bcx, auto_slice_and_ref(bcx, expr, datum))
}
Some(AutoBorrowFn(..)) => {
let adjusted_ty = ty::adjust_ty(bcx.tcx(), expr.span,
datum.ty, Some(adjustment));
let adjusted_ty = ty::adjust_ty(bcx.tcx(), expr.span, expr.id, datum.ty,
Some(adjustment), |method_call| {
bcx.ccx().maps.method_map.borrow().get()
.find(&method_call).map(|method| method.ty)
});
unpack_datum!(bcx, auto_borrow_fn(bcx, adjusted_ty, datum))
}
Some(AutoBorrowObj(..)) => {
@ -221,7 +225,8 @@ fn apply_adjustments<'a>(bcx: &'a Block<'a>,
};
}
AutoObject(..) => {
let adjusted_ty = ty::expr_ty_adjusted(bcx.tcx(), expr);
let adjusted_ty = ty::expr_ty_adjusted(bcx.tcx(), expr,
bcx.ccx().maps.method_map.borrow().get());
let scratch = rvalue_scratch_datum(bcx, adjusted_ty, "__adjust");
bcx = meth::trans_trait_cast(
bcx, datum, expr.id, SaveIn(scratch.val));
@ -231,30 +236,6 @@ fn apply_adjustments<'a>(bcx: &'a Block<'a>,
debug!("after adjustments, datum={}", datum.to_str(bcx.ccx()));
return DatumBlock {bcx: bcx, datum: datum};
fn auto_ref<'a>(bcx: &'a Block<'a>,
datum: Datum<Expr>,
expr: &ast::Expr)
-> DatumBlock<'a, Expr> {
let mut bcx = bcx;
// Ensure cleanup of `datum` if not already scheduled and obtain
// a "by ref" pointer.
let lv_datum = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "autoref", expr.id));
// Compute final type. Note that we are loose with the region and
// mutability, since those things don't matter in trans.
let referent_ty = lv_datum.ty;
let ptr_ty = ty::mk_imm_rptr(bcx.tcx(), ty::ReStatic, referent_ty);
// Get the pointer.
let llref = lv_datum.to_llref();
// Construct the resulting datum, using what was the "by ref"
// ValueRef of type `referent_ty` to be the "by value" ValueRef
// of type `&referent_ty`.
DatumBlock(bcx, Datum(llref, ptr_ty, RvalueExpr(Rvalue(ByValue))))
}
fn auto_borrow_fn<'a>(
bcx: &'a Block<'a>,
adjusted_ty: ty::t,
@ -462,13 +443,10 @@ fn trans_datum_unadjusted<'a>(bcx: &'a Block<'a>,
}
ast::ExprLit(lit) => trans_immediate_lit(bcx, expr, (*lit).clone()),
ast::ExprBinary(op, lhs, rhs) => {
// if overloaded, would be RvalueDpsExpr
assert!(!bcx.ccx().maps.method_map.borrow().get().contains_key(&expr.id));
trans_binary(bcx, expr, op, lhs, rhs)
}
ast::ExprUnary(op, x) => {
trans_unary_datum(bcx, expr, op, x)
trans_unary(bcx, expr, op, x)
}
ast::ExprAddrOf(_, x) => {
trans_addr_of(bcx, expr, x)
@ -789,15 +767,23 @@ fn trans_rvalue_dps_unadjusted<'a>(bcx: &'a Block<'a>,
}
ast::ExprBinary(_, lhs, rhs) => {
// if not overloaded, would be RvalueDatumExpr
trans_overloaded_op(bcx, expr, lhs, Some(&*rhs), Some(dest)).bcx
let lhs = unpack_datum!(bcx, trans(bcx, lhs));
let rhs_datum = unpack_datum!(bcx, trans(bcx, rhs));
trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), lhs,
Some((rhs_datum, rhs.id)), Some(dest)).bcx
}
ast::ExprUnary(_, subexpr) => {
// if not overloaded, would be RvalueDatumExpr
trans_overloaded_op(bcx, expr, subexpr, None, Some(dest)).bcx
let arg = unpack_datum!(bcx, trans(bcx, subexpr));
trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id),
arg, None, Some(dest)).bcx
}
ast::ExprIndex(base, idx) => {
// if not overloaded, would be RvalueDatumExpr
trans_overloaded_op(bcx, expr, base, Some(&*idx), Some(dest)).bcx
let base = unpack_datum!(bcx, trans(bcx, base));
let idx_datum = unpack_datum!(bcx, trans(bcx, idx));
trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), base,
Some((idx_datum, idx.id)), Some(dest)).bcx
}
ast::ExprCast(val, _) => {
// DPS output mode means this is a trait cast:
@ -848,7 +834,7 @@ fn trans_def_dps_unadjusted<'a>(
let variant_info = ty::enum_variant_with_id(ccx.tcx, tid, vid);
if variant_info.args.len() > 0u {
// N-ary variant.
let llfn = callee::trans_fn_ref(bcx, vid, ref_expr.id, false);
let llfn = callee::trans_fn_ref(bcx, vid, ExprId(ref_expr.id));
Store(bcx, llfn, lldest);
return bcx;
} else {
@ -888,7 +874,7 @@ fn trans_def_fn_unadjusted<'a>(bcx: &'a Block<'a>,
ast::DefFn(did, _) |
ast::DefStruct(did) | ast::DefVariant(_, did, _) |
ast::DefStaticMethod(did, ast::FromImpl(_), _) => {
callee::trans_fn_ref(bcx, did, ref_expr.id, false)
callee::trans_fn_ref(bcx, did, ExprId(ref_expr.id))
}
ast::DefStaticMethod(impl_did, ast::FromTrait(trait_did), _) => {
meth::trans_static_method_callee(bcx, impl_did,
@ -1165,25 +1151,22 @@ fn trans_immediate_lit<'a>(bcx: &'a Block<'a>,
immediate_rvalue_bcx(bcx, v, ty).to_expr_datumblock()
}
fn trans_unary_datum<'a>(
bcx: &'a Block<'a>,
un_expr: &ast::Expr,
fn trans_unary<'a>(bcx: &'a Block<'a>,
expr: &ast::Expr,
op: ast::UnOp,
sub_expr: &ast::Expr)
-> DatumBlock<'a, Expr> {
let mut bcx = bcx;
let _icx = push_ctxt("trans_unary_datum");
let overloaded = {
let method_map = bcx.ccx().maps.method_map.borrow();
method_map.get().contains_key(&un_expr.id)
};
let method_call = MethodCall::expr(expr.id);
let overloaded = bcx.ccx().maps.method_map.borrow().get().contains_key(&method_call);
// if overloaded, would be RvalueDpsExpr
assert!(!overloaded || op == ast::UnDeref);
let un_ty = expr_ty(bcx, un_expr);
let un_ty = expr_ty(bcx, expr);
return match op {
match op {
ast::UnNot => {
let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
let llresult = if ty::type_is_bool(un_ty) {
@ -1218,15 +1201,10 @@ fn trans_unary_datum<'a>(
trans_boxed_expr(bcx, un_ty, sub_expr, expr_ty(bcx, sub_expr), heap_exchange)
}
ast::UnDeref => {
if overloaded {
let r = trans_overloaded_op(bcx, un_expr, sub_expr, None, None);
DatumBlock(r.bcx, Datum(r.val, un_ty, LvalueExpr))
} else {
let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
deref_once(bcx, un_expr, datum, 0)
deref_once(bcx, expr, datum, 0)
}
}
};
}
fn trans_boxed_expr<'a>(bcx: &'a Block<'a>,
@ -1451,9 +1429,8 @@ fn trans_lazy_binop<'a>(
return immediate_rvalue_bcx(join, phi, binop_ty).to_expr_datumblock();
}
fn trans_binary<'a>(
bcx: &'a Block<'a>,
binop_expr: &ast::Expr,
fn trans_binary<'a>(bcx: &'a Block<'a>,
expr: &ast::Expr,
op: ast::BinOp,
lhs: &ast::Expr,
rhs: &ast::Expr)
@ -1461,31 +1438,34 @@ fn trans_binary<'a>(
let _icx = push_ctxt("trans_binary");
let ccx = bcx.ccx();
// if overloaded, would be RvalueDpsExpr
assert!(!ccx.maps.method_map.borrow().get().contains_key(&MethodCall::expr(expr.id)));
match op {
ast::BiAnd => {
trans_lazy_binop(bcx, binop_expr, lazy_and, lhs, rhs)
trans_lazy_binop(bcx, expr, lazy_and, lhs, rhs)
}
ast::BiOr => {
trans_lazy_binop(bcx, binop_expr, lazy_or, lhs, rhs)
trans_lazy_binop(bcx, expr, lazy_or, lhs, rhs)
}
_ => {
let mut bcx = bcx;
let lhs_datum = unpack_datum!(bcx, trans(bcx, lhs));
let rhs_datum = unpack_datum!(bcx, trans(bcx, rhs));
let binop_ty = expr_ty(bcx, binop_expr);
let binop_ty = expr_ty(bcx, expr);
debug!("trans_binary (expr {}): lhs_datum={}",
binop_expr.id,
expr.id,
lhs_datum.to_str(ccx));
let lhs_ty = lhs_datum.ty;
let lhs = lhs_datum.to_llscalarish(bcx);
debug!("trans_binary (expr {}): rhs_datum={}",
binop_expr.id,
expr.id,
rhs_datum.to_str(ccx));
let rhs_ty = rhs_datum.ty;
let rhs = rhs_datum.to_llscalarish(bcx);
trans_eager_binop(bcx, binop_expr, binop_ty, op,
trans_eager_binop(bcx, expr, binop_ty, op,
lhs_ty, lhs, rhs_ty, rhs)
}
}
@ -1494,21 +1474,22 @@ fn trans_binary<'a>(
fn trans_overloaded_op<'a, 'b>(
bcx: &'a Block<'a>,
expr: &ast::Expr,
rcvr: &'b ast::Expr,
arg: Option<&'b ast::Expr>,
method_call: MethodCall,
lhs: Datum<Expr>,
rhs: Option<(Datum<Expr>, ast::NodeId)>,
dest: Option<Dest>)
-> Result<'a> {
let method_ty = bcx.ccx().maps.method_map.borrow().get().get(&expr.id).ty;
let method_ty = bcx.ccx().maps.method_map.borrow().get().get(&method_call).ty;
callee::trans_call_inner(bcx,
Some(expr_info(expr)),
monomorphize_type(bcx, method_ty),
|bcx, arg_cleanup_scope| {
meth::trans_method_callee(bcx,
expr.id,
rcvr,
method_call,
None,
arg_cleanup_scope)
},
callee::ArgAutorefSecond(rcvr, arg),
callee::ArgOverloadedOp(lhs, rhs),
dest)
}
@ -1666,10 +1647,7 @@ fn trans_assign_op<'a>(
debug!("trans_assign_op(expr={})", bcx.expr_to_str(expr));
// User-defined operator methods cannot be used with `+=` etc right now
assert!({
let method_map = bcx.ccx().maps.method_map.borrow();
!method_map.get().find(&expr.id).is_some()
});
assert!(!bcx.ccx().maps.method_map.borrow().get().contains_key(&MethodCall::expr(expr.id)));
// Evaluate LHS (destination), which should be an lvalue
let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op"));
@ -1748,6 +1726,30 @@ fn trans_log_level<'a>(bcx: &'a Block<'a>) -> DatumBlock<'a, Expr> {
immediate_rvalue_bcx(bcx, Load(bcx, global), ty::mk_u32()).to_expr_datumblock()
}
fn auto_ref<'a>(bcx: &'a Block<'a>,
datum: Datum<Expr>,
expr: &ast::Expr)
-> DatumBlock<'a, Expr> {
let mut bcx = bcx;
// Ensure cleanup of `datum` if not already scheduled and obtain
// a "by ref" pointer.
let lv_datum = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "autoref", expr.id));
// Compute final type. Note that we are loose with the region and
// mutability, since those things don't matter in trans.
let referent_ty = lv_datum.ty;
let ptr_ty = ty::mk_imm_rptr(bcx.tcx(), ty::ReStatic, referent_ty);
// Get the pointer.
let llref = lv_datum.to_llref();
// Construct the resulting datum, using what was the "by ref"
// ValueRef of type `referent_ty` to be the "by value" ValueRef
// of type `&referent_ty`.
DatumBlock(bcx, Datum(llref, ptr_ty, RvalueExpr(Rvalue(ByValue))))
}
fn deref_multiple<'a>(bcx: &'a Block<'a>,
expr: &ast::Expr,
datum: Datum<Expr>,
@ -1777,6 +1779,28 @@ fn deref_once<'a>(bcx: &'a Block<'a>,
let mut bcx = bcx;
let method_call = MethodCall {
expr_id: expr.id,
autoderef: derefs as u32
};
let method_ty = ccx.maps.method_map.borrow().get()
.find(&method_call).map(|method| method.ty);
let datum = match method_ty {
Some(method_ty) => {
let datum = if derefs == 0 {
datum
} else {
// Always perform an AutoPtr when applying an overloaded auto-deref.
unpack_datum!(bcx, auto_ref(bcx, datum, expr))
};
let val = unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call,
datum, None, None));
let ref_ty = ty::ty_fn_ret(monomorphize_type(bcx, method_ty));
Datum(val, ref_ty, RvalueExpr(Rvalue(ByValue)))
}
None => datum
};
let r = match ty::get(datum.ty).sty {
ty::ty_uniq(content_ty) => {
deref_owned_pointer(bcx, expr, datum, content_ty)
@ -1805,55 +1829,6 @@ fn deref_once<'a>(bcx: &'a Block<'a>,
DatumBlock(bcx, Datum(ptr, content_ty, LvalueExpr))
}
ty::ty_enum(..) |
ty::ty_struct(..) => {
// Subtle efficiency note: In the case where we have a
// newtype struct where the struct itself does not have a
// dtor, but the contents do, we could avoid forcing the
// data into Lvalue and instead return an Rvalue. But it
// doesn't seem worth the trouble.
let datum = unpack_datum!(bcx, ensure_cleanup(bcx, expr, datum));
// Unlike the pointer case above, we generate an
// rvalue datum if we are given an rvalue. There are
// two reasons that this makes sense here:
//
// 1. dereferencing a struct does not actually perform a
// pointer load and hence the resulting value is not
// naturally by reference, as would be required by an
// lvalue result.
//
// 2. the struct always owns its contents, and hence and does not
// itself have a dtor (else it would be in lvalue mode).
let repr = adt::represent_type(ccx, datum.ty);
let ty = adt::deref_ty(ccx, repr);
let Datum { val, kind, .. } = datum;
let r = match kind {
LvalueExpr => {
Datum {
val: adt::trans_field_ptr(bcx, repr, val, 0, 0),
ty: ty,
kind: LvalueExpr
}
}
RvalueExpr(Rvalue { mode: ByRef }) => {
Datum {
val: adt::trans_field_ptr(bcx, repr, val, 0, 0),
ty: ty,
kind: RvalueExpr(Rvalue(ByValue))
}
}
RvalueExpr(Rvalue { mode: ByValue }) => {
Datum {
val: ExtractValue(bcx, val, 0),
ty: ty,
kind: RvalueExpr(Rvalue(ByValue))
}
}
};
DatumBlock(bcx, r)
}
_ => {
bcx.tcx().sess.span_bug(
expr.span,
@ -1867,25 +1842,6 @@ fn deref_once<'a>(bcx: &'a Block<'a>,
return r;
fn ensure_cleanup<'a>(mut bcx: &'a Block<'a>,
expr: &ast::Expr,
datum: Datum<Expr>)
-> DatumBlock<'a, Expr> {
/*!
* If the datum contains data that needs to be dropped,
* convert it to an lvalue, thus ensuring that cleanup
* is scheduled.
*/
if ty::type_needs_drop(bcx.tcx(), datum.ty) {
let lv_datum = unpack_datum!(
bcx, datum.to_lvalue_datum(bcx, "deref", expr.id));
DatumBlock(bcx, lv_datum.to_expr_datum())
} else {
DatumBlock(bcx, datum)
}
}
fn deref_owned_pointer<'a>(bcx: &'a Block<'a>,
expr: &ast::Expr,
datum: Datum<Expr>,

View file

@ -29,6 +29,7 @@ use middle::trans::type_::Type;
use middle::trans::type_of::*;
use middle::ty;
use middle::typeck;
use middle::typeck::MethodCall;
use util::common::indenter;
use util::ppaux::Repr;
@ -93,21 +94,22 @@ pub fn trans_method(ccx: @CrateContext, method: &ast::Method,
pub fn trans_method_callee<'a>(
bcx: &'a Block<'a>,
expr_id: ast::NodeId,
this: &ast::Expr,
method_call: MethodCall,
self_expr: Option<&ast::Expr>,
arg_cleanup_scope: cleanup::ScopeId)
-> Callee<'a> {
let _icx = push_ctxt("meth::trans_method_callee");
let (origin, method_ty) = match bcx.ccx().maps.method_map
.borrow().get().find(&expr_id) {
.borrow().get().find(&method_call) {
Some(method) => {
debug!("trans_method_callee(expr_id={:?}, method={})",
expr_id, method.repr(bcx.tcx()));
debug!("trans_method_callee({:?}, method={})",
method_call, method.repr(bcx.tcx()));
(method.origin, method.ty)
}
None => {
bcx.tcx().sess.span_bug(this.span, "method call expr wasn't in method map")
bcx.tcx().sess.span_bug(bcx.tcx().map.span(method_call.expr_id),
"method call expr wasn't in method map")
}
};
@ -115,7 +117,7 @@ pub fn trans_method_callee<'a>(
typeck::MethodStatic(did) => {
Callee {
bcx: bcx,
data: Fn(callee::trans_fn_ref(bcx, did, expr_id, true))
data: Fn(callee::trans_fn_ref(bcx, did, MethodCall(method_call)))
}
}
typeck::MethodParam(typeck::MethodParam {
@ -131,7 +133,7 @@ pub fn trans_method_callee<'a>(
trait_id);
let vtbl = find_vtable(bcx.tcx(), substs, p, b);
trans_monomorphized_callee(bcx, expr_id,
trans_monomorphized_callee(bcx, method_call,
trait_id, off, vtbl)
}
// how to get rid of this?
@ -140,10 +142,18 @@ pub fn trans_method_callee<'a>(
}
typeck::MethodObject(ref mt) => {
let self_expr = match self_expr {
Some(self_expr) => self_expr,
None => {
bcx.tcx().sess.span_bug(bcx.tcx().map.span(method_call.expr_id),
"self expr wasn't provided for trait object \
callee (trying to call overloaded op?)")
}
};
trans_trait_callee(bcx,
monomorphize_type(bcx, method_ty),
mt.real_index,
this,
self_expr,
arg_cleanup_scope)
}
}
@ -209,13 +219,10 @@ pub fn trans_static_method_callee(bcx: &Block,
let mth_id = method_with_name(ccx, impl_did, mname);
let (callee_substs, callee_origins) =
combine_impl_and_methods_tps(
bcx, mth_id, expr_id, false,
bcx, mth_id, ExprId(expr_id),
rcvr_substs.as_slice(), rcvr_origins);
let llfn = trans_fn_ref_with_vtables(bcx,
mth_id,
expr_id,
false,
let llfn = trans_fn_ref_with_vtables(bcx, mth_id, ExprId(expr_id),
callee_substs.as_slice(),
Some(callee_origins));
@ -254,7 +261,7 @@ pub fn method_with_name(ccx: &CrateContext,
}
fn trans_monomorphized_callee<'a>(bcx: &'a Block<'a>,
expr_id: ast::NodeId,
method_call: MethodCall,
trait_id: ast::DefId,
n_method: uint,
vtbl: typeck::vtable_origin)
@ -270,14 +277,13 @@ fn trans_monomorphized_callee<'a>(bcx: &'a Block<'a>,
// those from the impl and those from the method:
let (callee_substs, callee_origins) =
combine_impl_and_methods_tps(
bcx, mth_id, expr_id, true,
bcx, mth_id, MethodCall(method_call),
rcvr_substs.as_slice(), rcvr_origins);
// translate the function
let llfn = trans_fn_ref_with_vtables(bcx,
mth_id,
expr_id,
true,
MethodCall(method_call),
callee_substs.as_slice(),
Some(callee_origins));
@ -291,8 +297,7 @@ fn trans_monomorphized_callee<'a>(bcx: &'a Block<'a>,
fn combine_impl_and_methods_tps(bcx: &Block,
mth_did: ast::DefId,
expr_id: ast::NodeId,
is_method: bool,
node: ExprOrMethodCall,
rcvr_substs: &[ty::t],
rcvr_origins: typeck::vtable_res)
-> (Vec<ty::t> , typeck::vtable_res) {
@ -316,7 +321,7 @@ fn combine_impl_and_methods_tps(bcx: &Block,
let ccx = bcx.ccx();
let method = ty::method(ccx.tcx, mth_did);
let n_m_tps = method.generics.type_param_defs().len();
let node_substs = node_id_type_params(bcx, expr_id, is_method);
let node_substs = node_id_type_params(bcx, node);
debug!("rcvr_substs={:?}", rcvr_substs.repr(ccx.tcx));
let ty_substs
= vec_ng::append(Vec::from_slice(rcvr_substs),
@ -328,7 +333,14 @@ fn combine_impl_and_methods_tps(bcx: &Block,
// Now, do the same work for the vtables. The vtables might not
// exist, in which case we need to make them.
let r_m_origins = match node_vtables(bcx, expr_id) {
let vtables = match node {
ExprId(id) => node_vtables(bcx, id),
MethodCall(method_call) if method_call.autoderef == 0 => {
node_vtables(bcx, method_call.expr_id)
}
_ => None
};
let r_m_origins = match vtables {
Some(vt) => vt,
None => @Vec::from_elem(node_substs.len(), @Vec::new())
};
@ -555,7 +567,7 @@ fn emit_vtable_methods(bcx: &Block,
token::get_ident(ident));
C_null(Type::nil().ptr_to())
} else {
trans_fn_ref_with_vtables(bcx, m_id, 0, false, substs, Some(vtables))
trans_fn_ref_with_vtables(bcx, m_id, ExprId(0), substs, Some(vtables))
}
})
}

View file

@ -23,6 +23,7 @@ use middle::resolve_lifetime;
use middle::ty;
use middle::subst::Subst;
use middle::typeck;
use middle::typeck::{MethodCall, MethodCallee, MethodMap};
use middle::ty_fold;
use middle::ty_fold::TypeFolder;
use middle;
@ -30,7 +31,7 @@ use util::ppaux::{note_and_explain_region, bound_region_ptr_to_str};
use util::ppaux::{trait_store_to_str, ty_to_str, vstore_to_str};
use util::ppaux::{Repr, UserString};
use util::common::{indenter};
use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet, FnvHashMap};
use std::cast;
use std::cell::{Cell, RefCell};
@ -258,10 +259,7 @@ pub struct ctxt_ {
diag: @syntax::diagnostic::SpanHandler,
// Specifically use a speedy hash algorithm for this hash map, it's used
// quite often.
#[cfg(stage0)]
interner: RefCell<HashMap<intern_key, ~t_box_>>,
#[cfg(not(stage0))]
interner: RefCell<HashMap<intern_key, ~t_box_, ::util::nodemap::FnvHasher>>,
interner: RefCell<FnvHashMap<intern_key, ~t_box_>>,
next_id: Cell<uint>,
cstore: @metadata::cstore::CStore,
sess: session::Session,
@ -1091,19 +1089,11 @@ pub fn mk_ctxt(s: session::Session,
region_maps: middle::region::RegionMaps,
lang_items: @middle::lang_items::LanguageItems)
-> ctxt {
#[cfg(stage0)]
fn hasher() -> HashMap<intern_key, ~t_box_> {
HashMap::new()
}
#[cfg(not(stage0))]
fn hasher() -> HashMap<intern_key, ~t_box_, ::util::nodemap::FnvHasher> {
HashMap::with_hasher(::util::nodemap::FnvHasher)
}
@ctxt_ {
named_region_map: named_region_map,
item_variance_map: RefCell::new(DefIdMap::new()),
diag: s.diagnostic(),
interner: RefCell::new(hasher()),
interner: RefCell::new(FnvHashMap::new()),
next_id: Cell::new(primitives::LAST_PRIMITIVE_ID),
cstore: s.cstore,
sess: s,
@ -2710,47 +2700,20 @@ pub fn type_param(ty: t) -> Option<uint> {
// The parameter `explicit` indicates if this is an *explicit* dereference.
// Some types---notably unsafe ptrs---can only be dereferenced explicitly.
pub fn deref(t: t, explicit: bool) -> Option<mt> {
deref_sty(&get(t).sty, explicit)
}
pub fn deref_sty(sty: &sty, explicit: bool) -> Option<mt> {
match *sty {
ty_box(typ) | ty_uniq(typ) => {
Some(mt {
match get(t).sty {
ty_box(typ) | ty_uniq(typ) => Some(mt {
ty: typ,
mutbl: ast::MutImmutable,
})
}
ty_rptr(_, mt) => {
Some(mt)
}
ty_ptr(mt) if explicit => {
Some(mt)
}
}),
ty_rptr(_, mt) => Some(mt),
ty_ptr(mt) if explicit => Some(mt),
_ => None
}
}
pub fn type_autoderef(t: t) -> t {
let mut t = t;
loop {
match deref(t, false) {
None => return t,
Some(mt) => t = mt.ty
}
}
}
// Returns the type and mutability of t[i]
pub fn index(t: t) -> Option<mt> {
index_sty(&get(t).sty)
}
pub fn index_sty(sty: &sty) -> Option<mt> {
match *sty {
match get(t).sty {
ty_vec(mt, _) => Some(mt),
ty_str(_) => Some(mt {ty: mk_u8(), mutbl: ast::MutImmutable}),
_ => None
@ -2964,7 +2927,10 @@ pub fn expr_ty_opt(cx: ctxt, expr: &ast::Expr) -> Option<t> {
return node_id_to_type_opt(cx, expr.id);
}
pub fn expr_ty_adjusted(cx: ctxt, expr: &ast::Expr) -> t {
pub fn expr_ty_adjusted(cx: ctxt,
expr: &ast::Expr,
method_map: &FnvHashMap<MethodCall, MethodCallee>)
-> t {
/*!
*
* Returns the type of `expr`, considering any `AutoAdjustment`
@ -2979,11 +2945,10 @@ pub fn expr_ty_adjusted(cx: ctxt, expr: &ast::Expr) -> t {
*/
let unadjusted_ty = expr_ty(cx, expr);
let adjustment = {
let adjustments = cx.adjustments.borrow();
adjustments.get().find_copy(&expr.id)
};
adjust_ty(cx, expr.span, unadjusted_ty, adjustment)
let adjustment = cx.adjustments.borrow().get().find_copy(&expr.id);
adjust_ty(cx, expr.span, expr.id, unadjusted_ty, adjustment, |method_call| {
method_map.find(&method_call).map(|method| method.ty)
})
}
pub fn expr_span(cx: ctxt, id: NodeId) -> Span {
@ -3026,14 +2991,14 @@ pub fn local_var_name_str(cx: ctxt, id: NodeId) -> InternedString {
pub fn adjust_ty(cx: ctxt,
span: Span,
expr_id: ast::NodeId,
unadjusted_ty: ty::t,
adjustment: Option<@AutoAdjustment>)
adjustment: Option<@AutoAdjustment>,
method_type: |MethodCall| -> Option<ty::t>)
-> ty::t {
/*! See `expr_ty_adjusted` */
return match adjustment {
None => unadjusted_ty,
Some(adjustment) => {
match *adjustment {
AutoAddEnv(r, s) => {
@ -3062,7 +3027,13 @@ pub fn adjust_ty(cx: ctxt,
if !ty::type_is_error(adjusted_ty) {
for i in range(0, adj.autoderefs) {
match ty::deref(adjusted_ty, true) {
match method_type(MethodCall::autoderef(expr_id, i as u32)) {
Some(method_ty) => {
adjusted_ty = ty_fn_ret(method_ty);
}
None => {}
}
match deref(adjusted_ty, true) {
Some(mt) => { adjusted_ty = mt.ty; }
None => {
cx.sess.span_bug(
@ -3130,6 +3101,7 @@ pub fn adjust_ty(cx: ctxt,
}
}
}
None => unadjusted_ty
};
fn borrow_vec(cx: ctxt, span: Span,
@ -3274,7 +3246,7 @@ pub fn resolve_expr(tcx: ctxt, expr: &ast::Expr) -> ast::Def {
}
pub fn expr_is_lval(tcx: ctxt,
method_map: typeck::MethodMap,
method_map: MethodMap,
e: &ast::Expr) -> bool {
match expr_kind(tcx, method_map, e) {
LvalueExpr => true,
@ -3295,11 +3267,9 @@ pub enum ExprKind {
}
pub fn expr_kind(tcx: ctxt,
method_map: typeck::MethodMap,
method_map: MethodMap,
expr: &ast::Expr) -> ExprKind {
{
let method_map = method_map.borrow();
if method_map.get().contains_key(&expr.id) {
if method_map.borrow().get().contains_key(&MethodCall::expr(expr.id)) {
// Overloaded operations are generally calls, and hence they are
// generated via DPS. However, assign_op (e.g., `x += y`) is an
// exception, as its result is always unit.
@ -3309,7 +3279,6 @@ pub fn expr_kind(tcx: ctxt,
_ => RvalueDpsExpr
};
}
}
match expr.node {
ast::ExprPath(..) => {

View file

@ -84,9 +84,7 @@ use middle::subst::Subst;
use middle::ty::*;
use middle::ty;
use middle::typeck::astconv::AstConv;
use middle::typeck::check::{FnCtxt, impl_self_ty};
use middle::typeck::check::{structurally_resolved_type};
use middle::typeck::check::vtable;
use middle::typeck::check::{FnCtxt, PreferMutLvalue, impl_self_ty};
use middle::typeck::check;
use middle::typeck::infer;
use middle::typeck::MethodCallee;
@ -106,6 +104,7 @@ use syntax::ast::{DefId, SelfValue, SelfRegion};
use syntax::ast::{SelfUniq, SelfStatic};
use syntax::ast::{MutMutable, MutImmutable};
use syntax::ast;
use syntax::codemap::Span;
use syntax::parse::token;
#[deriving(Eq)]
@ -120,23 +119,23 @@ pub enum AutoderefReceiverFlag {
DontAutoderefReceiver,
}
pub fn lookup(
pub fn lookup<'a>(
fcx: @FnCtxt,
// In a call `a.b::<X, Y, ...>(...)`:
expr: &ast::Expr, // The expression `a.b(...)`.
self_expr: &ast::Expr, // The expression `a`.
self_expr: &'a ast::Expr, // The expression `a`.
m_name: ast::Name, // The name `b`.
self_ty: ty::t, // The type of `a`.
supplied_tps: &[ty::t], // The list of types X, Y, ... .
supplied_tps: &'a [ty::t], // The list of types X, Y, ... .
deref_args: check::DerefArgs, // Whether we autopointer first.
check_traits: CheckTraitsFlag, // Whether we check traits only.
autoderef_receiver: AutoderefReceiverFlag)
-> Option<MethodCallee> {
let lcx = LookupContext {
fcx: fcx,
expr: expr,
self_expr: self_expr,
span: expr.span,
self_expr: Some(self_expr),
m_name: m_name,
supplied_tps: supplied_tps,
impl_dups: @RefCell::new(HashSet::new()),
@ -147,7 +146,6 @@ pub fn lookup(
autoderef_receiver: autoderef_receiver,
};
let self_ty = structurally_resolved_type(fcx, self_expr.span, self_ty);
debug!("method lookup(self_ty={}, expr={}, self_expr={})",
self_ty.repr(fcx.tcx()), expr.repr(fcx.tcx()),
self_expr.repr(fcx.tcx()));
@ -162,25 +160,25 @@ pub fn lookup(
debug!("searching extension candidates");
lcx.reset_candidates();
lcx.push_bound_candidates(self_ty, None);
lcx.push_extension_candidates();
lcx.push_extension_candidates(expr.id);
return lcx.search(self_ty);
}
pub fn lookup_in_trait(
pub fn lookup_in_trait<'a>(
fcx: @FnCtxt,
// In a call `a.b::<X, Y, ...>(...)`:
expr: &ast::Expr, // The expression `a.b(...)`.
self_expr: &ast::Expr, // The expression `a`.
span: Span, // The expression `a.b(...)`'s span.
self_expr: Option<&'a ast::Expr>, // The expression `a`, if available.
m_name: ast::Name, // The name `b`.
trait_did: DefId, // The trait to limit the lookup to.
self_ty: ty::t, // The type of `a`.
supplied_tps: &[ty::t], // The list of types X, Y, ... .
supplied_tps: &'a [ty::t], // The list of types X, Y, ... .
autoderef_receiver: AutoderefReceiverFlag)
-> Option<MethodCallee> {
let lcx = LookupContext {
fcx: fcx,
expr: expr,
span: span,
self_expr: self_expr,
m_name: m_name,
supplied_tps: supplied_tps,
@ -192,20 +190,18 @@ pub fn lookup_in_trait(
autoderef_receiver: autoderef_receiver,
};
let self_ty = structurally_resolved_type(fcx, self_expr.span, self_ty);
debug!("method lookup_in_trait(self_ty={}, expr={}, self_expr={})",
self_ty.repr(fcx.tcx()), expr.repr(fcx.tcx()),
self_expr.repr(fcx.tcx()));
debug!("method lookup_in_trait(self_ty={}, self_expr={})",
self_ty.repr(fcx.tcx()), self_expr.map(|e| e.repr(fcx.tcx())));
lcx.push_bound_candidates(self_ty, Some(trait_did));
lcx.push_extension_candidate(trait_did);
lcx.search(self_ty)
}
pub struct LookupContext<'a> {
struct LookupContext<'a> {
fcx: @FnCtxt,
expr: &'a ast::Expr,
self_expr: &'a ast::Expr,
span: Span,
self_expr: Option<&'a ast::Expr>,
m_name: ast::Name,
supplied_tps: &'a [ty::t],
impl_dups: @RefCell<HashSet<DefId>>,
@ -221,7 +217,7 @@ pub struct LookupContext<'a> {
* is of a suitable type.
*/
#[deriving(Clone)]
pub struct Candidate {
struct Candidate {
rcvr_match_condition: RcvrMatchCondition,
rcvr_substs: ty::substs,
method_ty: @ty::Method,
@ -244,36 +240,35 @@ pub enum RcvrMatchCondition {
impl<'a> LookupContext<'a> {
fn search(&self, self_ty: ty::t) -> Option<MethodCallee> {
let mut self_ty = self_ty;
let mut autoderefs = 0;
loop {
let span = self.self_expr.map_or(self.span, |e| e.span);
let self_expr_id = self.self_expr.map(|e| e.id);
let (self_ty, autoderefs, result) =
check::autoderef(self.fcx, span, self_ty, self_expr_id,
PreferMutLvalue, |self_ty, autoderefs| {
debug!("loop: self_ty={} autoderefs={}",
self.ty_to_str(self_ty), autoderefs);
match self.deref_args {
check::DontDerefArgs => {
match self.search_for_autoderefd_method(self_ty,
autoderefs) {
Some(mme) => { return Some(mme); }
match self.search_for_autoderefd_method(self_ty, autoderefs) {
Some(result) => return Some(Some(result)),
None => {}
}
match self.search_for_autoptrd_method(self_ty,
autoderefs) {
Some(mme) => { return Some(mme); }
match self.search_for_autoptrd_method(self_ty, autoderefs) {
Some(result) => return Some(Some(result)),
None => {}
}
}
check::DoDerefArgs => {
match self.search_for_autoptrd_method(self_ty,
autoderefs) {
Some(mme) => { return Some(mme); }
match self.search_for_autoptrd_method(self_ty, autoderefs) {
Some(result) => return Some(Some(result)),
None => {}
}
match self.search_for_autoderefd_method(self_ty,
autoderefs) {
Some(mme) => { return Some(mme); }
match self.search_for_autoderefd_method(self_ty, autoderefs) {
Some(result) => return Some(Some(result)),
None => {}
}
}
@ -281,30 +276,15 @@ impl<'a> LookupContext<'a> {
// Don't autoderef if we aren't supposed to.
if self.autoderef_receiver == DontAutoderefReceiver {
break;
Some(None)
} else {
None
}
});
// Otherwise, perform autoderef.
match self.deref(self_ty) {
None => { break; }
Some(ty) => {
self_ty = ty;
autoderefs += 1;
}
}
}
self.search_for_autosliced_method(self_ty, autoderefs)
}
fn deref(&self, ty: ty::t) -> Option<ty::t> {
match ty::deref(ty, false) {
None => None,
Some(t) => {
Some(structurally_resolved_type(self.fcx,
self.self_expr.span,
t.ty))
}
match result {
Some(Some(result)) => Some(result),
_ => self.search_for_autosliced_method(self_ty, autoderefs)
}
}
@ -326,8 +306,8 @@ impl<'a> LookupContext<'a> {
* we'll want to find the inherent impls for `C`.
*/
let mut self_ty = self_ty;
loop {
let span = self.self_expr.map_or(self.span, |e| e.span);
check::autoderef(self.fcx, span, self_ty, None, PreferMutLvalue, |self_ty, _| {
match get(self_ty).sty {
ty_trait(did, ref substs, _, _, _) => {
self.push_inherent_candidates_from_object(did, substs);
@ -341,19 +321,18 @@ impl<'a> LookupContext<'a> {
_ => { /* No inherent methods in these types */ }
}
// n.b.: Generally speaking, we only loop if we hit the
// fallthrough case in the match above. The exception
// would be newtype enums.
self_ty = match self.deref(self_ty) {
None => { return; }
Some(ty) => { ty }
}
// Don't autoderef if we aren't supposed to.
if self.autoderef_receiver == DontAutoderefReceiver {
Some(())
} else {
None
}
});
}
fn push_bound_candidates(&self, self_ty: ty::t, restrict_to: Option<DefId>) {
let mut self_ty = self_ty;
loop {
let span = self.self_expr.map_or(self.span, |e| e.span);
check::autoderef(self.fcx, span, self_ty, None, PreferMutLvalue, |self_ty, _| {
match get(self_ty).sty {
ty_param(p) => {
self.push_inherent_candidates_from_param(self_ty, restrict_to, p);
@ -366,11 +345,13 @@ impl<'a> LookupContext<'a> {
_ => { /* No bound methods in these types */ }
}
self_ty = match self.deref(self_ty) {
None => { return; }
Some(ty) => { ty }
}
// Don't autoderef if we aren't supposed to.
if self.autoderef_receiver == DontAutoderefReceiver {
Some(())
} else {
None
}
});
}
fn push_extension_candidate(&self, trait_did: DefId) {
@ -386,11 +367,11 @@ impl<'a> LookupContext<'a> {
}
}
fn push_extension_candidates(&self) {
fn push_extension_candidates(&self, expr_id: ast::NodeId) {
// If the method being called is associated with a trait, then
// find all the impls of that trait. Each of those are
// candidates.
let opt_applicable_traits = self.fcx.ccx.trait_map.find(&self.expr.id);
let opt_applicable_traits = self.fcx.ccx.trait_map.find(&expr_id);
for applicable_traits in opt_applicable_traits.move_iter() {
for trait_did in applicable_traits.iter() {
self.push_extension_candidate(*trait_did);
@ -591,7 +572,7 @@ impl<'a> LookupContext<'a> {
}
fn push_candidates_from_impl(&self,
candidates: &mut Vec<Candidate> ,
candidates: &mut Vec<Candidate>,
impl_info: &ty::Impl) {
{
let mut impl_dups = self.impl_dups.borrow_mut();
@ -619,12 +600,12 @@ impl<'a> LookupContext<'a> {
// determine the `self` of the impl with fresh
// variables for each parameter:
let location_info = &vtable::location_info_for_expr(self.self_expr);
let span = self.self_expr.map_or(self.span, |e| e.span);
let vcx = self.fcx.vtable_context();
let ty::ty_param_substs_and_ty {
substs: impl_substs,
ty: impl_ty
} = impl_self_ty(&vcx, location_info, impl_info.did);
} = impl_self_ty(&vcx, span, impl_info.did);
candidates.push(Candidate {
rcvr_match_condition: RcvrMatchesIfSubtype(impl_ty),
@ -641,17 +622,34 @@ impl<'a> LookupContext<'a> {
self_ty: ty::t,
autoderefs: uint)
-> Option<MethodCallee> {
let (self_ty, autoadjust) =
let (self_ty, auto_deref_ref) =
self.consider_reborrow(self_ty, autoderefs);
// HACK(eddyb) only overloaded auto-deref calls should be missing
// adjustments, because we imply an AutoPtr adjustment for them.
let adjustment = match auto_deref_ref {
ty::AutoDerefRef {
autoderefs: 0,
autoref: Some(ty::AutoPtr(..))
} => None,
_ => match self.self_expr {
Some(expr) => Some((expr.id, @ty::AutoDerefRef(auto_deref_ref))),
None => return None
}
};
match self.search_for_method(self_ty) {
None => None,
Some(mme) => {
Some(method) => {
debug!("(searching for autoderef'd method) writing \
adjustment ({}) to {}",
autoderefs,
self.self_expr.id);
self.fcx.write_adjustment(self.self_expr.id, @autoadjust);
Some(mme)
adjustment {:?}", adjustment);
match adjustment {
Some((self_expr_id, adj)) => {
self.fcx.write_adjustment(self_expr_id, adj);
}
None => {}
}
Some(method)
}
}
}
@ -659,7 +657,7 @@ impl<'a> LookupContext<'a> {
fn consider_reborrow(&self,
self_ty: ty::t,
autoderefs: uint)
-> (ty::t, ty::AutoAdjustment) {
-> (ty::t, ty::AutoDerefRef) {
/*!
* In the event that we are invoking a method with a receiver
* of a borrowed type like `&T`, `&mut T`, or `&mut [T]`,
@ -681,44 +679,41 @@ impl<'a> LookupContext<'a> {
return match ty::get(self_ty).sty {
ty::ty_rptr(_, self_mt) if default_method_hack(self_mt) => {
(self_ty,
ty::AutoDerefRef(ty::AutoDerefRef {
ty::AutoDerefRef {
autoderefs: autoderefs,
autoref: None}))
autoref: None})
}
ty::ty_rptr(_, self_mt) => {
let region =
self.infcx().next_region_var(
infer::Autoref(self.expr.span));
self.infcx().next_region_var(infer::Autoref(self.span));
(ty::mk_rptr(tcx, region, self_mt),
ty::AutoDerefRef(ty::AutoDerefRef {
ty::AutoDerefRef {
autoderefs: autoderefs+1,
autoref: Some(ty::AutoPtr(region, self_mt.mutbl))}))
autoref: Some(ty::AutoPtr(region, self_mt.mutbl))})
}
ty::ty_vec(self_mt, vstore_slice(_)) => {
let region =
self.infcx().next_region_var(
infer::Autoref(self.expr.span));
self.infcx().next_region_var(infer::Autoref(self.span));
(ty::mk_vec(tcx, self_mt, vstore_slice(region)),
ty::AutoDerefRef(ty::AutoDerefRef {
ty::AutoDerefRef {
autoderefs: autoderefs,
autoref: Some(ty::AutoBorrowVec(region, self_mt.mutbl))}))
autoref: Some(ty::AutoBorrowVec(region, self_mt.mutbl))})
}
ty_trait(did, ref substs, ty::RegionTraitStore(_), mutbl, bounds) => {
ty::ty_trait(did, ref substs, ty::RegionTraitStore(_), mutbl, bounds) => {
let region =
self.infcx().next_region_var(
infer::Autoref(self.expr.span));
self.infcx().next_region_var(infer::Autoref(self.span));
(ty::mk_trait(tcx, did, substs.clone(),
ty::RegionTraitStore(region),
mutbl, bounds),
ty::AutoDerefRef(ty::AutoDerefRef {
ty::AutoDerefRef {
autoderefs: autoderefs,
autoref: Some(ty::AutoBorrowObj(region, mutbl))}))
autoref: Some(ty::AutoBorrowObj(region, mutbl))})
}
_ => {
(self_ty,
ty::AutoDerefRef(ty::AutoDerefRef {
ty::AutoDerefRef {
autoderefs: autoderefs,
autoref: None}))
autoref: None})
}
};
@ -848,30 +843,43 @@ impl<'a> LookupContext<'a> {
mutbls: &[ast::Mutability],
mk_autoref_ty: |ast::Mutability, ty::Region| -> ty::t)
-> Option<MethodCallee> {
// HACK(eddyb) only overloaded auto-deref calls should be missing
// adjustments, because we imply an AutoPtr adjustment for them.
let self_expr_id = match self.self_expr {
Some(expr) => Some(expr.id),
None => match kind(ty::ReEmpty, ast::MutImmutable) {
ty::AutoPtr(..) if autoderefs == 0 => None,
_ => return None
}
};
// This is hokey. We should have mutability inference as a
// variable. But for now, try &const, then &, then &mut:
let region =
self.infcx().next_region_var(
infer::Autoref(self.expr.span));
self.infcx().next_region_var(infer::Autoref(self.span));
for mutbl in mutbls.iter() {
let autoref_ty = mk_autoref_ty(*mutbl, region);
match self.search_for_method(autoref_ty) {
None => {}
Some(mme) => {
Some(method) => {
match self_expr_id {
Some(self_expr_id) => {
self.fcx.write_adjustment(
self.self_expr.id,
self_expr_id,
@ty::AutoDerefRef(ty::AutoDerefRef {
autoderefs: autoderefs,
autoref: Some(kind(region, *mutbl))}));
return Some(mme);
autoref: Some(kind(region, *mutbl))
}));
}
None => {}
}
return Some(method);
}
}
}
return None;
None
}
fn search_for_method(&self, rcvr_ty: ty::t)
-> Option<MethodCallee> {
fn search_for_method(&self, rcvr_ty: ty::t) -> Option<MethodCallee> {
debug!("search_for_method(rcvr_ty={})", self.ty_to_str(rcvr_ty));
let _indenter = indenter();
@ -900,9 +908,8 @@ impl<'a> LookupContext<'a> {
}
}
fn consider_candidates(&self,
rcvr_ty: ty::t,
candidates: &mut Vec<Candidate> )
fn consider_candidates(&self, rcvr_ty: ty::t,
candidates: &mut Vec<Candidate>)
-> Option<MethodCallee> {
// FIXME(pcwalton): Do we need to clone here?
let relevant_candidates: Vec<Candidate> =
@ -918,7 +925,7 @@ impl<'a> LookupContext<'a> {
if relevant_candidates.len() > 1 {
self.tcx().sess.span_err(
self.expr.span,
self.span,
"multiple applicable methods in scope");
for (idx, candidate) in relevant_candidates.iter().enumerate() {
self.report_candidate(idx, &candidate.origin);
@ -986,8 +993,7 @@ impl<'a> LookupContext<'a> {
let tcx = self.tcx();
debug!("confirm_candidate(expr={}, rcvr_ty={}, candidate={})",
self.expr.repr(tcx),
debug!("confirm_candidate(rcvr_ty={}, candidate={})",
self.ty_to_str(rcvr_ty),
candidate.repr(self.tcx()));
@ -1007,12 +1013,12 @@ impl<'a> LookupContext<'a> {
self.fcx.infcx().next_ty_vars(num_method_tps)
} else if num_method_tps == 0u {
tcx.sess.span_err(
self.expr.span,
self.span,
"this method does not take type parameters");
self.fcx.infcx().next_ty_vars(num_method_tps)
} else if num_supplied_tps != num_method_tps {
tcx.sess.span_err(
self.expr.span,
self.span,
"incorrect number of type \
parameters given for this method");
self.fcx.infcx().next_ty_vars(num_method_tps)
@ -1025,11 +1031,11 @@ impl<'a> LookupContext<'a> {
// FIXME -- permit users to manually specify lifetimes
let mut all_regions = match candidate.rcvr_substs.regions {
NonerasedRegions(ref v) => v.clone(),
ErasedRegions => tcx.sess.span_bug(self.expr.span, "ErasedRegions")
ErasedRegions => tcx.sess.span_bug(self.span, "ErasedRegions")
};
let m_regions =
self.fcx.infcx().region_vars_for_defs(
self.expr.span,
self.span,
candidate.method_ty.generics.region_param_defs.deref().as_slice());
for &r in m_regions.iter() {
all_regions.push(r);
@ -1077,7 +1083,7 @@ impl<'a> LookupContext<'a> {
let (_, fn_sig) = replace_late_bound_regions_in_fn_sig(
tcx, &fn_sig,
|br| self.fcx.infcx().next_region_var(
infer::LateBoundRegion(self.expr.span, br)));
infer::LateBoundRegion(self.span, br)));
let transformed_self_ty = *fn_sig.inputs.get(0);
let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {
sig: fn_sig,
@ -1091,7 +1097,8 @@ impl<'a> LookupContext<'a> {
// variables to unify etc). Since we checked beforehand, and
// nothing has changed in the meantime, this unification
// should never fail.
match self.fcx.mk_subty(false, infer::Misc(self.self_expr.span),
let span = self.self_expr.map_or(self.span, |e| e.span);
match self.fcx.mk_subty(false, infer::Misc(span),
rcvr_ty, transformed_self_ty) {
result::Ok(_) => {}
result::Err(_) => {
@ -1112,8 +1119,7 @@ impl<'a> LookupContext<'a> {
&self,
trait_def_id: ast::DefId,
rcvr_substs: &ty::substs,
method_ty: &ty::Method) -> ty::t
{
method_ty: &ty::Method) -> ty::t {
/*!
* This is a bit tricky. We have a match against a trait method
* being invoked on an object, and we want to generate the
@ -1140,7 +1146,7 @@ impl<'a> LookupContext<'a> {
tps: rcvr_substs.tps.clone()};
match method_ty.explicit_self {
ast::SelfStatic => {
self.bug(~"static method for object type receiver");
self.bug("static method for object type receiver");
}
ast::SelfValue => {
ty::mk_err() // error reported in `enforce_object_limitations()`
@ -1187,14 +1193,14 @@ impl<'a> LookupContext<'a> {
match candidate.method_ty.explicit_self {
ast::SelfStatic => { // reason (a) above
self.tcx().sess.span_err(
self.expr.span,
self.span,
"cannot call a method without a receiver \
through an object");
}
ast::SelfValue => { // reason (a) above
self.tcx().sess.span_err(
self.expr.span,
self.span,
"cannot call a method with a by-value receiver \
through an object");
}
@ -1206,7 +1212,7 @@ impl<'a> LookupContext<'a> {
let check_for_self_ty = |ty| {
if ty::type_has_self(ty) {
self.tcx().sess.span_err(
self.expr.span,
self.span,
"cannot call a method whose type contains a \
self-type through an object");
true
@ -1228,7 +1234,7 @@ impl<'a> LookupContext<'a> {
if candidate.method_ty.generics.has_type_params() { // reason (b) above
self.tcx().sess.span_err(
self.expr.span,
self.span,
"cannot call a generic method through an object");
}
}
@ -1253,7 +1259,7 @@ impl<'a> LookupContext<'a> {
}
if bad {
self.tcx().sess.span_err(self.expr.span,
self.tcx().sess.span_err(self.span,
"explicit call to destructor");
}
}
@ -1364,7 +1370,7 @@ impl<'a> LookupContext<'a> {
let span = if did.krate == ast::LOCAL_CRATE {
self.tcx().map.span(did.node)
} else {
self.expr.span
self.span
};
self.tcx().sess.span_note(
span,
@ -1375,7 +1381,7 @@ impl<'a> LookupContext<'a> {
fn report_param_candidate(&self, idx: uint, did: DefId) {
self.tcx().sess.span_note(
self.expr.span,
self.span,
format!("candidate \\#{} derives from the bound `{}`",
idx+1u,
ty::item_path_str(self.tcx(), did)));
@ -1383,7 +1389,7 @@ impl<'a> LookupContext<'a> {
fn report_trait_candidate(&self, idx: uint, did: DefId) {
self.tcx().sess.span_note(
self.expr.span,
self.span,
format!("candidate \\#{} derives from the type of the receiver, \
which is the trait `{}`",
idx+1u,
@ -1406,8 +1412,9 @@ impl<'a> LookupContext<'a> {
ty::item_path_str(self.tcx(), did)
}
fn bug(&self, s: ~str) -> ! {
self.tcx().sess.span_bug(self.self_expr.span, s)
fn bug(&self, s: &str) -> ! {
let span = self.self_expr.map_or(self.span, |e| e.span);
self.tcx().sess.span_bug(span, s)
}
}

View file

@ -99,19 +99,20 @@ use middle::typeck::check::method::{CheckTraitsAndInherentMethods};
use middle::typeck::check::method::{DontAutoderefReceiver};
use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
use middle::typeck::check::regionmanip::relate_free_regions;
use middle::typeck::check::vtable::{LocationInfo, VtableContext};
use middle::typeck::check::vtable::VtableContext;
use middle::typeck::CrateCtxt;
use middle::typeck::infer::{resolve_type, force_tvar};
use middle::typeck::infer;
use middle::typeck::rscope::RegionScope;
use middle::typeck::{lookup_def_ccx};
use middle::typeck::no_params;
use middle::typeck::{require_same_types, MethodMap, vtable_map};
use middle::typeck::{require_same_types, vtable_map};
use middle::typeck::{MethodCall, MethodMap};
use middle::lang_items::TypeIdLangItem;
use util::common::{block_query, indenter, loop_query};
use util::ppaux;
use util::ppaux::{UserString, Repr};
use util::nodemap::NodeMap;
use util::nodemap::{FnvHashMap, NodeMap};
use std::cell::{Cell, RefCell};
use collections::HashMap;
@ -266,7 +267,7 @@ impl Inherited {
node_types: RefCell::new(NodeMap::new()),
node_type_substs: RefCell::new(NodeMap::new()),
adjustments: RefCell::new(NodeMap::new()),
method_map: @RefCell::new(NodeMap::new()),
method_map: @RefCell::new(FnvHashMap::new()),
vtable_map: @RefCell::new(NodeMap::new()),
upvar_borrow_map: RefCell::new(HashMap::new()),
}
@ -1108,18 +1109,6 @@ impl FnCtxt {
}
}
pub fn method_ty(&self, id: ast::NodeId) -> ty::t {
match self.inh.method_map.borrow().get().find(&id) {
Some(method) => method.ty,
None => {
self.tcx().sess.bug(
format!("no method entry for node {}: {} in fcx {}",
id, self.tcx().map.node_to_str(id),
self.tag()));
}
}
}
pub fn node_ty_substs(&self, id: ast::NodeId) -> ty::substs {
match self.inh.node_type_substs.borrow().get().find(&id) {
Some(ts) => (*ts).clone(),
@ -1133,7 +1122,7 @@ impl FnCtxt {
}
pub fn method_ty_substs(&self, id: ast::NodeId) -> ty::substs {
match self.inh.method_map.borrow().get().find(&id) {
match self.inh.method_map.borrow().get().find(&MethodCall::expr(id)) {
Some(method) => method.substs.clone(),
None => {
self.tcx().sess.bug(
@ -1252,81 +1241,76 @@ pub enum LvaluePreference {
NoPreference
}
pub fn do_autoderef(fcx: @FnCtxt, sp: Span, t: ty::t) -> (ty::t, uint) {
pub fn autoderef<T>(fcx: @FnCtxt, sp: Span, t: ty::t,
expr_id: Option<ast::NodeId>,
mut lvalue_pref: LvaluePreference,
should_stop: |ty::t, uint| -> Option<T>)
-> (ty::t, uint, Option<T>) {
/*!
*
* Autoderefs the type `t` as many times as possible, returning
* a new type and a counter for how many times the type was
* deref'd. If the counter is non-zero, the receiver is responsible
* for inserting an AutoAdjustment record into `tcx.adjustments`
* Autoderefs the type `t` as many times as possible, returning a new type
* and an autoderef count. If the count is not zero, the receiver is
* responsible for inserting an AutoAdjustment record into `tcx.adjustments`
* so that trans/borrowck/etc know about this autoderef. */
let mut t1 = t;
let mut enum_dids = Vec::new();
let mut t = t;
let mut autoderefs = 0;
loop {
let sty = structure_of(fcx, sp, t1);
let resolved_t = structurally_resolved_type(fcx, sp, t);
// Some extra checks to detect weird cycles and so forth:
match *sty {
ty::ty_box(inner) | ty::ty_uniq(inner) => {
match ty::get(t1).sty {
match ty::get(resolved_t).sty {
ty::ty_box(_) | ty::ty_uniq(_) | ty::ty_rptr(_, _) => {
match ty::get(t).sty {
ty::ty_infer(ty::TyVar(v1)) => {
ty::occurs_check(fcx.ccx.tcx, sp, v1,
ty::mk_box(fcx.ccx.tcx, inner));
ty::occurs_check(fcx.ccx.tcx, sp, v1, resolved_t);
}
_ => ()
_ => {}
}
}
ty::ty_rptr(_, inner) => {
match ty::get(t1).sty {
ty::ty_infer(ty::TyVar(v1)) => {
ty::occurs_check(fcx.ccx.tcx, sp, v1,
ty::mk_box(fcx.ccx.tcx, inner.ty));
}
_ => ()
}
}
ty::ty_enum(ref did, _) => {
// Watch out for a type like `enum t = @t`. Such a
// type would otherwise infinitely auto-deref. Only
// autoderef loops during typeck (basically, this one
// and the loops in typeck::check::method) need to be
// concerned with this, as an error will be reported
// on the enum definition as well because the enum is
// not instantiable.
if enum_dids.contains(did) {
return (t1, autoderefs);
}
enum_dids.push(*did);
}
_ => { /*ok*/ }
}
match should_stop(resolved_t, autoderefs) {
Some(x) => return (resolved_t, autoderefs, Some(x)),
None => {}
}
// Otherwise, deref if type is derefable:
match ty::deref_sty(sty, false) {
let mt = match ty::deref(resolved_t, false) {
Some(mt) => Some(mt),
None => {
return (t1, autoderefs);
}
Some(mt) => {
autoderefs += 1;
t1 = mt.ty
}
let method_call =
expr_id.map(|id| MethodCall::autoderef(id, autoderefs as u32));
try_overloaded_deref(fcx, sp, method_call, None, resolved_t, lvalue_pref)
}
};
match mt {
Some(mt) => {
t = mt.ty;
if mt.mutbl == ast::MutImmutable {
lvalue_pref = NoPreference;
}
autoderefs += 1;
}
None => return (resolved_t, autoderefs, None)
}
}
}
fn try_overloaded_deref(fcx: @FnCtxt,
expr: &ast::Expr,
base_expr: &ast::Expr,
span: Span,
method_call: Option<MethodCall>,
base_expr: Option<&ast::Expr>,
base_ty: ty::t,
lvalue_pref: LvaluePreference)
-> Option<ty::mt> {
// Try DerefMut first, if preferred.
let method = match (lvalue_pref, fcx.tcx().lang_items.deref_mut_trait()) {
(PreferMutLvalue, Some(trait_did)) => {
method::lookup_in_trait(fcx, expr, base_expr, token::intern("deref_mut"),
trait_did, base_ty, [], DontAutoderefReceiver)
method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
token::intern("deref_mut"), trait_did,
base_ty, [], DontAutoderefReceiver)
}
_ => None
};
@ -1334,8 +1318,9 @@ fn try_overloaded_deref(fcx: @FnCtxt,
// Otherwise, fall back to Deref.
let method = match (method, fcx.tcx().lang_items.deref_trait()) {
(None, Some(trait_did)) => {
method::lookup_in_trait(fcx, expr, base_expr, token::intern("deref"),
trait_did, base_ty, [], DontAutoderefReceiver)
method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
token::intern("deref"), trait_did,
base_ty, [], DontAutoderefReceiver)
}
(method, _) => method
};
@ -1343,7 +1328,12 @@ fn try_overloaded_deref(fcx: @FnCtxt,
match method {
Some(method) => {
let ref_ty = ty::ty_fn_ret(method.ty);
fcx.inh.method_map.borrow_mut().get().insert(expr.id, method);
match method_call {
Some(method_call) => {
fcx.inh.method_map.borrow_mut().get().insert(method_call, method);
}
None => {}
}
ty::deref(ref_ty, true)
}
None => None
@ -1434,8 +1424,7 @@ fn check_expr_with_lvalue_pref(fcx: @FnCtxt, expr: &ast::Expr,
// would return ($0, $1) where $0 and $1 are freshly instantiated type
// variables.
pub fn impl_self_ty(vcx: &VtableContext,
location_info: &LocationInfo, // (potential) receiver for
// this impl
span: Span, // (potential) receiver for this impl
did: ast::DefId)
-> ty_param_substs_and_ty {
let tcx = vcx.tcx();
@ -1446,7 +1435,7 @@ pub fn impl_self_ty(vcx: &VtableContext,
ity.generics.region_param_defs(),
ity.ty);
let rps = vcx.infcx.region_vars_for_defs(location_info.span, rps);
let rps = vcx.infcx.region_vars_for_defs(span, rps);
let tps = vcx.infcx.next_ty_vars(n_tps);
let substs = substs {
@ -1921,7 +1910,8 @@ fn check_expr_with_unifier(fcx: @FnCtxt,
AutoderefReceiver) {
Some(method) => {
let method_ty = method.ty;
fcx.inh.method_map.borrow_mut().get().insert(expr.id, method);
let method_call = MethodCall::expr(expr.id);
fcx.inh.method_map.borrow_mut().get().insert(method_call, method);
method_ty
}
None => {
@ -2001,15 +1991,17 @@ fn check_expr_with_unifier(fcx: @FnCtxt,
unbound_method: ||) -> ty::t {
let method = match trait_did {
Some(trait_did) => {
method::lookup_in_trait(fcx, op_ex, args[0], opname, trait_did,
self_t, [], autoderef_receiver)
method::lookup_in_trait(fcx, op_ex.span, Some(&*args[0]), opname,
trait_did, self_t, [], autoderef_receiver)
}
None => None
};
match method {
Some(method) => {
let method_ty = method.ty;
fcx.inh.method_map.borrow_mut().get().insert(op_ex.id, method);
// HACK(eddyb) Fully qualified path to work around a resolve bug.
let method_call = ::middle::typeck::MethodCall::expr(op_ex.id);
fcx.inh.method_map.borrow_mut().get().insert(method_call, method);
check_method_argument_types(fcx, op_ex.span,
method_ty, op_ex,
args, DoDerefArgs)
@ -2293,32 +2285,28 @@ fn check_expr_with_unifier(fcx: @FnCtxt,
field: ast::Name,
tys: &[ast::P<ast::Ty>]) {
let tcx = fcx.ccx.tcx;
let bot = check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
let expr_t = structurally_resolved_type(fcx, expr.span,
fcx.expr_ty(base));
let (base_t, derefs) = do_autoderef(fcx, expr.span, expr_t);
match *structure_of(fcx, expr.span, base_t) {
// FIXME(eddyb) #12808 Integrate privacy into this auto-deref loop.
let (_, autoderefs, field_ty) =
autoderef(fcx, expr.span, expr_t, Some(base.id), lvalue_pref, |base_t, _| {
match ty::get(base_t).sty {
ty::ty_struct(base_id, ref substs) => {
// This is just for fields -- the same code handles
// methods in both classes and traits
// (1) verify that the class id actually has a field called
// field
debug!("class named {}", ppaux::ty_to_str(tcx, base_t));
let cls_items = ty::lookup_struct_fields(tcx, base_id);
match lookup_field_ty(tcx, base_id, cls_items.as_slice(),
field, &(*substs)) {
debug!("struct named {}", ppaux::ty_to_str(tcx, base_t));
let fields = ty::lookup_struct_fields(tcx, base_id);
lookup_field_ty(tcx, base_id, fields.as_slice(), field, &(*substs))
}
_ => None
}
});
match field_ty {
Some(field_ty) => {
// (2) look up what field's type is, and return it
fcx.write_ty(expr.id, field_ty);
fcx.write_autoderef_adjustment(base.id, derefs);
return bot;
fcx.write_autoderef_adjustment(base.id, autoderefs);
return;
}
None => ()
}
}
_ => ()
None => {}
}
let tps: Vec<ty::t> = tys.iter().map(|&ty| fcx.to_ty(ty)).collect();
@ -2738,8 +2726,9 @@ fn check_expr_with_unifier(fcx: @FnCtxt,
oprnd_t = structurally_resolved_type(fcx, expr.span, oprnd_t);
oprnd_t = match ty::deref(oprnd_t, true) {
Some(mt) => mt.ty,
None => match try_overloaded_deref(fcx, expr, oprnd,
oprnd_t, lvalue_pref) {
None => match try_overloaded_deref(fcx, expr.span,
Some(MethodCall::expr(expr.id)),
Some(&*oprnd), oprnd_t, lvalue_pref) {
Some(mt) => mt.ty,
None => {
let is_newtype = match ty::get(oprnd_t).sty {
@ -3175,19 +3164,27 @@ fn check_expr_with_unifier(fcx: @FnCtxt,
} else if ty::type_is_error(idx_t) || ty::type_is_bot(idx_t) {
fcx.write_ty(id, idx_t);
} else {
let (base_t, derefs) = do_autoderef(fcx, expr.span, raw_base_t);
let base_sty = structure_of(fcx, expr.span, base_t);
match ty::index_sty(base_sty) {
let (base_t, autoderefs, field_ty) =
autoderef(fcx, expr.span, raw_base_t, Some(base.id),
lvalue_pref, |base_t, _| ty::index(base_t));
match field_ty {
Some(mt) => {
require_integral(fcx, idx.span, idx_t);
fcx.write_ty(id, mt.ty);
fcx.write_autoderef_adjustment(base.id, derefs);
fcx.write_autoderef_adjustment(base.id, autoderefs);
}
None => {
let resolved = structurally_resolved_type(fcx,
expr.span,
raw_base_t);
let error_message = || {
let ret_ty = lookup_op_method(fcx,
expr,
resolved,
token::intern("index"),
tcx.lang_items.index_trait(),
[base, idx],
AutoderefReceiver,
|| {
fcx.type_error_message(expr.span,
|actual| {
format!("cannot index a value \
@ -3196,15 +3193,7 @@ fn check_expr_with_unifier(fcx: @FnCtxt,
},
base_t,
None);
};
let ret_ty = lookup_op_method(fcx,
expr,
resolved,
token::intern("index"),
tcx.lang_items.index_trait(),
[base, idx],
AutoderefReceiver,
error_message);
});
fcx.write_ty(id, ret_ty);
}
}

View file

@ -129,6 +129,7 @@ use middle::typeck::check::regionmanip::relate_nested_regions;
use middle::typeck::infer::resolve_and_force_all_but_regions;
use middle::typeck::infer::resolve_type;
use middle::typeck::infer;
use middle::typeck::MethodCall;
use middle::pat_util;
use util::ppaux::{ty_to_str, region_to_str, Repr};
@ -221,11 +222,17 @@ impl Rcx {
}
/// Try to resolve the type for the given node.
pub fn resolve_node_type(&mut self, id: ast::NodeId) -> ty::t {
fn resolve_node_type(&mut self, id: ast::NodeId) -> ty::t {
let t = self.fcx.node_ty(id);
self.resolve_type(t)
}
fn resolve_method_type(&mut self, method_call: MethodCall) -> Option<ty::t> {
let method_ty = self.fcx.inh.method_map.borrow().get()
.find(&method_call).map(|method| method.ty);
method_ty.map(|method_ty| self.resolve_type(method_ty))
}
/// Try to resolve the type for the given node.
pub fn resolve_expr_type_adjusted(&mut self, expr: &ast::Expr) -> ty::t {
let ty_unadjusted = self.resolve_node_type(expr.id);
@ -233,11 +240,9 @@ impl Rcx {
ty_unadjusted
} else {
let tcx = self.fcx.tcx();
let adjustment = {
let adjustments = self.fcx.inh.adjustments.borrow();
adjustments.get().find_copy(&expr.id)
};
ty::adjust_ty(tcx, expr.span, ty_unadjusted, adjustment)
let adjustment = self.fcx.inh.adjustments.borrow().get().find_copy(&expr.id);
ty::adjust_ty(tcx, expr.span, expr.id, ty_unadjusted, adjustment,
|method_call| self.resolve_method_type(method_call))
}
}
}
@ -252,10 +257,8 @@ impl<'a> mc::Typer for &'a mut Rcx {
if ty::type_is_error(t) {Err(())} else {Ok(t)}
}
fn node_method_ty(&mut self, id: ast::NodeId) -> Option<ty::t> {
self.fcx.inh.method_map.borrow().get().find(&id).map(|method| {
self.resolve_type(method.ty)
})
fn node_method_ty(&mut self, method_call: MethodCall) -> Option<ty::t> {
self.resolve_method_type(method_call)
}
fn adjustment(&mut self, id: ast::NodeId) -> Option<@ty::AutoAdjustment> {
@ -264,7 +267,7 @@ impl<'a> mc::Typer for &'a mut Rcx {
}
fn is_method_call(&mut self, id: ast::NodeId) -> bool {
self.fcx.inh.method_map.borrow().get().contains_key(&id)
self.fcx.inh.method_map.borrow().get().contains_key(&MethodCall::expr(id))
}
fn temporary_scope(&mut self, id: ast::NodeId) -> Option<ast::NodeId> {
@ -383,18 +386,14 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
debug!("regionck::visit_expr(e={}, repeating_scope={:?})",
expr.repr(rcx.fcx.tcx()), rcx.repeating_scope);
let has_method_map = rcx.fcx.inh.method_map.get().contains_key(&expr.id);
let method_call = MethodCall::expr(expr.id);
let has_method_map = rcx.fcx.inh.method_map.get().contains_key(&method_call);
// Check any autoderefs or autorefs that appear.
{
let adjustments = rcx.fcx.inh.adjustments.borrow();
let r = adjustments.get().find(&expr.id);
for &adjustment in r.iter() {
for &adjustment in rcx.fcx.inh.adjustments.borrow().get().find(&expr.id).iter() {
debug!("adjustment={:?}", adjustment);
match **adjustment {
ty::AutoDerefRef(
ty::AutoDerefRef {autoderefs: autoderefs, autoref: opt_autoref}) =>
{
ty::AutoDerefRef(ty::AutoDerefRef {autoderefs, autoref: opt_autoref}) => {
let expr_ty = rcx.resolve_node_type(expr.id);
constrain_derefs(rcx, expr, autoderefs, expr_ty);
for autoref in opt_autoref.iter() {
@ -431,7 +430,6 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
_ => {}
}
}
}
match expr.node {
ast::ExprCall(callee, ref args) => {
@ -488,7 +486,8 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
ast::ExprUnary(ast::UnDeref, base) => {
// For *a, the lifetime of a must enclose the deref
let base_ty = match rcx.fcx.inh.method_map.get().find(&expr.id) {
let method_call = MethodCall::expr(expr.id);
let base_ty = match rcx.fcx.inh.method_map.get().find(&method_call) {
Some(method) => {
constrain_call(rcx, None, expr, Some(base), [], true);
ty::ty_fn_ret(method.ty)
@ -769,7 +768,8 @@ fn constrain_call(rcx: &mut Rcx,
implicitly_ref_args);
let callee_ty = match fn_expr_id {
Some(id) => rcx.resolve_node_type(id),
None => rcx.resolve_type(rcx.fcx.method_ty(call_expr.id))
None => rcx.resolve_method_type(MethodCall::expr(call_expr.id))
.expect("call should have been to a method")
};
if ty::type_is_error(callee_ty) {
// Bail, as function type is unknown
@ -904,11 +904,9 @@ fn constrain_regions_in_type_of_node(
// is going to fail anyway, so just stop here and let typeck
// report errors later on in the writeback phase.
let ty0 = rcx.resolve_node_type(id);
let adjustment = {
let adjustments = rcx.fcx.inh.adjustments.borrow();
adjustments.get().find_copy(&id)
};
let ty = ty::adjust_ty(tcx, origin.span(), ty0, adjustment);
let adjustment = rcx.fcx.inh.adjustments.borrow().get().find_copy(&id);
let ty = ty::adjust_ty(tcx, origin.span(), id, ty0, adjustment,
|method_call| rcx.resolve_method_type(method_call));
debug!("constrain_regions_in_type_of_node(\
ty={}, ty0={}, id={}, minimum_lifetime={:?}, adjustment={:?})",
ty_to_str(tcx, ty), ty_to_str(tcx, ty0),

View file

@ -21,6 +21,7 @@ use middle::typeck::infer;
use middle::typeck::{vtable_origin, vtable_res, vtable_param_res};
use middle::typeck::{vtable_static, vtable_param, impl_res};
use middle::typeck::{param_numbered, param_self, param_index};
use middle::typeck::MethodCall;
use middle::subst::Subst;
use util::common::indenter;
use util::ppaux;
@ -62,15 +63,6 @@ use syntax::visit::Visitor;
// It may be better to do something more clever, like processing fully
// resolved types first.
/// Location info records the span and ID of the expression or item that is
/// responsible for this vtable instantiation. (This may not be an expression
/// if the vtable instantiation is being performed as part of "deriving".)
pub struct LocationInfo {
span: Span,
id: ast::NodeId
}
/// A vtable context includes an inference context, a crate context, and a
/// callback function to call in case of type error.
pub struct VtableContext<'a> {
@ -88,14 +80,14 @@ fn has_trait_bounds(type_param_defs: &[ty::TypeParameterDef]) -> bool {
}
fn lookup_vtables(vcx: &VtableContext,
location_info: &LocationInfo,
span: Span,
type_param_defs: &[ty::TypeParameterDef],
substs: &ty::substs,
is_early: bool) -> vtable_res {
debug!("lookup_vtables(location_info={:?}, \
debug!("lookup_vtables(span={:?}, \
type_param_defs={}, \
substs={}",
location_info,
span,
type_param_defs.repr(vcx.tcx()),
substs.repr(vcx.tcx()));
@ -105,18 +97,18 @@ fn lookup_vtables(vcx: &VtableContext,
substs.tps.rev_iter()
.zip(type_param_defs.rev_iter())
.map(|(ty, def)|
lookup_vtables_for_param(vcx, location_info, Some(substs),
lookup_vtables_for_param(vcx, span, Some(substs),
&*def.bounds, *ty, is_early))
.collect();
result.reverse();
assert_eq!(substs.tps.len(), result.len());
debug!("lookup_vtables result(\
location_info={:?}, \
span={:?}, \
type_param_defs={}, \
substs={}, \
result={})",
location_info,
span,
type_param_defs.repr(vcx.tcx()),
substs.repr(vcx.tcx()),
result.repr(vcx.tcx()));
@ -124,7 +116,7 @@ fn lookup_vtables(vcx: &VtableContext,
}
fn lookup_vtables_for_param(vcx: &VtableContext,
location_info: &LocationInfo,
span: Span,
// None for substs means the identity
substs: Option<&ty::substs>,
type_param_bounds: &ty::ParamBounds,
@ -155,11 +147,10 @@ fn lookup_vtables_for_param(vcx: &VtableContext,
debug!("after subst: {}", trait_ref.repr(tcx));
match lookup_vtable(vcx, location_info, ty, trait_ref, is_early) {
match lookup_vtable(vcx, span, ty, trait_ref, is_early) {
Some(vtable) => param_result.push(vtable),
None => {
vcx.tcx().sess.span_fatal(
location_info.span,
vcx.tcx().sess.span_fatal(span,
format!("failed to find an implementation of \
trait {} for {}",
vcx.infcx.trait_ref_to_str(trait_ref),
@ -170,11 +161,11 @@ fn lookup_vtables_for_param(vcx: &VtableContext,
});
debug!("lookup_vtables_for_param result(\
location_info={:?}, \
span={:?}, \
type_param_bounds={}, \
ty={}, \
result={})",
location_info,
span,
type_param_bounds.repr(vcx.tcx()),
ty.repr(vcx.tcx()),
param_result.repr(vcx.tcx()));
@ -183,10 +174,9 @@ fn lookup_vtables_for_param(vcx: &VtableContext,
}
fn relate_trait_refs(vcx: &VtableContext,
location_info: &LocationInfo,
span: Span,
act_trait_ref: @ty::TraitRef,
exp_trait_ref: @ty::TraitRef)
{
exp_trait_ref: @ty::TraitRef) {
/*!
*
* Checks that an implementation of `act_trait_ref` is suitable
@ -196,10 +186,9 @@ fn relate_trait_refs(vcx: &VtableContext,
match infer::mk_sub_trait_refs(vcx.infcx,
false,
infer::RelateTraitRefs(location_info.span),
infer::RelateTraitRefs(span),
act_trait_ref,
exp_trait_ref)
{
exp_trait_ref) {
result::Ok(()) => {} // Ok.
result::Err(ref err) => {
// There is an error, but we need to do some work to make
@ -215,8 +204,7 @@ fn relate_trait_refs(vcx: &VtableContext,
!ty::trait_ref_contains_error(&r_exp_trait_ref)
{
let tcx = vcx.tcx();
tcx.sess.span_err(
location_info.span,
tcx.sess.span_err(span,
format!("expected {}, but found {} ({})",
ppaux::trait_ref_to_str(tcx, &r_exp_trait_ref),
ppaux::trait_ref_to_str(tcx, &r_act_trait_ref),
@ -228,18 +216,17 @@ fn relate_trait_refs(vcx: &VtableContext,
// Look up the vtable implementing the trait `trait_ref` at type `t`
fn lookup_vtable(vcx: &VtableContext,
location_info: &LocationInfo,
span: Span,
ty: ty::t,
trait_ref: @ty::TraitRef,
is_early: bool)
-> Option<vtable_origin>
{
-> Option<vtable_origin> {
debug!("lookup_vtable(ty={}, trait_ref={})",
vcx.infcx.ty_to_str(ty),
vcx.infcx.trait_ref_to_str(trait_ref));
let _i = indenter();
let ty = match fixup_ty(vcx, location_info, ty, is_early) {
let ty = match fixup_ty(vcx, span, ty, is_early) {
Some(ty) => ty,
None => {
// fixup_ty can only fail if this is early resolution
@ -261,8 +248,7 @@ fn lookup_vtable(vcx: &VtableContext,
.get(n)
.trait_bounds
.as_slice();
lookup_vtable_from_bounds(vcx,
location_info,
lookup_vtable_from_bounds(vcx, span,
type_param_bounds,
param_numbered(n),
trait_ref)
@ -270,8 +256,7 @@ fn lookup_vtable(vcx: &VtableContext,
ty::ty_self(_) => {
let self_param_bound = vcx.param_env.self_param_bound.unwrap();
lookup_vtable_from_bounds(vcx,
location_info,
lookup_vtable_from_bounds(vcx, span,
[self_param_bound],
param_self,
trait_ref)
@ -285,14 +270,13 @@ fn lookup_vtable(vcx: &VtableContext,
// If we aren't a self type or param, or it was, but we didn't find it,
// do a search.
return search_for_vtable(vcx, location_info,
ty, trait_ref, is_early)
search_for_vtable(vcx, span, ty, trait_ref, is_early)
}
// Given a list of bounds on a type, search those bounds to see if any
// of them are the vtable we are looking for.
fn lookup_vtable_from_bounds(vcx: &VtableContext,
location_info: &LocationInfo,
span: Span,
bounds: &[@ty::TraitRef],
param: param_index,
trait_ref: @ty::TraitRef)
@ -306,10 +290,7 @@ fn lookup_vtable_from_bounds(vcx: &VtableContext,
bound_trait_ref.repr(vcx.tcx()));
if bound_trait_ref.def_id == trait_ref.def_id {
relate_trait_refs(vcx,
location_info,
bound_trait_ref,
trait_ref);
relate_trait_refs(vcx, span, bound_trait_ref, trait_ref);
let vtable = vtable_param(param, n_bound);
debug!("found param vtable: {:?}",
vtable);
@ -324,7 +305,7 @@ fn lookup_vtable_from_bounds(vcx: &VtableContext,
}
fn search_for_vtable(vcx: &VtableContext,
location_info: &LocationInfo,
span: Span,
ty: ty::t,
trait_ref: @ty::TraitRef,
is_early: bool)
@ -385,11 +366,10 @@ fn search_for_vtable(vcx: &VtableContext,
let ty::ty_param_substs_and_ty {
substs: substs,
ty: for_ty
} = impl_self_ty(vcx, location_info, im.did);
} = impl_self_ty(vcx, span, im.did);
match infer::mk_subty(vcx.infcx,
false,
infer::RelateSelfType(
location_info.span),
infer::RelateSelfType(span),
ty,
for_ty) {
result::Err(_) => continue,
@ -418,7 +398,7 @@ fn search_for_vtable(vcx: &VtableContext,
vcx.infcx.trait_ref_to_str(of_trait_ref));
let of_trait_ref = of_trait_ref.subst(tcx, &substs);
relate_trait_refs(vcx, location_info, of_trait_ref, trait_ref);
relate_trait_refs(vcx, span, of_trait_ref, trait_ref);
// Recall that trait_ref -- the trait type we're casting to --
@ -430,15 +410,14 @@ fn search_for_vtable(vcx: &VtableContext,
// process of looking up bounds might constrain some of them.
let im_generics =
ty::lookup_item_type(tcx, im.did).generics;
let subres = lookup_vtables(vcx, location_info,
let subres = lookup_vtables(vcx, span,
im_generics.type_param_defs(), &substs,
is_early);
// substs might contain type variables, so we call
// fixup_substs to resolve them.
let substs_f = match fixup_substs(vcx,
location_info,
let substs_f = match fixup_substs(vcx, span,
trait_ref.def_id,
substs,
is_early) {
@ -463,7 +442,7 @@ fn search_for_vtable(vcx: &VtableContext,
// I am a little confused about this, since it seems to be
// very similar to the relate_trait_refs we already do,
// but problems crop up if it is removed, so... -sully
connect_trait_tps(vcx, location_info, &substs_f, trait_ref, im.did);
connect_trait_tps(vcx, span, &substs_f, trait_ref, im.did);
// Finally, we register that we found a matching impl, and
// record the def ID of the impl as well as the resolved list
@ -476,9 +455,7 @@ fn search_for_vtable(vcx: &VtableContext,
1 => return Some(found.get(0).clone()),
_ => {
if !is_early {
vcx.tcx().sess.span_err(
location_info.span,
"multiple applicable methods in scope");
vcx.tcx().sess.span_err(span, "multiple applicable methods in scope");
}
return Some(found.get(0).clone());
}
@ -487,7 +464,7 @@ fn search_for_vtable(vcx: &VtableContext,
fn fixup_substs(vcx: &VtableContext,
location_info: &LocationInfo,
span: Span,
id: ast::DefId,
substs: ty::substs,
is_early: bool)
@ -499,7 +476,7 @@ fn fixup_substs(vcx: &VtableContext,
ty::RegionTraitStore(ty::ReStatic),
ast::MutImmutable,
ty::EmptyBuiltinBounds());
fixup_ty(vcx, location_info, t, is_early).map(|t_f| {
fixup_ty(vcx, span, t, is_early).map(|t_f| {
match ty::get(t_f).sty {
ty::ty_trait(_, ref substs_f, _, _, _) => (*substs_f).clone(),
_ => fail!("t_f should be a trait")
@ -508,7 +485,7 @@ fn fixup_substs(vcx: &VtableContext,
}
fn fixup_ty(vcx: &VtableContext,
location_info: &LocationInfo,
span: Span,
ty: ty::t,
is_early: bool)
-> Option<ty::t> {
@ -516,8 +493,7 @@ fn fixup_ty(vcx: &VtableContext,
match resolve_type(vcx.infcx, ty, resolve_and_force_all_but_regions) {
Ok(new_type) => Some(new_type),
Err(e) if !is_early => {
tcx.sess.span_fatal(
location_info.span,
tcx.sess.span_fatal(span,
format!("cannot determine a type \
for this bounded type parameter: {}",
fixup_err_to_str(e)))
@ -529,7 +505,7 @@ fn fixup_ty(vcx: &VtableContext,
}
fn connect_trait_tps(vcx: &VtableContext,
location_info: &LocationInfo,
span: Span,
impl_substs: &ty::substs,
trait_ref: @ty::TraitRef,
impl_did: ast::DefId) {
@ -537,12 +513,12 @@ fn connect_trait_tps(vcx: &VtableContext,
let impl_trait_ref = match ty::impl_trait_ref(tcx, impl_did) {
Some(t) => t,
None => vcx.tcx().sess.span_bug(location_info.span,
None => vcx.tcx().sess.span_bug(span,
"connect_trait_tps invoked on a type impl")
};
let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs);
relate_trait_refs(vcx, location_info, impl_trait_ref, trait_ref);
relate_trait_refs(vcx, span, impl_trait_ref, trait_ref);
}
fn insert_vtables(fcx: &FnCtxt, expr_id: ast::NodeId, vtables: vtable_res) {
@ -551,19 +527,6 @@ fn insert_vtables(fcx: &FnCtxt, expr_id: ast::NodeId, vtables: vtable_res) {
fcx.inh.vtable_map.borrow_mut().get().insert(expr_id, vtables);
}
pub fn location_info_for_expr(expr: &ast::Expr) -> LocationInfo {
LocationInfo {
span: expr.span,
id: expr.id
}
}
pub fn location_info_for_item(item: &ast::Item) -> LocationInfo {
LocationInfo {
span: item.span,
id: item.id
}
}
pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
debug!("vtable: early_resolve_expr() ex with id {:?} (early: {}): {}",
ex.id, is_early, expr_to_str(ex));
@ -608,8 +571,6 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
_ => fail!("shouldn't get here"),
};
let location_info =
&location_info_for_expr(ex);
let vcx = fcx.vtable_context();
let target_trait_ref = @ty::TraitRef {
def_id: target_def_id,
@ -626,7 +587,7 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
};
let vtables =
lookup_vtables_for_param(&vcx,
location_info,
ex.span,
None,
&param_bounds,
typ,
@ -687,7 +648,7 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
debug!("early_resolve_expr: looking up vtables for type params {}",
item_ty.generics.type_param_defs().repr(fcx.tcx()));
let vcx = fcx.vtable_context();
let vtbls = lookup_vtables(&vcx, &location_info_for_expr(ex),
let vtbls = lookup_vtables(&vcx, ex.span,
item_ty.generics.type_param_defs(),
substs, is_early);
if !is_early {
@ -704,7 +665,7 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
ast::ExprAssignOp(_, _, _) |
ast::ExprIndex(_, _) |
ast::ExprMethodCall(_, _, _) => {
match fcx.inh.method_map.borrow().get().find(&ex.id) {
match fcx.inh.method_map.borrow().get().find(&MethodCall::expr(ex.id)) {
Some(method) => {
debug!("vtable resolution on parameter bounds for method call {}",
ex.repr(fcx.tcx()));
@ -712,7 +673,7 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
if has_trait_bounds(type_param_defs.deref().as_slice()) {
let substs = fcx.method_ty_substs(ex.id);
let vcx = fcx.vtable_context();
let vtbls = lookup_vtables(&vcx, &location_info_for_expr(ex),
let vtbls = lookup_vtables(&vcx, ex.span,
type_param_defs.deref()
.as_slice(),
&substs, is_early);
@ -782,13 +743,11 @@ pub fn resolve_impl(tcx: ty::ctxt,
let infcx = &infer::new_infer_ctxt(tcx);
let vcx = VtableContext { infcx: infcx, param_env: &param_env };
let loc_info = location_info_for_item(impl_item);
// First, check that the impl implements any trait bounds
// on the trait.
let trait_def = ty::lookup_trait_def(tcx, impl_trait_ref.def_id);
let vtbls = lookup_vtables(&vcx,
&loc_info,
let vtbls = lookup_vtables(&vcx, impl_item.span,
trait_def.generics.type_param_defs(),
&impl_trait_ref.substs,
false);
@ -808,7 +767,7 @@ pub fn resolve_impl(tcx: ty::ctxt,
// We will need to make one so we can use this information
// for compiling default methods that refer to supertraits.
let self_vtable_res =
lookup_vtables_for_param(&vcx, &loc_info, None,
lookup_vtables_for_param(&vcx, impl_item.span, None,
&param_bounds, t, false);
@ -833,13 +792,9 @@ pub fn trans_resolve_method(tcx: ty::ctxt, id: ast::NodeId,
infcx: &infer::new_infer_ctxt(tcx),
param_env: &ty::construct_parameter_environment(tcx, None, [], [], [], [], id)
};
let loc_info = LocationInfo {
id: id,
span: tcx.map.span(id)
};
Some(lookup_vtables(&vcx,
&loc_info,
tcx.map.span(id),
type_param_defs.as_slice(),
substs,
false))

View file

@ -20,7 +20,7 @@ use middle::typeck::check::FnCtxt;
use middle::typeck::infer::{force_all, resolve_all, resolve_region};
use middle::typeck::infer::resolve_type;
use middle::typeck::infer;
use middle::typeck::MethodCallee;
use middle::typeck::{MethodCall, MethodCallee};
use middle::typeck::{vtable_res, vtable_origin};
use middle::typeck::{vtable_static, vtable_param};
use middle::typeck::write_substs_to_tcx;
@ -63,15 +63,15 @@ fn resolve_type_vars_in_types(fcx: @FnCtxt, sp: Span, tys: &[ty::t])
}).collect()
}
fn resolve_method_map_entry(wbcx: &mut WbCtxt, sp: Span, id: ast::NodeId) {
fn resolve_method_map_entry(wbcx: &mut WbCtxt, sp: Span, method_call: MethodCall) {
let fcx = wbcx.fcx;
let tcx = fcx.ccx.tcx;
// Resolve any method map entry
match fcx.inh.method_map.borrow().get().find(&id) {
match fcx.inh.method_map.borrow().get().find(&method_call) {
Some(method) => {
debug!("writeback::resolve_method_map_entry(id={:?}, entry={:?})",
id, method.repr(tcx));
debug!("writeback::resolve_method_map_entry(call={:?}, entry={:?})",
method_call, method.repr(tcx));
let method_ty = match resolve_type_vars_in_type(fcx, sp, method.ty) {
Some(t) => t,
None => {
@ -95,7 +95,7 @@ fn resolve_method_map_entry(wbcx: &mut WbCtxt, sp: Span, id: ast::NodeId) {
self_ty: None
}
};
fcx.ccx.method_map.borrow_mut().get().insert(id, new_method);
fcx.ccx.method_map.borrow_mut().get().insert(method_call, new_method);
}
None => {}
}
@ -142,10 +142,7 @@ fn resolve_type_vars_for_node(wbcx: &mut WbCtxt, sp: Span, id: ast::NodeId)
let tcx = fcx.ccx.tcx;
// Resolve any borrowings for the node with id `id`
let adjustment = {
let adjustments = fcx.inh.adjustments.borrow();
adjustments.get().find_copy(&id)
};
let adjustment = fcx.inh.adjustments.borrow().get().find_copy(&id);
match adjustment {
None => (),
@ -167,9 +164,7 @@ fn resolve_type_vars_for_node(wbcx: &mut WbCtxt, sp: Span, id: ast::NodeId)
// FIXME(eddyb) #2190 Allow only statically resolved
// bare functions to coerce to a closure to avoid
// constructing (slower) indirect call wrappers.
{
let def_map = tcx.def_map.borrow();
match def_map.get().find(&id) {
match tcx.def_map.borrow().get().find(&id) {
Some(&ast::DefFn(..)) |
Some(&ast::DefStaticMethod(..)) |
Some(&ast::DefVariant(..)) |
@ -177,20 +172,21 @@ fn resolve_type_vars_for_node(wbcx: &mut WbCtxt, sp: Span, id: ast::NodeId)
_ => tcx.sess.span_err(sp,
"cannot coerce non-statically resolved bare fn")
}
}
let resolved_adj = @ty::AutoAddEnv(r1, s);
debug!("Adjustments for node {}: {:?}",
id,
resolved_adj);
let mut adjustments = tcx.adjustments
.borrow_mut();
adjustments.get().insert(id, resolved_adj);
id, resolved_adj);
tcx.adjustments.borrow_mut().get().insert(id, resolved_adj);
}
}
}
ty::AutoDerefRef(adj) => {
for autoderef in range(0, adj.autoderefs) {
let method_call = MethodCall::autoderef(id, autoderef as u32);
resolve_method_map_entry(wbcx, sp, method_call);
}
let fixup_region = |r| {
match resolve_region(fcx.infcx(),
r,
@ -218,14 +214,12 @@ fn resolve_type_vars_for_node(wbcx: &mut WbCtxt, sp: Span, id: ast::NodeId)
autoref: resolved_autoref,
});
debug!("Adjustments for node {}: {:?}", id, resolved_adj);
let mut adjustments = tcx.adjustments.borrow_mut();
adjustments.get().insert(id, resolved_adj);
tcx.adjustments.borrow_mut().get().insert(id, resolved_adj);
}
ty::AutoObject(..) => {
debug!("Adjustments for node {}: {:?}", id, adjustment);
let mut adjustments = tcx.adjustments.borrow_mut();
adjustments.get().insert(id, adjustment);
tcx.adjustments.borrow_mut().get().insert(id, adjustment);
}
}
}
@ -280,7 +274,7 @@ fn visit_expr(e: &ast::Expr, wbcx: &mut WbCtxt) {
}
resolve_type_vars_for_node(wbcx, e.span, e.id);
resolve_method_map_entry(wbcx, e.span, e.id);
resolve_method_map_entry(wbcx, e.span, MethodCall::expr(e.id));
resolve_vtable_map_entry(wbcx.fcx, e.span, e.id);
match e.node {

View file

@ -68,7 +68,7 @@ use middle::ty;
use util::common::time;
use util::ppaux::Repr;
use util::ppaux;
use util::nodemap::{DefIdMap, NodeMap};
use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
use std::cell::RefCell;
use std::rc::Rc;
@ -149,9 +149,31 @@ pub struct MethodCallee {
substs: ty::substs
}
#[deriving(Clone, Eq, Hash)]
pub struct MethodCall {
expr_id: ast::NodeId,
autoderef: u32
}
impl MethodCall {
pub fn expr(id: ast::NodeId) -> MethodCall {
MethodCall {
expr_id: id,
autoderef: 0
}
}
pub fn autoderef(expr_id: ast::NodeId, autoderef: u32) -> MethodCall {
MethodCall {
expr_id: expr_id,
autoderef: 1 + autoderef
}
}
}
// maps from an expression id that corresponds to a method call to the details
// of the method to be invoked
pub type MethodMap = @RefCell<NodeMap<MethodCallee>>;
pub type MethodMap = @RefCell<FnvHashMap<MethodCall, MethodCallee>>;
pub type vtable_param_res = @Vec<vtable_origin> ;
// Resolutions for bounds of all parameters, left to right, for a given path.
@ -442,7 +464,7 @@ pub fn check_crate(tcx: ty::ctxt,
let time_passes = tcx.sess.time_passes();
let ccx = @CrateCtxt {
trait_map: trait_map,
method_map: @RefCell::new(NodeMap::new()),
method_map: @RefCell::new(FnvHashMap::new()),
vtable_map: @RefCell::new(NodeMap::new()),
tcx: tcx
};

View file

@ -16,9 +16,11 @@ use std::io;
use syntax::ast;
#[cfg(not(stage0))]
pub type NodeMap<T> = HashMap<ast::NodeId, T, FnvHasher>;
#[cfg(not(stage0))]
pub type DefIdMap<T> = HashMap<ast::DefId, T, FnvHasher>;
pub type FnvHashMap<K, V> = HashMap<K, V, FnvHasher>;
pub type NodeMap<T> = FnvHashMap<ast::NodeId, T>;
pub type DefIdMap<T> = FnvHashMap<ast::DefId, T>;
#[cfg(not(stage0))]
pub type NodeSet = HashSet<ast::NodeId, FnvHasher>;
#[cfg(not(stage0))]
@ -26,12 +28,23 @@ pub type DefIdSet = HashSet<ast::DefId, FnvHasher>;
// Hacks to get good names
#[cfg(not(stage0))]
pub mod NodeMap {
pub mod FnvHashMap {
use std::hash::Hash;
use collections::HashMap;
pub fn new<T>() -> super::NodeMap<T> {
pub fn new<K: Hash<super::FnvState> + Eq, V>() -> super::FnvHashMap<K, V> {
HashMap::with_hasher(super::FnvHasher)
}
}
pub mod NodeMap {
pub fn new<T>() -> super::NodeMap<T> {
super::FnvHashMap::new()
}
}
pub mod DefIdMap {
pub fn new<T>() -> super::DefIdMap<T> {
super::FnvHashMap::new()
}
}
#[cfg(not(stage0))]
pub mod NodeSet {
use collections::HashSet;
@ -40,13 +53,6 @@ pub mod NodeSet {
}
}
#[cfg(not(stage0))]
pub mod DefIdMap {
use collections::HashMap;
pub fn new<T>() -> super::DefIdMap<T> {
HashMap::with_hasher(super::FnvHasher)
}
}
#[cfg(not(stage0))]
pub mod DefIdSet {
use collections::HashSet;
pub fn new() -> super::DefIdSet {
@ -55,9 +61,8 @@ pub mod DefIdSet {
}
#[cfg(stage0)]
pub type NodeMap<T> = HashMap<ast::NodeId, T>;
#[cfg(stage0)]
pub type DefIdMap<T> = HashMap<ast::DefId, T>;
pub type FnvHashMap<K, V> = HashMap<K, V>;
#[cfg(stage0)]
pub type NodeSet = HashSet<ast::NodeId>;
#[cfg(stage0)]
@ -65,9 +70,10 @@ pub type DefIdSet = HashSet<ast::DefId>;
// Hacks to get good names
#[cfg(stage0)]
pub mod NodeMap {
pub mod FnvHashMap {
use std::hash::Hash;
use collections::HashMap;
pub fn new<T>() -> super::NodeMap<T> {
pub fn new<K: Hash + Eq, V>() -> super::FnvHashMap<K, V> {
HashMap::new()
}
}
@ -79,13 +85,6 @@ pub mod NodeSet {
}
}
#[cfg(stage0)]
pub mod DefIdMap {
use collections::HashMap;
pub fn new<T>() -> super::DefIdMap<T> {
HashMap::new()
}
}
#[cfg(stage0)]
pub mod DefIdSet {
use collections::HashSet;
pub fn new() -> super::DefIdSet {

View file

@ -0,0 +1,51 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::cell::RefCell;
use std::rc::Rc;
#[deriving(Eq, Show)]
struct Point {
x: int,
y: int
}
pub fn main() {
assert_eq!(Rc::new(5u).to_uint(), Some(5));
assert_eq!((~&~&Rc::new(~~&~5u)).to_uint(), Some(5));
let point = Rc::new(Point {x: 2, y: 4});
assert_eq!(point.x, 2);
assert_eq!(point.y, 4);
let i = Rc::new(RefCell::new(2));
let i_value = *i.borrow();
*i.borrow_mut() = 5;
assert_eq!((i_value, *i.borrow()), (2, 5));
let s = Rc::new(~"foo");
assert!(s.equiv(&("foo")));
assert_eq!(s.as_slice(), "foo");
let mut_s = Rc::new(RefCell::new(~"foo"));
mut_s.borrow_mut().push_str("bar");
// HACK assert_eq! would fail here because it stores the LHS and RHS in two locals.
assert!(mut_s.borrow().as_slice() == "foobar");
assert!(mut_s.borrow_mut().as_slice() == "foobar");
let p = Rc::new(RefCell::new(Point {x: 1, y: 2}));
p.borrow_mut().x = 3;
p.borrow_mut().y += 3;
assert_eq!(*p.borrow(), Point {x: 3, y: 5});
let v = Rc::new(RefCell::new(~[1, 2, 3]));
v.borrow_mut()[0] = 3;
v.borrow_mut()[1] += 3;
assert_eq!((v.borrow()[0], v.borrow()[1], v.borrow()[2]), (3, 5, 3));
}