parent
cdc18b96d6
commit
20b4e159ed
33 changed files with 876 additions and 926 deletions
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
};
|
||||
|
|
|
@ -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]) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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(..) |
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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,
|
||||
node: &N,
|
||||
base_cmt: cmt,
|
||||
deref_cnt: uint)
|
||||
-> cmt {
|
||||
let mt = match ty::deref(base_cmt.ty, true) {
|
||||
Some(mt) => mt,
|
||||
fn cat_deref<N:ast_node>(&mut self,
|
||||
node: &N,
|
||||
base_cmt: cmt,
|
||||
deref_cnt: uint)
|
||||
-> cmt {
|
||||
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,
|
||||
node: &N,
|
||||
base_cmt: cmt,
|
||||
deref_cnt: uint,
|
||||
deref_ty: ty::t)
|
||||
-> cmt {
|
||||
match deref_kind(self.tcx(), base_cmt.ty) {
|
||||
fn cat_deref_common<N:ast_node>(&mut self,
|
||||
node: &N,
|
||||
base_cmt: cmt,
|
||||
deref_cnt: uint,
|
||||
deref_ty: ty::t)
|
||||
-> cmt {
|
||||
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();
|
||||
@cmt_ {
|
||||
id:node.id(),
|
||||
span:node.span(),
|
||||
cat:cat_interior(base_cmt, interior),
|
||||
mutbl:m,
|
||||
ty:deref_ty
|
||||
}
|
||||
(base_cmt.mutbl.inherit(), cat_interior(base_cmt, interior))
|
||||
}
|
||||
};
|
||||
@cmt_ {
|
||||
id: node.id(),
|
||||
span: node.span(),
|
||||
cat: cat,
|
||||
mutbl: m,
|
||||
ty: deref_ty
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,40 +772,26 @@ 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) {
|
||||
None => {
|
||||
self.tcx.sess.span_bug(expr.span,
|
||||
"method call not in \
|
||||
method map");
|
||||
}
|
||||
Some(method) => {
|
||||
debug!("(privacy checking) checking impl method");
|
||||
self.check_method(expr.span, method.origin, ident);
|
||||
}
|
||||
}
|
||||
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 \
|
||||
method map");
|
||||
}
|
||||
Some(method) => {
|
||||
debug!("(privacy checking) checking impl method");
|
||||
self.check_method(expr.span, method.origin, ident);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
ast::ExprStruct(_, ref fields, _) => {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
|
|
|
@ -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;
|
||||
monomorphize_type(bcx, t)
|
||||
} else {
|
||||
node_id_type(bcx, ref_id)
|
||||
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)
|
||||
}
|
||||
};
|
||||
|
||||
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,
|
||||
arg_cleanup_scope,
|
||||
DontAutorefArg)
|
||||
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,
|
||||
arg_cleanup_scope,
|
||||
DontAutorefArg)
|
||||
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,
|
||||
arg_cleanup_scope,
|
||||
DoAutorefArg)
|
||||
trans_arg_datum(bcx, *arg_tys.get(1), rhs,
|
||||
arg_cleanup_scope,
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
op: ast::UnOp,
|
||||
sub_expr: &ast::Expr)
|
||||
-> DatumBlock<'a, 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)
|
||||
}
|
||||
let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
|
||||
deref_once(bcx, expr, datum, 0)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn trans_boxed_expr<'a>(bcx: &'a Block<'a>,
|
||||
|
@ -1451,41 +1429,43 @@ 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,
|
||||
op: ast::BinOp,
|
||||
lhs: &ast::Expr,
|
||||
rhs: &ast::Expr)
|
||||
-> DatumBlock<'a, Expr> {
|
||||
fn trans_binary<'a>(bcx: &'a Block<'a>,
|
||||
expr: &ast::Expr,
|
||||
op: ast::BinOp,
|
||||
lhs: &ast::Expr,
|
||||
rhs: &ast::Expr)
|
||||
-> DatumBlock<'a, Expr> {
|
||||
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>,
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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,50 +2700,23 @@ 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 {
|
||||
ty: typ,
|
||||
mutbl: ast::MutImmutable,
|
||||
})
|
||||
}
|
||||
|
||||
ty_rptr(_, mt) => {
|
||||
Some(mt)
|
||||
}
|
||||
|
||||
ty_ptr(mt) if explicit => {
|
||||
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),
|
||||
_ => 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 {
|
||||
ty_vec(mt, _) => Some(mt),
|
||||
ty_str(_) => Some(mt {ty: mk_u8(), mutbl: ast::MutImmutable}),
|
||||
_ => None
|
||||
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,20 +3267,17 @@ 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) {
|
||||
// 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.
|
||||
return match expr.node {
|
||||
ast::ExprAssignOp(..) => RvalueStmtExpr,
|
||||
ast::ExprUnary(ast::UnDeref, _) => LvalueExpr,
|
||||
_ => RvalueDpsExpr
|
||||
};
|
||||
}
|
||||
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.
|
||||
return match expr.node {
|
||||
ast::ExprAssignOp(..) => RvalueStmtExpr,
|
||||
ast::ExprUnary(ast::UnDeref, _) => LvalueExpr,
|
||||
_ => RvalueDpsExpr
|
||||
};
|
||||
}
|
||||
|
||||
match expr.node {
|
||||
|
|
|
@ -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,8 +572,8 @@ impl<'a> LookupContext<'a> {
|
|||
}
|
||||
|
||||
fn push_candidates_from_impl(&self,
|
||||
candidates: &mut Vec<Candidate> ,
|
||||
impl_info: &ty::Impl) {
|
||||
candidates: &mut Vec<Candidate>,
|
||||
impl_info: &ty::Impl) {
|
||||
{
|
||||
let mut impl_dups = self.impl_dups.borrow_mut();
|
||||
if !impl_dups.get().insert(impl_info.did) {
|
||||
|
@ -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),
|
||||
|
@ -638,28 +619,45 @@ impl<'a> LookupContext<'a> {
|
|||
// Candidate selection (see comment at start of file)
|
||||
|
||||
fn search_for_autoderefd_method(&self,
|
||||
self_ty: ty::t,
|
||||
autoderefs: uint)
|
||||
-> Option<MethodCallee> {
|
||||
let (self_ty, autoadjust) =
|
||||
self_ty: ty::t,
|
||||
autoderefs: uint)
|
||||
-> Option<MethodCallee> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn consider_reborrow(&self,
|
||||
self_ty: ty::t,
|
||||
autoderefs: uint)
|
||||
-> (ty::t, ty::AutoAdjustment) {
|
||||
self_ty: ty::t,
|
||||
autoderefs: uint)
|
||||
-> (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) => {
|
||||
self.fcx.write_adjustment(
|
||||
self.self_expr.id,
|
||||
@ty::AutoDerefRef(ty::AutoDerefRef {
|
||||
autoderefs: autoderefs,
|
||||
autoref: Some(kind(region, *mutbl))}));
|
||||
return Some(mme);
|
||||
Some(method) => {
|
||||
match self_expr_id {
|
||||
Some(self_expr_id) => {
|
||||
self.fcx.write_adjustment(
|
||||
self_expr_id,
|
||||
@ty::AutoDerefRef(ty::AutoDerefRef {
|
||||
autoderefs: autoderefs,
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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*/ }
|
||||
}
|
||||
|
||||
// Otherwise, deref if type is derefable:
|
||||
match ty::deref_sty(sty, false) {
|
||||
None => {
|
||||
return (t1, autoderefs);
|
||||
}
|
||||
Some(mt) => {
|
||||
autoderefs += 1;
|
||||
t1 = mt.ty
|
||||
}
|
||||
match should_stop(resolved_t, autoderefs) {
|
||||
Some(x) => return (resolved_t, autoderefs, Some(x)),
|
||||
None => {}
|
||||
}
|
||||
};
|
||||
|
||||
// Otherwise, deref if type is derefable:
|
||||
let mt = match ty::deref(resolved_t, false) {
|
||||
Some(mt) => Some(mt),
|
||||
None => {
|
||||
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) {
|
||||
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)) {
|
||||
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;
|
||||
}
|
||||
None => ()
|
||||
// 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) => {
|
||||
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) => {
|
||||
fcx.write_ty(expr.id, field_ty);
|
||||
fcx.write_autoderef_adjustment(base.id, autoderefs);
|
||||
return;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,53 +386,48 @@ 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() {
|
||||
debug!("adjustment={:?}", adjustment);
|
||||
match **adjustment {
|
||||
ty::AutoDerefRef(
|
||||
ty::AutoDerefRef {autoderefs: 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() {
|
||||
link_autoref(rcx, expr, autoderefs, autoref);
|
||||
for &adjustment in rcx.fcx.inh.adjustments.borrow().get().find(&expr.id).iter() {
|
||||
debug!("adjustment={:?}", adjustment);
|
||||
match **adjustment {
|
||||
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() {
|
||||
link_autoref(rcx, expr, autoderefs, autoref);
|
||||
|
||||
// Require that the resulting region encompasses
|
||||
// the current node.
|
||||
//
|
||||
// FIXME(#6268) remove to support nested method calls
|
||||
constrain_regions_in_type_of_node(
|
||||
rcx, expr.id, ty::ReScope(expr.id),
|
||||
infer::AutoBorrow(expr.span));
|
||||
}
|
||||
}
|
||||
ty::AutoObject(ast::BorrowedSigil, Some(trait_region), _, _, _, _) => {
|
||||
// Determine if we are casting `expr` to an trait
|
||||
// instance. If so, we have to be sure that the type of
|
||||
// the source obeys the trait's region bound.
|
||||
// Require that the resulting region encompasses
|
||||
// the current node.
|
||||
//
|
||||
// Note: there is a subtle point here concerning type
|
||||
// parameters. It is possible that the type of `source`
|
||||
// contains type parameters, which in turn may contain
|
||||
// regions that are not visible to us (only the caller
|
||||
// knows about them). The kind checker is ultimately
|
||||
// responsible for guaranteeing region safety in that
|
||||
// particular case. There is an extensive comment on the
|
||||
// function check_cast_for_escaping_regions() in kind.rs
|
||||
// explaining how it goes about doing that.
|
||||
|
||||
let source_ty = rcx.fcx.expr_ty(expr);
|
||||
constrain_regions_in_type(rcx, trait_region,
|
||||
infer::RelateObjectBound(expr.span), source_ty);
|
||||
// FIXME(#6268) remove to support nested method calls
|
||||
constrain_regions_in_type_of_node(
|
||||
rcx, expr.id, ty::ReScope(expr.id),
|
||||
infer::AutoBorrow(expr.span));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
ty::AutoObject(ast::BorrowedSigil, Some(trait_region), _, _, _, _) => {
|
||||
// Determine if we are casting `expr` to an trait
|
||||
// instance. If so, we have to be sure that the type of
|
||||
// the source obeys the trait's region bound.
|
||||
//
|
||||
// Note: there is a subtle point here concerning type
|
||||
// parameters. It is possible that the type of `source`
|
||||
// contains type parameters, which in turn may contain
|
||||
// regions that are not visible to us (only the caller
|
||||
// knows about them). The kind checker is ultimately
|
||||
// responsible for guaranteeing region safety in that
|
||||
// particular case. There is an extensive comment on the
|
||||
// function check_cast_for_escaping_regions() in kind.rs
|
||||
// explaining how it goes about doing that.
|
||||
|
||||
let source_ty = rcx.fcx.expr_ty(expr);
|
||||
constrain_regions_in_type(rcx, trait_region,
|
||||
infer::RelateObjectBound(expr.span), source_ty);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
|
|
|
@ -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),
|
||||
&*def.bounds, *ty, is_early))
|
||||
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,
|
||||
¶m_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: ¶m_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,
|
||||
¶m_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))
|
||||
|
|
|
@ -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,30 +164,29 @@ 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) {
|
||||
Some(&ast::DefFn(..)) |
|
||||
Some(&ast::DefStaticMethod(..)) |
|
||||
Some(&ast::DefVariant(..)) |
|
||||
Some(&ast::DefStruct(_)) => {}
|
||||
_ => tcx.sess.span_err(sp,
|
||||
"cannot coerce non-statically resolved bare fn")
|
||||
}
|
||||
match tcx.def_map.borrow().get().find(&id) {
|
||||
Some(&ast::DefFn(..)) |
|
||||
Some(&ast::DefStaticMethod(..)) |
|
||||
Some(&ast::DefVariant(..)) |
|
||||
Some(&ast::DefStruct(_)) => {}
|
||||
_ => 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 {
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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 {
|
||||
|
|
51
src/test/run-pass/overloaded-autoderef.rs
Normal file
51
src/test/run-pass/overloaded-autoderef.rs
Normal 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));
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue