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.
|
/// Convert a polar representation into a complex number.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_polar(r: &T, theta: &T) -> Cmplx<T> {
|
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,
|
use metadata::tydecode::{DefIdSource, NominalType, TypeWithId, TypeParameter,
|
||||||
RegionParameter};
|
RegionParameter};
|
||||||
use metadata::tyencode;
|
use metadata::tyencode;
|
||||||
use middle::typeck::{MethodCallee, MethodOrigin};
|
use middle::typeck::{MethodCall, MethodCallee, MethodOrigin};
|
||||||
use middle::{ty, typeck, moves};
|
use middle::{ty, typeck, moves};
|
||||||
use middle;
|
use middle;
|
||||||
use util::ppaux::ty_to_str;
|
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.tag(c::tag_table_method_map, |ebml_w| {
|
||||||
ebml_w.id(id);
|
ebml_w.id(id);
|
||||||
ebml_w.tag(c::tag_table_val, |ebml_w| {
|
ebml_w.tag(c::tag_table_val, |ebml_w| {
|
||||||
|
@ -1385,7 +1386,8 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext,
|
||||||
}
|
}
|
||||||
c::tag_table_method_map => {
|
c::tag_table_method_map => {
|
||||||
let method = val_dsr.read_method_callee(xcx);
|
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 => {
|
c::tag_table_vtable_map => {
|
||||||
let vtable_res =
|
let vtable_res =
|
||||||
|
|
|
@ -22,6 +22,7 @@ use mc = middle::mem_categorization;
|
||||||
use middle::borrowck::*;
|
use middle::borrowck::*;
|
||||||
use middle::moves;
|
use middle::moves;
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
|
use middle::typeck::MethodCall;
|
||||||
use std::vec_ng::Vec;
|
use std::vec_ng::Vec;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::ast_util;
|
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());
|
this.check_call(expr, None, expr.span, args.as_slice());
|
||||||
}
|
}
|
||||||
ast::ExprIndex(_, rval) | ast::ExprBinary(_, _, rval)
|
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]);
|
this.check_call(expr, None, expr.span, [rval]);
|
||||||
}
|
}
|
||||||
ast::ExprUnary(_, _) | ast::ExprIndex(_, _)
|
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, []);
|
this.check_call(expr, None, expr.span, []);
|
||||||
}
|
}
|
||||||
ast::ExprInlineAsm(ref ia) => {
|
ast::ExprInlineAsm(ref ia) => {
|
||||||
|
|
|
@ -23,6 +23,7 @@ use middle::moves;
|
||||||
use middle::pat_util;
|
use middle::pat_util;
|
||||||
use middle::ty::{ty_region};
|
use middle::ty::{ty_region};
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
|
use middle::typeck::MethodCall;
|
||||||
use util::common::indenter;
|
use util::common::indenter;
|
||||||
use util::ppaux::{Repr};
|
use util::ppaux::{Repr};
|
||||||
|
|
||||||
|
@ -242,7 +243,7 @@ fn gather_loans_in_expr(this: &mut GatherLoanCtxt,
|
||||||
|
|
||||||
ast::ExprIndex(_, arg) |
|
ast::ExprIndex(_, arg) |
|
||||||
ast::ExprBinary(_, _, 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.
|
// Arguments in method calls are always passed by ref.
|
||||||
//
|
//
|
||||||
// Currently these do not use adjustments, so we have to
|
// Currently these do not use adjustments, so we have to
|
||||||
|
|
|
@ -556,7 +556,8 @@ impl BorrowckCtxt {
|
||||||
move_data::MoveExpr => {
|
move_data::MoveExpr => {
|
||||||
let (expr_ty, expr_span) = match self.tcx.map.find(move.id) {
|
let (expr_ty, expr_span) = match self.tcx.map.find(move.id) {
|
||||||
Some(ast_map::NodeExpr(expr)) => {
|
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",
|
r => self.tcx.sess.bug(format!("MoveExpr({:?}) maps to {:?}, not Expr",
|
||||||
move.id, r))
|
move.id, r))
|
||||||
|
@ -582,7 +583,8 @@ impl BorrowckCtxt {
|
||||||
move_data::Captured => {
|
move_data::Captured => {
|
||||||
let (expr_ty, expr_span) = match self.tcx.map.find(move.id) {
|
let (expr_ty, expr_span) = match self.tcx.map.find(move.id) {
|
||||||
Some(ast_map::NodeExpr(expr)) => {
|
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",
|
r => self.tcx.sess.bug(format!("Captured({:?}) maps to {:?}, not Expr",
|
||||||
move.id, r))
|
move.id, r))
|
||||||
|
@ -922,8 +924,8 @@ impl mc::Typer for TcxTyper {
|
||||||
Ok(ty::node_id_to_type(self.tcx, id))
|
Ok(ty::node_id_to_type(self.tcx, id))
|
||||||
}
|
}
|
||||||
|
|
||||||
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> {
|
||||||
self.method_map.borrow().get().find(&id).map(|method| method.ty)
|
self.method_map.borrow().get().find(&method_call).map(|method| method.ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn adjustment(&mut self, id: ast::NodeId) -> Option<@ty::AutoAdjustment> {
|
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 {
|
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> {
|
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 {
|
fn is_method_call(&self, expr: &ast::Expr) -> bool {
|
||||||
let method_map = self.method_map.borrow();
|
let method_call = typeck::MethodCall::expr(expr.id);
|
||||||
method_map.get().contains_key(&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) => {}
|
ExprLit(lit) if ast_util::lit_is_str(lit) => {}
|
||||||
ExprBinary(..) | ExprUnary(..) => {
|
ExprBinary(..) | ExprUnary(..) => {
|
||||||
let method_map = method_map.borrow();
|
let method_call = typeck::MethodCall::expr(e.id);
|
||||||
if method_map.get().contains_key(&e.id) {
|
if method_map.borrow().get().contains_key(&method_call) {
|
||||||
sess.span_err(e.span, "user-defined operators are not \
|
sess.span_err(e.span, "user-defined operators are not \
|
||||||
allowed in constant expressions");
|
allowed in constant expressions");
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ use middle::astencode;
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::typeck::astconv;
|
use middle::typeck::astconv;
|
||||||
use middle;
|
use middle;
|
||||||
use util::nodemap::{DefIdMap, NodeMap};
|
use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
|
||||||
|
|
||||||
use syntax::ast::*;
|
use syntax::ast::*;
|
||||||
use syntax::parse::token::InternedString;
|
use syntax::parse::token::InternedString;
|
||||||
|
@ -136,7 +136,7 @@ pub fn lookup_variant_by_id(tcx: ty::ctxt,
|
||||||
}
|
}
|
||||||
let maps = astencode::Maps {
|
let maps = astencode::Maps {
|
||||||
root_map: @RefCell::new(HashMap::new()),
|
root_map: @RefCell::new(HashMap::new()),
|
||||||
method_map: @RefCell::new(NodeMap::new()),
|
method_map: @RefCell::new(FnvHashMap::new()),
|
||||||
vtable_map: @RefCell::new(NodeMap::new()),
|
vtable_map: @RefCell::new(NodeMap::new()),
|
||||||
capture_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 {
|
let maps = astencode::Maps {
|
||||||
root_map: @RefCell::new(HashMap::new()),
|
root_map: @RefCell::new(HashMap::new()),
|
||||||
method_map: @RefCell::new(NodeMap::new()),
|
method_map: @RefCell::new(FnvHashMap::new()),
|
||||||
vtable_map: @RefCell::new(NodeMap::new()),
|
vtable_map: @RefCell::new(NodeMap::new()),
|
||||||
capture_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 {
|
fn is_method_call(&self, expr: &ast::Expr) -> bool {
|
||||||
let method_map = self.dfcx.method_map.borrow();
|
let method_call = typeck::MethodCall::expr(expr.id);
|
||||||
method_map.get().contains_key(&expr.id)
|
self.dfcx.method_map.borrow().get().contains_key(&method_call)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset(&mut self, bits: &mut [uint]) {
|
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) {
|
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) => {
|
Some(method) => {
|
||||||
match method.origin {
|
match method.origin {
|
||||||
typeck::MethodStatic(def_id) => {
|
typeck::MethodStatic(def_id) => {
|
||||||
|
@ -179,7 +180,7 @@ impl Visitor<()> for MarkSymbolVisitor {
|
||||||
fn visit_expr(&mut self, expr: &ast::Expr, _: ()) {
|
fn visit_expr(&mut self, expr: &ast::Expr, _: ()) {
|
||||||
match expr.node {
|
match expr.node {
|
||||||
ast::ExprMethodCall(..) => {
|
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`.
|
/// `unsafe`.
|
||||||
|
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::typeck::MethodMap;
|
use middle::typeck::{MethodCall, MethodMap};
|
||||||
use util::ppaux;
|
use util::ppaux;
|
||||||
|
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
@ -138,7 +138,8 @@ impl Visitor<()> for EffectCheckVisitor {
|
||||||
fn visit_expr(&mut self, expr: &ast::Expr, _:()) {
|
fn visit_expr(&mut self, expr: &ast::Expr, _:()) {
|
||||||
match expr.node {
|
match expr.node {
|
||||||
ast::ExprMethodCall(_, _, _) => {
|
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 {}",
|
debug!("effect: method call case, base type is {}",
|
||||||
ppaux::ty_to_str(self.tcx, base_type));
|
ppaux::ty_to_str(self.tcx, base_type));
|
||||||
if type_is_unsafe_function(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
|
// Handle any kind bounds on type parameters
|
||||||
{
|
{
|
||||||
let method_map = cx.method_map.borrow();
|
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 node_type_substs = cx.tcx.node_type_substs.borrow();
|
||||||
let r = match method {
|
let r = match method {
|
||||||
Some(method) => Some(&method.substs.tps),
|
Some(method) => Some(&method.substs.tps),
|
||||||
|
@ -341,7 +341,8 @@ pub fn check_expr(cx: &mut Context, e: &Expr) {
|
||||||
match **adjustment {
|
match **adjustment {
|
||||||
ty::AutoObject(..) => {
|
ty::AutoObject(..) => {
|
||||||
let source_ty = ty::expr_ty(cx.tcx, e);
|
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);
|
check_trait_cast(cx, source_ty, target_ty, e.span);
|
||||||
}
|
}
|
||||||
ty::AutoAddEnv(..) |
|
ty::AutoAddEnv(..) |
|
||||||
|
|
|
@ -1491,7 +1491,8 @@ fn check_stability(cx: &Context, e: &ast::Expr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::ExprMethodCall(..) => {
|
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) => {
|
Some(method) => {
|
||||||
match method.origin {
|
match method.origin {
|
||||||
typeck::MethodStatic(def_id) => {
|
typeck::MethodStatic(def_id) => {
|
||||||
|
|
|
@ -63,6 +63,7 @@
|
||||||
#[allow(non_camel_case_types)];
|
#[allow(non_camel_case_types)];
|
||||||
|
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
|
use middle::typeck;
|
||||||
use util::ppaux::{ty_to_str, region_ptr_to_str, Repr};
|
use util::ppaux::{ty_to_str, region_ptr_to_str, Repr};
|
||||||
|
|
||||||
use std::vec_ng::Vec;
|
use std::vec_ng::Vec;
|
||||||
|
@ -268,7 +269,7 @@ pub type McResult<T> = Result<T, ()>;
|
||||||
pub trait Typer {
|
pub trait Typer {
|
||||||
fn tcx(&self) -> ty::ctxt;
|
fn tcx(&self) -> ty::ctxt;
|
||||||
fn node_ty(&mut self, id: ast::NodeId) -> McResult<ty::t>;
|
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 adjustment(&mut self, node_id: ast::NodeId) -> Option<@ty::AutoAdjustment>;
|
||||||
fn is_method_call(&mut self, id: ast::NodeId) -> bool;
|
fn is_method_call(&mut self, id: ast::NodeId) -> bool;
|
||||||
fn temporary_scope(&mut self, rvalue_id: ast::NodeId) -> Option<ast::NodeId>;
|
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> {
|
fn expr_ty_adjusted(&mut self, expr: &ast::Expr) -> McResult<ty::t> {
|
||||||
let unadjusted_ty = if_ok!(self.expr_ty(expr));
|
let unadjusted_ty = if_ok!(self.expr_ty(expr));
|
||||||
let adjustment = self.adjustment(expr.id);
|
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> {
|
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));
|
let expr_ty = if_ok!(self.expr_ty(expr));
|
||||||
match expr.node {
|
match expr.node {
|
||||||
ast::ExprUnary(ast::UnDeref, e_base) => {
|
ast::ExprUnary(ast::UnDeref, e_base) => {
|
||||||
let base_cmt = match self.typer.node_method_ty(expr.id) {
|
let base_cmt = if_ok!(self.cat_expr(e_base));
|
||||||
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))
|
|
||||||
};
|
|
||||||
Ok(self.cat_deref(expr, base_cmt, 0))
|
Ok(self.cat_deref(expr, base_cmt, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::ExprField(base, f_name, _) => {
|
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));
|
let base_cmt = if_ok!(self.cat_expr(base));
|
||||||
Ok(self.cat_field(expr, base_cmt, f_name, expr_ty))
|
Ok(self.cat_field(expr, base_cmt, f_name, expr_ty))
|
||||||
}
|
}
|
||||||
|
@ -725,59 +717,64 @@ impl<TYPER:Typer> MemCategorizationContext<TYPER> {
|
||||||
// `()` (the empty tuple).
|
// `()` (the empty tuple).
|
||||||
|
|
||||||
let opaque_ty = ty::mk_tup(self.tcx(), Vec::new());
|
let opaque_ty = ty::mk_tup(self.tcx(), Vec::new());
|
||||||
return self.cat_deref_common(node, base_cmt, deref_cnt, opaque_ty);
|
self.cat_deref_common(node, base_cmt, deref_cnt, opaque_ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cat_deref<N:ast_node>(&mut self,
|
fn cat_deref<N:ast_node>(&mut self,
|
||||||
node: &N,
|
node: &N,
|
||||||
base_cmt: cmt,
|
base_cmt: cmt,
|
||||||
deref_cnt: uint)
|
deref_cnt: uint)
|
||||||
-> cmt {
|
-> cmt {
|
||||||
let mt = match ty::deref(base_cmt.ty, true) {
|
let method_call = typeck::MethodCall {
|
||||||
Some(mt) => mt,
|
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 => {
|
None => {
|
||||||
self.tcx().sess.span_bug(
|
self.tcx().sess.span_bug(
|
||||||
node.span(),
|
node.span(),
|
||||||
format!("Explicit deref of non-derefable type: {}",
|
format!("Explicit deref of non-derefable type: {}",
|
||||||
base_cmt.ty.repr(self.tcx())));
|
base_cmt.ty.repr(self.tcx())));
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
return self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cat_deref_common<N:ast_node>(&mut self,
|
fn cat_deref_common<N:ast_node>(&mut self,
|
||||||
node: &N,
|
node: &N,
|
||||||
base_cmt: cmt,
|
base_cmt: cmt,
|
||||||
deref_cnt: uint,
|
deref_cnt: uint,
|
||||||
deref_ty: ty::t)
|
deref_ty: ty::t)
|
||||||
-> cmt {
|
-> cmt {
|
||||||
match deref_kind(self.tcx(), base_cmt.ty) {
|
let (m, cat) = match deref_kind(self.tcx(), base_cmt.ty) {
|
||||||
deref_ptr(ptr) => {
|
deref_ptr(ptr) => {
|
||||||
// for unique ptrs, we inherit mutability from the
|
// for unique ptrs, we inherit mutability from the
|
||||||
// owning reference.
|
// owning reference.
|
||||||
let m = MutabilityCategory::from_pointer_kind(base_cmt.mutbl,
|
(MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr),
|
||||||
ptr);
|
cat_deref(base_cmt, deref_cnt, ptr))
|
||||||
|
|
||||||
@cmt_ {
|
|
||||||
id:node.id(),
|
|
||||||
span:node.span(),
|
|
||||||
cat:cat_deref(base_cmt, deref_cnt, ptr),
|
|
||||||
mutbl:m,
|
|
||||||
ty:deref_ty
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
deref_interior(interior) => {
|
deref_interior(interior) => {
|
||||||
let m = base_cmt.mutbl.inherit();
|
(base_cmt.mutbl.inherit(), cat_interior(base_cmt, interior))
|
||||||
@cmt_ {
|
|
||||||
id:node.id(),
|
|
||||||
span:node.span(),
|
|
||||||
cat:cat_interior(base_cmt, interior),
|
|
||||||
mutbl:m,
|
|
||||||
ty:deref_ty
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
@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::pat_util::{pat_bindings};
|
||||||
use middle::freevars;
|
use middle::freevars;
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::typeck::MethodMap;
|
use middle::typeck::{MethodCall, MethodMap};
|
||||||
use util::ppaux;
|
use util::ppaux;
|
||||||
use util::ppaux::Repr;
|
use util::ppaux::Repr;
|
||||||
use util::common::indenter;
|
use util::common::indenter;
|
||||||
|
@ -281,12 +281,10 @@ impl VisitContext {
|
||||||
debug!("consume_expr(expr={})",
|
debug!("consume_expr(expr={})",
|
||||||
expr.repr(self.tcx));
|
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) {
|
if ty::type_moves_by_default(self.tcx, expr_ty) {
|
||||||
{
|
self.move_maps.moves_map.borrow_mut().get().insert(expr.id);
|
||||||
let mut moves_map = self.move_maps.moves_map.borrow_mut();
|
|
||||||
moves_map.get().insert(expr.id);
|
|
||||||
}
|
|
||||||
self.use_expr(expr, Move);
|
self.use_expr(expr, Move);
|
||||||
} else {
|
} else {
|
||||||
self.use_expr(expr, Read);
|
self.use_expr(expr, Read);
|
||||||
|
@ -608,8 +606,8 @@ impl VisitContext {
|
||||||
receiver_expr: @Expr,
|
receiver_expr: @Expr,
|
||||||
arg_exprs: &[@Expr])
|
arg_exprs: &[@Expr])
|
||||||
-> bool {
|
-> bool {
|
||||||
let method_map = self.method_map.borrow();
|
let method_call = MethodCall::expr(expr.id);
|
||||||
if !method_map.get().contains_key(&expr.id) {
|
if !self.method_map.borrow().get().contains_key(&method_call) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ use metadata::csearch;
|
||||||
use middle::lint;
|
use middle::lint;
|
||||||
use middle::resolve;
|
use middle::resolve;
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::typeck::{MethodMap, MethodOrigin, MethodParam};
|
use middle::typeck::{MethodCall, MethodMap, MethodOrigin, MethodParam};
|
||||||
use middle::typeck::{MethodStatic, MethodObject};
|
use middle::typeck::{MethodStatic, MethodObject};
|
||||||
use util::nodemap::{NodeMap, NodeSet};
|
use util::nodemap::{NodeMap, NodeSet};
|
||||||
|
|
||||||
|
@ -772,40 +772,26 @@ impl<'a> Visitor<()> for PrivacyVisitor<'a> {
|
||||||
fn visit_expr(&mut self, expr: &ast::Expr, _: ()) {
|
fn visit_expr(&mut self, expr: &ast::Expr, _: ()) {
|
||||||
match expr.node {
|
match expr.node {
|
||||||
ast::ExprField(base, ident, _) => {
|
ast::ExprField(base, ident, _) => {
|
||||||
// Method calls are now a special syntactic form,
|
match ty::get(ty::expr_ty_adjusted(self.tcx, base,
|
||||||
// so `a.b` should always be a field.
|
self.method_map.borrow().get())).sty {
|
||||||
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 {
|
|
||||||
ty::ty_struct(id, _) => {
|
ty::ty_struct(id, _) => {
|
||||||
self.check_field(expr.span, id, ident, None);
|
self.check_field(expr.span, id, ident, None);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::ExprMethodCall(ident, _, ref args) => {
|
ast::ExprMethodCall(ident, _, _) => {
|
||||||
// see above
|
let method_call = MethodCall::expr(expr.id);
|
||||||
let t = ty::type_autoderef(ty::expr_ty(self.tcx,
|
match self.method_map.borrow().get().find(&method_call) {
|
||||||
*args.get(0)));
|
None => {
|
||||||
match ty::get(t).sty {
|
self.tcx.sess.span_bug(expr.span,
|
||||||
ty::ty_enum(_, _) | ty::ty_struct(_, _) => {
|
"method call not in \
|
||||||
match self.method_map.borrow().get().find(&expr.id) {
|
method map");
|
||||||
None => {
|
}
|
||||||
self.tcx.sess.span_bug(expr.span,
|
Some(method) => {
|
||||||
"method call not in \
|
debug!("(privacy checking) checking impl method");
|
||||||
method map");
|
self.check_method(expr.span, method.origin, ident);
|
||||||
}
|
|
||||||
Some(method) => {
|
|
||||||
debug!("(privacy checking) checking impl method");
|
|
||||||
self.check_method(expr.span, method.origin, ident);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::ExprStruct(_, ref fields, _) => {
|
ast::ExprStruct(_, ref fields, _) => {
|
||||||
|
|
|
@ -149,24 +149,17 @@ impl Visitor<()> for MarkSymbolVisitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::ExprMethodCall(..) => {
|
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) => {
|
typeck::MethodStatic(def_id) => {
|
||||||
if is_local(def_id) {
|
if is_local(def_id) {
|
||||||
if ReachableContext::
|
if ReachableContext::
|
||||||
def_id_represents_local_inlined_item(
|
def_id_represents_local_inlined_item(
|
||||||
self.tcx,
|
self.tcx,
|
||||||
def_id) {
|
def_id) {
|
||||||
{
|
self.worklist.borrow_mut().get().push(def_id.node)
|
||||||
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.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)| {
|
let inputs = ia.inputs.map(|&(ref c, input)| {
|
||||||
constraints.push((*c).clone());
|
constraints.push((*c).clone());
|
||||||
|
|
||||||
|
let in_datum = unpack_datum!(bcx, expr::trans(bcx, input));
|
||||||
unpack_result!(bcx, {
|
unpack_result!(bcx, {
|
||||||
callee::trans_arg_expr(bcx,
|
callee::trans_arg_datum(bcx,
|
||||||
expr_ty(bcx, input),
|
expr_ty(bcx, input),
|
||||||
input,
|
in_datum,
|
||||||
cleanup::CustomScope(temp_scope),
|
cleanup::CustomScope(temp_scope),
|
||||||
callee::DontAutorefArg)
|
callee::DontAutorefArg)
|
||||||
})
|
})
|
||||||
|
|
|
@ -44,6 +44,7 @@ use middle::ty;
|
||||||
use middle::subst::Subst;
|
use middle::subst::Subst;
|
||||||
use middle::typeck;
|
use middle::typeck;
|
||||||
use middle::typeck::coherence::make_substs_for_receiver_types;
|
use middle::typeck::coherence::make_substs_for_receiver_types;
|
||||||
|
use middle::typeck::MethodCall;
|
||||||
use util::ppaux::Repr;
|
use util::ppaux::Repr;
|
||||||
|
|
||||||
use middle::trans::type_::Type;
|
use middle::trans::type_::Type;
|
||||||
|
@ -120,7 +121,7 @@ fn trans<'a>(bcx: &'a Block<'a>, expr: &ast::Expr) -> Callee<'a> {
|
||||||
match def {
|
match def {
|
||||||
ast::DefFn(did, _) |
|
ast::DefFn(did, _) |
|
||||||
ast::DefStaticMethod(did, ast::FromImpl(_), _) => {
|
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::DefStaticMethod(impl_did,
|
||||||
ast::FromTrait(trait_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(),
|
assert!(ty::enum_variant_with_id(bcx.tcx(),
|
||||||
tid,
|
tid,
|
||||||
vid).args.len() > 0u);
|
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) => {
|
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::DefStatic(..) |
|
||||||
ast::DefArg(..) |
|
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,
|
pub fn trans_fn_ref(bcx: &Block, def_id: ast::DefId, node: ExprOrMethodCall) -> ValueRef {
|
||||||
ref_id: ast::NodeId, is_method: bool)
|
|
||||||
-> ValueRef {
|
|
||||||
/*!
|
/*!
|
||||||
*
|
*
|
||||||
* Translates a reference (with id `ref_id`) to the fn/method
|
* 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 _icx = push_ctxt("trans_fn_ref");
|
||||||
|
|
||||||
let type_params = node_id_type_params(bcx, ref_id, is_method);
|
let type_params = node_id_type_params(bcx, node);
|
||||||
let vtables = node_vtables(bcx, ref_id);
|
let vtables = match node {
|
||||||
debug!("trans_fn_ref(def_id={}, ref_id={:?}, type_params={}, vtables={})",
|
ExprId(id) => node_vtables(bcx, id),
|
||||||
def_id.repr(bcx.tcx()), ref_id, type_params.repr(bcx.tcx()),
|
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()));
|
vtables.repr(bcx.tcx()));
|
||||||
trans_fn_ref_with_vtables(bcx,
|
trans_fn_ref_with_vtables(bcx, def_id, node,
|
||||||
def_id,
|
|
||||||
ref_id,
|
|
||||||
is_method,
|
|
||||||
type_params.as_slice(),
|
type_params.as_slice(),
|
||||||
vtables)
|
vtables)
|
||||||
}
|
}
|
||||||
|
@ -191,7 +193,7 @@ fn trans_fn_ref_with_vtables_to_callee<'a>(bcx: &'a Block<'a>,
|
||||||
vtables: Option<typeck::vtable_res>)
|
vtables: Option<typeck::vtable_res>)
|
||||||
-> Callee<'a> {
|
-> Callee<'a> {
|
||||||
Callee {bcx: bcx,
|
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))}
|
type_params, vtables))}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,8 +243,7 @@ fn resolve_default_method_vtables(bcx: &Block,
|
||||||
pub fn trans_fn_ref_with_vtables(
|
pub fn trans_fn_ref_with_vtables(
|
||||||
bcx: &Block, //
|
bcx: &Block, //
|
||||||
def_id: ast::DefId, // def id of fn
|
def_id: ast::DefId, // def id of fn
|
||||||
ref_id: ast::NodeId, // node id of use of fn; may be zero if N/A
|
node: ExprOrMethodCall, // node id of use of fn; may be zero if N/A
|
||||||
is_method: bool,
|
|
||||||
type_params: &[ty::t], // values for fn's ty params
|
type_params: &[ty::t], // values for fn's ty params
|
||||||
vtables: Option<typeck::vtable_res>) // vtables for the call
|
vtables: Option<typeck::vtable_res>) // vtables for the call
|
||||||
-> ValueRef {
|
-> ValueRef {
|
||||||
|
@ -254,7 +255,7 @@ pub fn trans_fn_ref_with_vtables(
|
||||||
*
|
*
|
||||||
* - `bcx`: the current block where the reference to the fn occurs
|
* - `bcx`: the current block where the reference to the fn occurs
|
||||||
* - `def_id`: def id of the fn or method item being referenced
|
* - `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
|
* 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.
|
* have the right type, so it must be cast before being used.
|
||||||
* - `type_params`: values for each of the fn/method's type parameters
|
* - `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 ccx = bcx.ccx();
|
||||||
let tcx = ccx.tcx;
|
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={})",
|
type_params={}, vtables={})",
|
||||||
bcx.to_str(),
|
bcx.to_str(),
|
||||||
def_id.repr(bcx.tcx()),
|
def_id.repr(bcx.tcx()),
|
||||||
ref_id,
|
node,
|
||||||
type_params.repr(bcx.tcx()),
|
type_params.repr(bcx.tcx()),
|
||||||
vtables.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.
|
// Should be either intra-crate or inlined.
|
||||||
assert_eq!(def_id.krate, ast::LOCAL_CRATE);
|
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) =
|
let (val, must_cast) =
|
||||||
monomorphize::monomorphic_fn(ccx, def_id, &substs,
|
monomorphize::monomorphic_fn(ccx, def_id, &substs,
|
||||||
vtables, self_vtables,
|
vtables, self_vtables,
|
||||||
Some(ref_id));
|
ref_id);
|
||||||
let mut val = val;
|
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
|
// Monotype of the REFERENCE to the function (type params
|
||||||
// are subst'd)
|
// are subst'd)
|
||||||
let ref_ty = if is_method {
|
let ref_ty = match node {
|
||||||
let t = bcx.ccx().maps.method_map.borrow().get().get(&ref_id).ty;
|
ExprId(id) => node_id_type(bcx, id),
|
||||||
monomorphize_type(bcx, t)
|
MethodCall(method_call) => {
|
||||||
} else {
|
let t = bcx.ccx().maps.method_map.borrow().get().get(&method_call).ty;
|
||||||
node_id_type(bcx, ref_id)
|
monomorphize_type(bcx, t)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
val = PointerCast(
|
val = PointerCast(
|
||||||
|
@ -472,13 +479,14 @@ pub fn trans_method_call<'a>(
|
||||||
-> &'a Block<'a> {
|
-> &'a Block<'a> {
|
||||||
let _icx = push_ctxt("trans_method_call");
|
let _icx = push_ctxt("trans_method_call");
|
||||||
debug!("trans_method_call(call_ex={})", call_ex.repr(bcx.tcx()));
|
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(
|
trans_call_inner(
|
||||||
bcx,
|
bcx,
|
||||||
Some(common::expr_info(call_ex)),
|
Some(common::expr_info(call_ex)),
|
||||||
monomorphize_type(bcx, method_ty),
|
monomorphize_type(bcx, method_ty),
|
||||||
|cx, arg_cleanup_scope| {
|
|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,
|
args,
|
||||||
Some(dest)).bcx
|
Some(dest)).bcx
|
||||||
|
@ -717,19 +725,16 @@ pub fn trans_call_inner<'a>(
|
||||||
assert!(dest.is_some());
|
assert!(dest.is_some());
|
||||||
|
|
||||||
let mut llargs = Vec::new();
|
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 {
|
let arg_tys = match args {
|
||||||
ArgExprs(a) => a.iter().map(|x| expr_ty(bcx, *x)).collect(),
|
ArgExprs(a) => a.iter().map(|x| expr_ty(bcx, *x)).collect(),
|
||||||
_ => fail!("expected arg exprs.")
|
_ => fail!("expected arg exprs.")
|
||||||
};
|
};
|
||||||
bcx = foreign::trans_native_call(bcx,
|
bcx = trans_args(bcx, args, callee_ty, &mut llargs,
|
||||||
callee_ty,
|
cleanup::CustomScope(arg_cleanup_scope), false);
|
||||||
llfn,
|
fcx.pop_custom_cleanup_scope(arg_cleanup_scope);
|
||||||
opt_llretslot.unwrap(),
|
bcx = foreign::trans_native_call(bcx, callee_ty,
|
||||||
llargs.as_slice(),
|
llfn, opt_llretslot.unwrap(),
|
||||||
arg_tys);
|
llargs.as_slice(), arg_tys);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the caller doesn't care about the result of this fn call,
|
// 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> {
|
pub enum CallArgs<'a> {
|
||||||
ArgExprs(&'a [@ast::Expr]),
|
ArgExprs(&'a [@ast::Expr]),
|
||||||
// HACK used only by trans_overloaded_op.
|
ArgOverloadedOp(Datum<Expr>, Option<(Datum<Expr>, ast::NodeId)>),
|
||||||
ArgAutorefSecond(&'a ast::Expr, Option<&'a ast::Expr>),
|
|
||||||
ArgVals(&'a [ValueRef])
|
ArgVals(&'a [ValueRef])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -778,40 +782,42 @@ fn trans_args<'a>(cx: &'a Block<'a>,
|
||||||
match args {
|
match args {
|
||||||
ArgExprs(arg_exprs) => {
|
ArgExprs(arg_exprs) => {
|
||||||
let num_formal_args = arg_tys.len();
|
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 {
|
if i == 0 && ignore_self {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let arg_ty = if i >= num_formal_args {
|
let arg_ty = if i >= num_formal_args {
|
||||||
assert!(variadic);
|
assert!(variadic);
|
||||||
expr_ty_adjusted(cx, *arg_expr)
|
expr_ty_adjusted(cx, arg_expr)
|
||||||
} else {
|
} else {
|
||||||
*arg_tys.get(i)
|
*arg_tys.get(i)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let arg_datum = unpack_datum!(bcx, expr::trans(bcx, arg_expr));
|
||||||
llargs.push(unpack_result!(bcx, {
|
llargs.push(unpack_result!(bcx, {
|
||||||
trans_arg_expr(bcx, arg_ty, *arg_expr,
|
trans_arg_datum(bcx, arg_ty, arg_datum,
|
||||||
arg_cleanup_scope,
|
arg_cleanup_scope,
|
||||||
DontAutorefArg)
|
DontAutorefArg)
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ArgAutorefSecond(arg_expr, arg2) => {
|
ArgOverloadedOp(lhs, rhs) => {
|
||||||
assert!(!variadic);
|
assert!(!variadic);
|
||||||
|
|
||||||
llargs.push(unpack_result!(bcx, {
|
llargs.push(unpack_result!(bcx, {
|
||||||
trans_arg_expr(bcx, *arg_tys.get(0), arg_expr,
|
trans_arg_datum(bcx, *arg_tys.get(0), lhs,
|
||||||
arg_cleanup_scope,
|
arg_cleanup_scope,
|
||||||
DontAutorefArg)
|
DontAutorefArg)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
match arg2 {
|
match rhs {
|
||||||
Some(arg2_expr) => {
|
Some((rhs, rhs_id)) => {
|
||||||
assert_eq!(arg_tys.len(), 2);
|
assert_eq!(arg_tys.len(), 2);
|
||||||
|
|
||||||
llargs.push(unpack_result!(bcx, {
|
llargs.push(unpack_result!(bcx, {
|
||||||
trans_arg_expr(bcx, *arg_tys.get(1), arg2_expr,
|
trans_arg_datum(bcx, *arg_tys.get(1), rhs,
|
||||||
arg_cleanup_scope,
|
arg_cleanup_scope,
|
||||||
DoAutorefArg)
|
DoAutorefArg(rhs_id))
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
None => assert_eq!(arg_tys.len(), 1)
|
None => assert_eq!(arg_tys.len(), 1)
|
||||||
|
@ -827,26 +833,23 @@ fn trans_args<'a>(cx: &'a Block<'a>,
|
||||||
|
|
||||||
pub enum AutorefArg {
|
pub enum AutorefArg {
|
||||||
DontAutorefArg,
|
DontAutorefArg,
|
||||||
DoAutorefArg
|
DoAutorefArg(ast::NodeId)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trans_arg_expr<'a>(
|
pub fn trans_arg_datum<'a>(
|
||||||
bcx: &'a Block<'a>,
|
bcx: &'a Block<'a>,
|
||||||
formal_arg_ty: ty::t,
|
formal_arg_ty: ty::t,
|
||||||
arg_expr: &ast::Expr,
|
arg_datum: Datum<Expr>,
|
||||||
arg_cleanup_scope: cleanup::ScopeId,
|
arg_cleanup_scope: cleanup::ScopeId,
|
||||||
autoref_arg: AutorefArg)
|
autoref_arg: AutorefArg)
|
||||||
-> Result<'a> {
|
-> Result<'a> {
|
||||||
let _icx = push_ctxt("trans_arg_expr");
|
let _icx = push_ctxt("trans_arg_datum");
|
||||||
let mut bcx = bcx;
|
let mut bcx = bcx;
|
||||||
let ccx = bcx.ccx();
|
let ccx = bcx.ccx();
|
||||||
|
|
||||||
debug!("trans_arg_expr(formal_arg_ty=({}), arg_expr={})",
|
debug!("trans_arg_datum({})",
|
||||||
formal_arg_ty.repr(bcx.tcx()),
|
formal_arg_ty.repr(bcx.tcx()));
|
||||||
arg_expr.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;
|
let arg_datum_ty = arg_datum.ty;
|
||||||
|
|
||||||
debug!(" arg datum: {}", arg_datum.to_str(bcx.ccx()));
|
debug!(" arg datum: {}", arg_datum.to_str(bcx.ccx()));
|
||||||
|
@ -864,11 +867,11 @@ pub fn trans_arg_expr<'a>(
|
||||||
} else {
|
} else {
|
||||||
// FIXME(#3548) use the adjustments table
|
// FIXME(#3548) use the adjustments table
|
||||||
match autoref_arg {
|
match autoref_arg {
|
||||||
DoAutorefArg => {
|
DoAutorefArg(arg_id) => {
|
||||||
// We will pass argument by reference
|
// We will pass argument by reference
|
||||||
// We want an lvalue, so that we can pass by reference and
|
// We want an lvalue, so that we can pass by reference and
|
||||||
let arg_datum = unpack_datum!(
|
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;
|
val = arg_datum.val;
|
||||||
}
|
}
|
||||||
DontAutorefArg => {
|
DontAutorefArg => {
|
||||||
|
@ -898,6 +901,6 @@ pub fn trans_arg_expr<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("--- trans_arg_expr passing {}", bcx.val_to_str(val));
|
debug!("--- trans_arg_datum passing {}", bcx.val_to_str(val));
|
||||||
return rslt(bcx, val);
|
rslt(bcx, val)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ use middle::trans::base;
|
||||||
use middle::trans::build;
|
use middle::trans::build;
|
||||||
use middle::trans::callee;
|
use middle::trans::callee;
|
||||||
use middle::trans::common;
|
use middle::trans::common;
|
||||||
use middle::trans::common::{Block, FunctionContext};
|
use middle::trans::common::{Block, FunctionContext, ExprId};
|
||||||
use middle::trans::glue;
|
use middle::trans::glue;
|
||||||
use middle::trans::type_::Type;
|
use middle::trans::type_::Type;
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
|
@ -673,7 +673,7 @@ impl<'a> CleanupHelperMethods<'a> for FunctionContext<'a> {
|
||||||
|
|
||||||
// The exception handling personality function.
|
// The exception handling personality function.
|
||||||
let def_id = common::langcall(pad_bcx, None, "", EhPersonalityLangItem);
|
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'
|
// The only landing pad clause will be 'cleanup'
|
||||||
let llretval = build::LandingPad(pad_bcx, llretty, llpersonality, 1u);
|
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 {
|
pub fn expr_ty_adjusted(bcx: &Block, ex: &ast::Expr) -> ty::t {
|
||||||
let tcx = bcx.tcx();
|
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)
|
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 tcx = bcx.tcx();
|
||||||
let params = if is_method {
|
let params = match node {
|
||||||
bcx.ccx().maps.method_map.borrow().get().get(&id).substs.tps.clone()
|
ExprId(id) => ty::node_id_to_type_params(tcx, id),
|
||||||
} else {
|
MethodCall(method_call) => {
|
||||||
ty::node_id_to_type_params(tcx, id)
|
bcx.ccx().maps.method_map.borrow().get().get(&method_call).substs.tps.clone()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if !params.iter().all(|t| !ty::type_needs_infer(*t)) {
|
if !params.iter().all(|t| !ty::type_needs_infer(*t)) {
|
||||||
bcx.sess().bug(
|
bcx.sess().bug(
|
||||||
format!("type parameters for node {} include inference types: {}",
|
format!("type parameters for node {:?} include inference types: {}",
|
||||||
id, params.map(|t| bcx.ty_to_str(*t)).connect(",")));
|
node, params.map(|t| bcx.ty_to_str(*t)).connect(",")));
|
||||||
}
|
}
|
||||||
|
|
||||||
match bcx.fcx.param_substs {
|
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 llconst = llconst;
|
||||||
let mut inlineable = inlineable;
|
let mut inlineable = inlineable;
|
||||||
let ety = ty::expr_ty(cx.tcx, e);
|
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 adjustment = {
|
||||||
let adjustments = cx.tcx.adjustments.borrow();
|
let adjustments = cx.tcx.adjustments.borrow();
|
||||||
adjustments.get().find_copy(&e.id)
|
adjustments.get().find_copy(&e.id)
|
||||||
|
@ -422,7 +423,8 @@ fn const_expr_unadjusted(cx: @CrateContext, e: &ast::Expr,
|
||||||
}, true)
|
}, true)
|
||||||
}
|
}
|
||||||
ast::ExprField(base, field, _) => {
|
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 brepr = adt::represent_type(cx, bt);
|
||||||
let (bv, inlineable) = const_expr(cx, base, is_local);
|
let (bv, inlineable) = const_expr(cx, base, is_local);
|
||||||
expr::with_field_tys(cx.tcx, bt, None, |discr, field_tys| {
|
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) => {
|
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 (bv, inlineable) = const_expr(cx, base, is_local);
|
||||||
let iv = match const_eval::eval_const_expr(cx.tcx, index) {
|
let iv = match const_eval::eval_const_expr(cx.tcx, index) {
|
||||||
const_eval::const_int(i) => i as u64,
|
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::{AutoBorrowObj, AutoDerefRef, AutoAddEnv, AutoObject, AutoUnsafe};
|
||||||
use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn};
|
use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn};
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
|
use middle::typeck::MethodCall;
|
||||||
use util::common::indenter;
|
use util::common::indenter;
|
||||||
use util::ppaux::Repr;
|
use util::ppaux::Repr;
|
||||||
use util::nodemap::NodeMap;
|
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))
|
unpack_datum!(bcx, auto_slice_and_ref(bcx, expr, datum))
|
||||||
}
|
}
|
||||||
Some(AutoBorrowFn(..)) => {
|
Some(AutoBorrowFn(..)) => {
|
||||||
let adjusted_ty = ty::adjust_ty(bcx.tcx(), expr.span,
|
let adjusted_ty = ty::adjust_ty(bcx.tcx(), expr.span, expr.id, datum.ty,
|
||||||
datum.ty, Some(adjustment));
|
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))
|
unpack_datum!(bcx, auto_borrow_fn(bcx, adjusted_ty, datum))
|
||||||
}
|
}
|
||||||
Some(AutoBorrowObj(..)) => {
|
Some(AutoBorrowObj(..)) => {
|
||||||
|
@ -221,7 +225,8 @@ fn apply_adjustments<'a>(bcx: &'a Block<'a>,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
AutoObject(..) => {
|
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");
|
let scratch = rvalue_scratch_datum(bcx, adjusted_ty, "__adjust");
|
||||||
bcx = meth::trans_trait_cast(
|
bcx = meth::trans_trait_cast(
|
||||||
bcx, datum, expr.id, SaveIn(scratch.val));
|
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()));
|
debug!("after adjustments, datum={}", datum.to_str(bcx.ccx()));
|
||||||
return DatumBlock {bcx: bcx, datum: datum};
|
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>(
|
fn auto_borrow_fn<'a>(
|
||||||
bcx: &'a Block<'a>,
|
bcx: &'a Block<'a>,
|
||||||
adjusted_ty: ty::t,
|
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::ExprLit(lit) => trans_immediate_lit(bcx, expr, (*lit).clone()),
|
||||||
ast::ExprBinary(op, lhs, rhs) => {
|
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)
|
trans_binary(bcx, expr, op, lhs, rhs)
|
||||||
}
|
}
|
||||||
ast::ExprUnary(op, x) => {
|
ast::ExprUnary(op, x) => {
|
||||||
trans_unary_datum(bcx, expr, op, x)
|
trans_unary(bcx, expr, op, x)
|
||||||
}
|
}
|
||||||
ast::ExprAddrOf(_, x) => {
|
ast::ExprAddrOf(_, x) => {
|
||||||
trans_addr_of(bcx, expr, 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) => {
|
ast::ExprBinary(_, lhs, rhs) => {
|
||||||
// if not overloaded, would be RvalueDatumExpr
|
// 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) => {
|
ast::ExprUnary(_, subexpr) => {
|
||||||
// if not overloaded, would be RvalueDatumExpr
|
// 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) => {
|
ast::ExprIndex(base, idx) => {
|
||||||
// if not overloaded, would be RvalueDatumExpr
|
// 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, _) => {
|
ast::ExprCast(val, _) => {
|
||||||
// DPS output mode means this is a trait cast:
|
// 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);
|
let variant_info = ty::enum_variant_with_id(ccx.tcx, tid, vid);
|
||||||
if variant_info.args.len() > 0u {
|
if variant_info.args.len() > 0u {
|
||||||
// N-ary variant.
|
// 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);
|
Store(bcx, llfn, lldest);
|
||||||
return bcx;
|
return bcx;
|
||||||
} else {
|
} else {
|
||||||
|
@ -888,7 +874,7 @@ fn trans_def_fn_unadjusted<'a>(bcx: &'a Block<'a>,
|
||||||
ast::DefFn(did, _) |
|
ast::DefFn(did, _) |
|
||||||
ast::DefStruct(did) | ast::DefVariant(_, did, _) |
|
ast::DefStruct(did) | ast::DefVariant(_, did, _) |
|
||||||
ast::DefStaticMethod(did, ast::FromImpl(_), _) => {
|
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), _) => {
|
ast::DefStaticMethod(impl_did, ast::FromTrait(trait_did), _) => {
|
||||||
meth::trans_static_method_callee(bcx, impl_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()
|
immediate_rvalue_bcx(bcx, v, ty).to_expr_datumblock()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trans_unary_datum<'a>(
|
fn trans_unary<'a>(bcx: &'a Block<'a>,
|
||||||
bcx: &'a Block<'a>,
|
expr: &ast::Expr,
|
||||||
un_expr: &ast::Expr,
|
op: ast::UnOp,
|
||||||
op: ast::UnOp,
|
sub_expr: &ast::Expr)
|
||||||
sub_expr: &ast::Expr)
|
-> DatumBlock<'a, Expr> {
|
||||||
-> DatumBlock<'a, Expr> {
|
|
||||||
let mut bcx = bcx;
|
let mut bcx = bcx;
|
||||||
let _icx = push_ctxt("trans_unary_datum");
|
let _icx = push_ctxt("trans_unary_datum");
|
||||||
|
|
||||||
let overloaded = {
|
let method_call = MethodCall::expr(expr.id);
|
||||||
let method_map = bcx.ccx().maps.method_map.borrow();
|
let overloaded = bcx.ccx().maps.method_map.borrow().get().contains_key(&method_call);
|
||||||
method_map.get().contains_key(&un_expr.id)
|
|
||||||
};
|
|
||||||
// if overloaded, would be RvalueDpsExpr
|
// if overloaded, would be RvalueDpsExpr
|
||||||
assert!(!overloaded || op == ast::UnDeref);
|
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 => {
|
ast::UnNot => {
|
||||||
let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
|
let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
|
||||||
let llresult = if ty::type_is_bool(un_ty) {
|
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)
|
trans_boxed_expr(bcx, un_ty, sub_expr, expr_ty(bcx, sub_expr), heap_exchange)
|
||||||
}
|
}
|
||||||
ast::UnDeref => {
|
ast::UnDeref => {
|
||||||
if overloaded {
|
let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
|
||||||
let r = trans_overloaded_op(bcx, un_expr, sub_expr, None, None);
|
deref_once(bcx, expr, datum, 0)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trans_boxed_expr<'a>(bcx: &'a Block<'a>,
|
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();
|
return immediate_rvalue_bcx(join, phi, binop_ty).to_expr_datumblock();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trans_binary<'a>(
|
fn trans_binary<'a>(bcx: &'a Block<'a>,
|
||||||
bcx: &'a Block<'a>,
|
expr: &ast::Expr,
|
||||||
binop_expr: &ast::Expr,
|
op: ast::BinOp,
|
||||||
op: ast::BinOp,
|
lhs: &ast::Expr,
|
||||||
lhs: &ast::Expr,
|
rhs: &ast::Expr)
|
||||||
rhs: &ast::Expr)
|
-> DatumBlock<'a, Expr> {
|
||||||
-> DatumBlock<'a, Expr> {
|
|
||||||
let _icx = push_ctxt("trans_binary");
|
let _icx = push_ctxt("trans_binary");
|
||||||
let ccx = bcx.ccx();
|
let ccx = bcx.ccx();
|
||||||
|
|
||||||
|
// if overloaded, would be RvalueDpsExpr
|
||||||
|
assert!(!ccx.maps.method_map.borrow().get().contains_key(&MethodCall::expr(expr.id)));
|
||||||
|
|
||||||
match op {
|
match op {
|
||||||
ast::BiAnd => {
|
ast::BiAnd => {
|
||||||
trans_lazy_binop(bcx, binop_expr, lazy_and, lhs, rhs)
|
trans_lazy_binop(bcx, expr, lazy_and, lhs, rhs)
|
||||||
}
|
}
|
||||||
ast::BiOr => {
|
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 mut bcx = bcx;
|
||||||
let lhs_datum = unpack_datum!(bcx, trans(bcx, lhs));
|
let lhs_datum = unpack_datum!(bcx, trans(bcx, lhs));
|
||||||
let rhs_datum = unpack_datum!(bcx, trans(bcx, rhs));
|
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={}",
|
debug!("trans_binary (expr {}): lhs_datum={}",
|
||||||
binop_expr.id,
|
expr.id,
|
||||||
lhs_datum.to_str(ccx));
|
lhs_datum.to_str(ccx));
|
||||||
let lhs_ty = lhs_datum.ty;
|
let lhs_ty = lhs_datum.ty;
|
||||||
let lhs = lhs_datum.to_llscalarish(bcx);
|
let lhs = lhs_datum.to_llscalarish(bcx);
|
||||||
|
|
||||||
debug!("trans_binary (expr {}): rhs_datum={}",
|
debug!("trans_binary (expr {}): rhs_datum={}",
|
||||||
binop_expr.id,
|
expr.id,
|
||||||
rhs_datum.to_str(ccx));
|
rhs_datum.to_str(ccx));
|
||||||
let rhs_ty = rhs_datum.ty;
|
let rhs_ty = rhs_datum.ty;
|
||||||
let rhs = rhs_datum.to_llscalarish(bcx);
|
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)
|
lhs_ty, lhs, rhs_ty, rhs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1494,21 +1474,22 @@ fn trans_binary<'a>(
|
||||||
fn trans_overloaded_op<'a, 'b>(
|
fn trans_overloaded_op<'a, 'b>(
|
||||||
bcx: &'a Block<'a>,
|
bcx: &'a Block<'a>,
|
||||||
expr: &ast::Expr,
|
expr: &ast::Expr,
|
||||||
rcvr: &'b ast::Expr,
|
method_call: MethodCall,
|
||||||
arg: Option<&'b ast::Expr>,
|
lhs: Datum<Expr>,
|
||||||
|
rhs: Option<(Datum<Expr>, ast::NodeId)>,
|
||||||
dest: Option<Dest>)
|
dest: Option<Dest>)
|
||||||
-> Result<'a> {
|
-> 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,
|
callee::trans_call_inner(bcx,
|
||||||
Some(expr_info(expr)),
|
Some(expr_info(expr)),
|
||||||
monomorphize_type(bcx, method_ty),
|
monomorphize_type(bcx, method_ty),
|
||||||
|bcx, arg_cleanup_scope| {
|
|bcx, arg_cleanup_scope| {
|
||||||
meth::trans_method_callee(bcx,
|
meth::trans_method_callee(bcx,
|
||||||
expr.id,
|
method_call,
|
||||||
rcvr,
|
None,
|
||||||
arg_cleanup_scope)
|
arg_cleanup_scope)
|
||||||
},
|
},
|
||||||
callee::ArgAutorefSecond(rcvr, arg),
|
callee::ArgOverloadedOp(lhs, rhs),
|
||||||
dest)
|
dest)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1666,10 +1647,7 @@ fn trans_assign_op<'a>(
|
||||||
debug!("trans_assign_op(expr={})", bcx.expr_to_str(expr));
|
debug!("trans_assign_op(expr={})", bcx.expr_to_str(expr));
|
||||||
|
|
||||||
// User-defined operator methods cannot be used with `+=` etc right now
|
// User-defined operator methods cannot be used with `+=` etc right now
|
||||||
assert!({
|
assert!(!bcx.ccx().maps.method_map.borrow().get().contains_key(&MethodCall::expr(expr.id)));
|
||||||
let method_map = bcx.ccx().maps.method_map.borrow();
|
|
||||||
!method_map.get().find(&expr.id).is_some()
|
|
||||||
});
|
|
||||||
|
|
||||||
// Evaluate LHS (destination), which should be an lvalue
|
// Evaluate LHS (destination), which should be an lvalue
|
||||||
let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op"));
|
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()
|
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>,
|
fn deref_multiple<'a>(bcx: &'a Block<'a>,
|
||||||
expr: &ast::Expr,
|
expr: &ast::Expr,
|
||||||
datum: Datum<Expr>,
|
datum: Datum<Expr>,
|
||||||
|
@ -1777,6 +1779,28 @@ fn deref_once<'a>(bcx: &'a Block<'a>,
|
||||||
|
|
||||||
let mut bcx = bcx;
|
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 {
|
let r = match ty::get(datum.ty).sty {
|
||||||
ty::ty_uniq(content_ty) => {
|
ty::ty_uniq(content_ty) => {
|
||||||
deref_owned_pointer(bcx, expr, datum, 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))
|
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(
|
bcx.tcx().sess.span_bug(
|
||||||
expr.span,
|
expr.span,
|
||||||
|
@ -1867,25 +1842,6 @@ fn deref_once<'a>(bcx: &'a Block<'a>,
|
||||||
|
|
||||||
return r;
|
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>,
|
fn deref_owned_pointer<'a>(bcx: &'a Block<'a>,
|
||||||
expr: &ast::Expr,
|
expr: &ast::Expr,
|
||||||
datum: Datum<Expr>,
|
datum: Datum<Expr>,
|
||||||
|
|
|
@ -29,6 +29,7 @@ use middle::trans::type_::Type;
|
||||||
use middle::trans::type_of::*;
|
use middle::trans::type_of::*;
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::typeck;
|
use middle::typeck;
|
||||||
|
use middle::typeck::MethodCall;
|
||||||
use util::common::indenter;
|
use util::common::indenter;
|
||||||
use util::ppaux::Repr;
|
use util::ppaux::Repr;
|
||||||
|
|
||||||
|
@ -93,21 +94,22 @@ pub fn trans_method(ccx: @CrateContext, method: &ast::Method,
|
||||||
|
|
||||||
pub fn trans_method_callee<'a>(
|
pub fn trans_method_callee<'a>(
|
||||||
bcx: &'a Block<'a>,
|
bcx: &'a Block<'a>,
|
||||||
expr_id: ast::NodeId,
|
method_call: MethodCall,
|
||||||
this: &ast::Expr,
|
self_expr: Option<&ast::Expr>,
|
||||||
arg_cleanup_scope: cleanup::ScopeId)
|
arg_cleanup_scope: cleanup::ScopeId)
|
||||||
-> Callee<'a> {
|
-> Callee<'a> {
|
||||||
let _icx = push_ctxt("meth::trans_method_callee");
|
let _icx = push_ctxt("meth::trans_method_callee");
|
||||||
|
|
||||||
let (origin, method_ty) = match bcx.ccx().maps.method_map
|
let (origin, method_ty) = match bcx.ccx().maps.method_map
|
||||||
.borrow().get().find(&expr_id) {
|
.borrow().get().find(&method_call) {
|
||||||
Some(method) => {
|
Some(method) => {
|
||||||
debug!("trans_method_callee(expr_id={:?}, method={})",
|
debug!("trans_method_callee({:?}, method={})",
|
||||||
expr_id, method.repr(bcx.tcx()));
|
method_call, method.repr(bcx.tcx()));
|
||||||
(method.origin, method.ty)
|
(method.origin, method.ty)
|
||||||
}
|
}
|
||||||
None => {
|
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) => {
|
typeck::MethodStatic(did) => {
|
||||||
Callee {
|
Callee {
|
||||||
bcx: bcx,
|
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 {
|
typeck::MethodParam(typeck::MethodParam {
|
||||||
|
@ -131,7 +133,7 @@ pub fn trans_method_callee<'a>(
|
||||||
trait_id);
|
trait_id);
|
||||||
|
|
||||||
let vtbl = find_vtable(bcx.tcx(), substs, p, b);
|
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)
|
trait_id, off, vtbl)
|
||||||
}
|
}
|
||||||
// how to get rid of this?
|
// how to get rid of this?
|
||||||
|
@ -140,10 +142,18 @@ pub fn trans_method_callee<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
typeck::MethodObject(ref mt) => {
|
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,
|
trans_trait_callee(bcx,
|
||||||
monomorphize_type(bcx, method_ty),
|
monomorphize_type(bcx, method_ty),
|
||||||
mt.real_index,
|
mt.real_index,
|
||||||
this,
|
self_expr,
|
||||||
arg_cleanup_scope)
|
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 mth_id = method_with_name(ccx, impl_did, mname);
|
||||||
let (callee_substs, callee_origins) =
|
let (callee_substs, callee_origins) =
|
||||||
combine_impl_and_methods_tps(
|
combine_impl_and_methods_tps(
|
||||||
bcx, mth_id, expr_id, false,
|
bcx, mth_id, ExprId(expr_id),
|
||||||
rcvr_substs.as_slice(), rcvr_origins);
|
rcvr_substs.as_slice(), rcvr_origins);
|
||||||
|
|
||||||
let llfn = trans_fn_ref_with_vtables(bcx,
|
let llfn = trans_fn_ref_with_vtables(bcx, mth_id, ExprId(expr_id),
|
||||||
mth_id,
|
|
||||||
expr_id,
|
|
||||||
false,
|
|
||||||
callee_substs.as_slice(),
|
callee_substs.as_slice(),
|
||||||
Some(callee_origins));
|
Some(callee_origins));
|
||||||
|
|
||||||
|
@ -254,7 +261,7 @@ pub fn method_with_name(ccx: &CrateContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trans_monomorphized_callee<'a>(bcx: &'a Block<'a>,
|
fn trans_monomorphized_callee<'a>(bcx: &'a Block<'a>,
|
||||||
expr_id: ast::NodeId,
|
method_call: MethodCall,
|
||||||
trait_id: ast::DefId,
|
trait_id: ast::DefId,
|
||||||
n_method: uint,
|
n_method: uint,
|
||||||
vtbl: typeck::vtable_origin)
|
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:
|
// those from the impl and those from the method:
|
||||||
let (callee_substs, callee_origins) =
|
let (callee_substs, callee_origins) =
|
||||||
combine_impl_and_methods_tps(
|
combine_impl_and_methods_tps(
|
||||||
bcx, mth_id, expr_id, true,
|
bcx, mth_id, MethodCall(method_call),
|
||||||
rcvr_substs.as_slice(), rcvr_origins);
|
rcvr_substs.as_slice(), rcvr_origins);
|
||||||
|
|
||||||
// translate the function
|
// translate the function
|
||||||
let llfn = trans_fn_ref_with_vtables(bcx,
|
let llfn = trans_fn_ref_with_vtables(bcx,
|
||||||
mth_id,
|
mth_id,
|
||||||
expr_id,
|
MethodCall(method_call),
|
||||||
true,
|
|
||||||
callee_substs.as_slice(),
|
callee_substs.as_slice(),
|
||||||
Some(callee_origins));
|
Some(callee_origins));
|
||||||
|
|
||||||
|
@ -291,8 +297,7 @@ fn trans_monomorphized_callee<'a>(bcx: &'a Block<'a>,
|
||||||
|
|
||||||
fn combine_impl_and_methods_tps(bcx: &Block,
|
fn combine_impl_and_methods_tps(bcx: &Block,
|
||||||
mth_did: ast::DefId,
|
mth_did: ast::DefId,
|
||||||
expr_id: ast::NodeId,
|
node: ExprOrMethodCall,
|
||||||
is_method: bool,
|
|
||||||
rcvr_substs: &[ty::t],
|
rcvr_substs: &[ty::t],
|
||||||
rcvr_origins: typeck::vtable_res)
|
rcvr_origins: typeck::vtable_res)
|
||||||
-> (Vec<ty::t> , 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 ccx = bcx.ccx();
|
||||||
let method = ty::method(ccx.tcx, mth_did);
|
let method = ty::method(ccx.tcx, mth_did);
|
||||||
let n_m_tps = method.generics.type_param_defs().len();
|
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));
|
debug!("rcvr_substs={:?}", rcvr_substs.repr(ccx.tcx));
|
||||||
let ty_substs
|
let ty_substs
|
||||||
= vec_ng::append(Vec::from_slice(rcvr_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
|
// Now, do the same work for the vtables. The vtables might not
|
||||||
// exist, in which case we need to make them.
|
// 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,
|
Some(vt) => vt,
|
||||||
None => @Vec::from_elem(node_substs.len(), @Vec::new())
|
None => @Vec::from_elem(node_substs.len(), @Vec::new())
|
||||||
};
|
};
|
||||||
|
@ -555,7 +567,7 @@ fn emit_vtable_methods(bcx: &Block,
|
||||||
token::get_ident(ident));
|
token::get_ident(ident));
|
||||||
C_null(Type::nil().ptr_to())
|
C_null(Type::nil().ptr_to())
|
||||||
} else {
|
} 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::ty;
|
||||||
use middle::subst::Subst;
|
use middle::subst::Subst;
|
||||||
use middle::typeck;
|
use middle::typeck;
|
||||||
|
use middle::typeck::{MethodCall, MethodCallee, MethodMap};
|
||||||
use middle::ty_fold;
|
use middle::ty_fold;
|
||||||
use middle::ty_fold::TypeFolder;
|
use middle::ty_fold::TypeFolder;
|
||||||
use middle;
|
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::{trait_store_to_str, ty_to_str, vstore_to_str};
|
||||||
use util::ppaux::{Repr, UserString};
|
use util::ppaux::{Repr, UserString};
|
||||||
use util::common::{indenter};
|
use util::common::{indenter};
|
||||||
use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
|
use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet, FnvHashMap};
|
||||||
|
|
||||||
use std::cast;
|
use std::cast;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
|
@ -258,10 +259,7 @@ pub struct ctxt_ {
|
||||||
diag: @syntax::diagnostic::SpanHandler,
|
diag: @syntax::diagnostic::SpanHandler,
|
||||||
// Specifically use a speedy hash algorithm for this hash map, it's used
|
// Specifically use a speedy hash algorithm for this hash map, it's used
|
||||||
// quite often.
|
// quite often.
|
||||||
#[cfg(stage0)]
|
interner: RefCell<FnvHashMap<intern_key, ~t_box_>>,
|
||||||
interner: RefCell<HashMap<intern_key, ~t_box_>>,
|
|
||||||
#[cfg(not(stage0))]
|
|
||||||
interner: RefCell<HashMap<intern_key, ~t_box_, ::util::nodemap::FnvHasher>>,
|
|
||||||
next_id: Cell<uint>,
|
next_id: Cell<uint>,
|
||||||
cstore: @metadata::cstore::CStore,
|
cstore: @metadata::cstore::CStore,
|
||||||
sess: session::Session,
|
sess: session::Session,
|
||||||
|
@ -1091,19 +1089,11 @@ pub fn mk_ctxt(s: session::Session,
|
||||||
region_maps: middle::region::RegionMaps,
|
region_maps: middle::region::RegionMaps,
|
||||||
lang_items: @middle::lang_items::LanguageItems)
|
lang_items: @middle::lang_items::LanguageItems)
|
||||||
-> ctxt {
|
-> 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_ {
|
@ctxt_ {
|
||||||
named_region_map: named_region_map,
|
named_region_map: named_region_map,
|
||||||
item_variance_map: RefCell::new(DefIdMap::new()),
|
item_variance_map: RefCell::new(DefIdMap::new()),
|
||||||
diag: s.diagnostic(),
|
diag: s.diagnostic(),
|
||||||
interner: RefCell::new(hasher()),
|
interner: RefCell::new(FnvHashMap::new()),
|
||||||
next_id: Cell::new(primitives::LAST_PRIMITIVE_ID),
|
next_id: Cell::new(primitives::LAST_PRIMITIVE_ID),
|
||||||
cstore: s.cstore,
|
cstore: s.cstore,
|
||||||
sess: s,
|
sess: s,
|
||||||
|
@ -2710,50 +2700,23 @@ pub fn type_param(ty: t) -> Option<uint> {
|
||||||
// The parameter `explicit` indicates if this is an *explicit* dereference.
|
// The parameter `explicit` indicates if this is an *explicit* dereference.
|
||||||
// Some types---notably unsafe ptrs---can only be dereferenced explicitly.
|
// Some types---notably unsafe ptrs---can only be dereferenced explicitly.
|
||||||
pub fn deref(t: t, explicit: bool) -> Option<mt> {
|
pub fn deref(t: t, explicit: bool) -> Option<mt> {
|
||||||
deref_sty(&get(t).sty, explicit)
|
match get(t).sty {
|
||||||
}
|
ty_box(typ) | ty_uniq(typ) => Some(mt {
|
||||||
|
ty: typ,
|
||||||
pub fn deref_sty(sty: &sty, explicit: bool) -> Option<mt> {
|
mutbl: ast::MutImmutable,
|
||||||
match *sty {
|
}),
|
||||||
ty_box(typ) | ty_uniq(typ) => {
|
ty_rptr(_, mt) => Some(mt),
|
||||||
Some(mt {
|
ty_ptr(mt) if explicit => Some(mt),
|
||||||
ty: typ,
|
|
||||||
mutbl: ast::MutImmutable,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
ty_rptr(_, mt) => {
|
|
||||||
Some(mt)
|
|
||||||
}
|
|
||||||
|
|
||||||
ty_ptr(mt) if explicit => {
|
|
||||||
Some(mt)
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => None
|
_ => 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]
|
// Returns the type and mutability of t[i]
|
||||||
pub fn index(t: t) -> Option<mt> {
|
pub fn index(t: t) -> Option<mt> {
|
||||||
index_sty(&get(t).sty)
|
match get(t).sty {
|
||||||
}
|
ty_vec(mt, _) => Some(mt),
|
||||||
|
ty_str(_) => Some(mt {ty: mk_u8(), mutbl: ast::MutImmutable}),
|
||||||
pub fn index_sty(sty: &sty) -> Option<mt> {
|
_ => None
|
||||||
match *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);
|
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`
|
* 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 unadjusted_ty = expr_ty(cx, expr);
|
||||||
let adjustment = {
|
let adjustment = cx.adjustments.borrow().get().find_copy(&expr.id);
|
||||||
let adjustments = cx.adjustments.borrow();
|
adjust_ty(cx, expr.span, expr.id, unadjusted_ty, adjustment, |method_call| {
|
||||||
adjustments.get().find_copy(&expr.id)
|
method_map.find(&method_call).map(|method| method.ty)
|
||||||
};
|
})
|
||||||
adjust_ty(cx, expr.span, unadjusted_ty, adjustment)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expr_span(cx: ctxt, id: NodeId) -> Span {
|
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,
|
pub fn adjust_ty(cx: ctxt,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
expr_id: ast::NodeId,
|
||||||
unadjusted_ty: ty::t,
|
unadjusted_ty: ty::t,
|
||||||
adjustment: Option<@AutoAdjustment>)
|
adjustment: Option<@AutoAdjustment>,
|
||||||
|
method_type: |MethodCall| -> Option<ty::t>)
|
||||||
-> ty::t {
|
-> ty::t {
|
||||||
/*! See `expr_ty_adjusted` */
|
/*! See `expr_ty_adjusted` */
|
||||||
|
|
||||||
return match adjustment {
|
return match adjustment {
|
||||||
None => unadjusted_ty,
|
|
||||||
|
|
||||||
Some(adjustment) => {
|
Some(adjustment) => {
|
||||||
match *adjustment {
|
match *adjustment {
|
||||||
AutoAddEnv(r, s) => {
|
AutoAddEnv(r, s) => {
|
||||||
|
@ -3062,7 +3027,13 @@ pub fn adjust_ty(cx: ctxt,
|
||||||
|
|
||||||
if !ty::type_is_error(adjusted_ty) {
|
if !ty::type_is_error(adjusted_ty) {
|
||||||
for i in range(0, adj.autoderefs) {
|
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; }
|
Some(mt) => { adjusted_ty = mt.ty; }
|
||||||
None => {
|
None => {
|
||||||
cx.sess.span_bug(
|
cx.sess.span_bug(
|
||||||
|
@ -3130,6 +3101,7 @@ pub fn adjust_ty(cx: ctxt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
None => unadjusted_ty
|
||||||
};
|
};
|
||||||
|
|
||||||
fn borrow_vec(cx: ctxt, span: Span,
|
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,
|
pub fn expr_is_lval(tcx: ctxt,
|
||||||
method_map: typeck::MethodMap,
|
method_map: MethodMap,
|
||||||
e: &ast::Expr) -> bool {
|
e: &ast::Expr) -> bool {
|
||||||
match expr_kind(tcx, method_map, e) {
|
match expr_kind(tcx, method_map, e) {
|
||||||
LvalueExpr => true,
|
LvalueExpr => true,
|
||||||
|
@ -3295,20 +3267,17 @@ pub enum ExprKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expr_kind(tcx: ctxt,
|
pub fn expr_kind(tcx: ctxt,
|
||||||
method_map: typeck::MethodMap,
|
method_map: MethodMap,
|
||||||
expr: &ast::Expr) -> ExprKind {
|
expr: &ast::Expr) -> ExprKind {
|
||||||
{
|
if method_map.borrow().get().contains_key(&MethodCall::expr(expr.id)) {
|
||||||
let method_map = method_map.borrow();
|
// Overloaded operations are generally calls, and hence they are
|
||||||
if method_map.get().contains_key(&expr.id) {
|
// generated via DPS. However, assign_op (e.g., `x += y`) is an
|
||||||
// Overloaded operations are generally calls, and hence they are
|
// exception, as its result is always unit.
|
||||||
// generated via DPS. However, assign_op (e.g., `x += y`) is an
|
return match expr.node {
|
||||||
// exception, as its result is always unit.
|
ast::ExprAssignOp(..) => RvalueStmtExpr,
|
||||||
return match expr.node {
|
ast::ExprUnary(ast::UnDeref, _) => LvalueExpr,
|
||||||
ast::ExprAssignOp(..) => RvalueStmtExpr,
|
_ => RvalueDpsExpr
|
||||||
ast::ExprUnary(ast::UnDeref, _) => LvalueExpr,
|
};
|
||||||
_ => RvalueDpsExpr
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match expr.node {
|
match expr.node {
|
||||||
|
|
|
@ -84,9 +84,7 @@ use middle::subst::Subst;
|
||||||
use middle::ty::*;
|
use middle::ty::*;
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::typeck::astconv::AstConv;
|
use middle::typeck::astconv::AstConv;
|
||||||
use middle::typeck::check::{FnCtxt, impl_self_ty};
|
use middle::typeck::check::{FnCtxt, PreferMutLvalue, impl_self_ty};
|
||||||
use middle::typeck::check::{structurally_resolved_type};
|
|
||||||
use middle::typeck::check::vtable;
|
|
||||||
use middle::typeck::check;
|
use middle::typeck::check;
|
||||||
use middle::typeck::infer;
|
use middle::typeck::infer;
|
||||||
use middle::typeck::MethodCallee;
|
use middle::typeck::MethodCallee;
|
||||||
|
@ -106,6 +104,7 @@ use syntax::ast::{DefId, SelfValue, SelfRegion};
|
||||||
use syntax::ast::{SelfUniq, SelfStatic};
|
use syntax::ast::{SelfUniq, SelfStatic};
|
||||||
use syntax::ast::{MutMutable, MutImmutable};
|
use syntax::ast::{MutMutable, MutImmutable};
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
use syntax::codemap::Span;
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
|
|
||||||
#[deriving(Eq)]
|
#[deriving(Eq)]
|
||||||
|
@ -120,23 +119,23 @@ pub enum AutoderefReceiverFlag {
|
||||||
DontAutoderefReceiver,
|
DontAutoderefReceiver,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lookup(
|
pub fn lookup<'a>(
|
||||||
fcx: @FnCtxt,
|
fcx: @FnCtxt,
|
||||||
|
|
||||||
// In a call `a.b::<X, Y, ...>(...)`:
|
// In a call `a.b::<X, Y, ...>(...)`:
|
||||||
expr: &ast::Expr, // The expression `a.b(...)`.
|
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`.
|
m_name: ast::Name, // The name `b`.
|
||||||
self_ty: ty::t, // The type of `a`.
|
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.
|
deref_args: check::DerefArgs, // Whether we autopointer first.
|
||||||
check_traits: CheckTraitsFlag, // Whether we check traits only.
|
check_traits: CheckTraitsFlag, // Whether we check traits only.
|
||||||
autoderef_receiver: AutoderefReceiverFlag)
|
autoderef_receiver: AutoderefReceiverFlag)
|
||||||
-> Option<MethodCallee> {
|
-> Option<MethodCallee> {
|
||||||
let lcx = LookupContext {
|
let lcx = LookupContext {
|
||||||
fcx: fcx,
|
fcx: fcx,
|
||||||
expr: expr,
|
span: expr.span,
|
||||||
self_expr: self_expr,
|
self_expr: Some(self_expr),
|
||||||
m_name: m_name,
|
m_name: m_name,
|
||||||
supplied_tps: supplied_tps,
|
supplied_tps: supplied_tps,
|
||||||
impl_dups: @RefCell::new(HashSet::new()),
|
impl_dups: @RefCell::new(HashSet::new()),
|
||||||
|
@ -147,7 +146,6 @@ pub fn lookup(
|
||||||
autoderef_receiver: autoderef_receiver,
|
autoderef_receiver: autoderef_receiver,
|
||||||
};
|
};
|
||||||
|
|
||||||
let self_ty = structurally_resolved_type(fcx, self_expr.span, self_ty);
|
|
||||||
debug!("method lookup(self_ty={}, expr={}, self_expr={})",
|
debug!("method lookup(self_ty={}, expr={}, self_expr={})",
|
||||||
self_ty.repr(fcx.tcx()), expr.repr(fcx.tcx()),
|
self_ty.repr(fcx.tcx()), expr.repr(fcx.tcx()),
|
||||||
self_expr.repr(fcx.tcx()));
|
self_expr.repr(fcx.tcx()));
|
||||||
|
@ -162,25 +160,25 @@ pub fn lookup(
|
||||||
debug!("searching extension candidates");
|
debug!("searching extension candidates");
|
||||||
lcx.reset_candidates();
|
lcx.reset_candidates();
|
||||||
lcx.push_bound_candidates(self_ty, None);
|
lcx.push_bound_candidates(self_ty, None);
|
||||||
lcx.push_extension_candidates();
|
lcx.push_extension_candidates(expr.id);
|
||||||
return lcx.search(self_ty);
|
return lcx.search(self_ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lookup_in_trait(
|
pub fn lookup_in_trait<'a>(
|
||||||
fcx: @FnCtxt,
|
fcx: @FnCtxt,
|
||||||
|
|
||||||
// In a call `a.b::<X, Y, ...>(...)`:
|
// In a call `a.b::<X, Y, ...>(...)`:
|
||||||
expr: &ast::Expr, // The expression `a.b(...)`.
|
span: Span, // The expression `a.b(...)`'s span.
|
||||||
self_expr: &ast::Expr, // The expression `a`.
|
self_expr: Option<&'a ast::Expr>, // The expression `a`, if available.
|
||||||
m_name: ast::Name, // The name `b`.
|
m_name: ast::Name, // The name `b`.
|
||||||
trait_did: DefId, // The trait to limit the lookup to.
|
trait_did: DefId, // The trait to limit the lookup to.
|
||||||
self_ty: ty::t, // The type of `a`.
|
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)
|
autoderef_receiver: AutoderefReceiverFlag)
|
||||||
-> Option<MethodCallee> {
|
-> Option<MethodCallee> {
|
||||||
let lcx = LookupContext {
|
let lcx = LookupContext {
|
||||||
fcx: fcx,
|
fcx: fcx,
|
||||||
expr: expr,
|
span: span,
|
||||||
self_expr: self_expr,
|
self_expr: self_expr,
|
||||||
m_name: m_name,
|
m_name: m_name,
|
||||||
supplied_tps: supplied_tps,
|
supplied_tps: supplied_tps,
|
||||||
|
@ -192,20 +190,18 @@ pub fn lookup_in_trait(
|
||||||
autoderef_receiver: autoderef_receiver,
|
autoderef_receiver: autoderef_receiver,
|
||||||
};
|
};
|
||||||
|
|
||||||
let self_ty = structurally_resolved_type(fcx, self_expr.span, self_ty);
|
debug!("method lookup_in_trait(self_ty={}, self_expr={})",
|
||||||
debug!("method lookup_in_trait(self_ty={}, expr={}, self_expr={})",
|
self_ty.repr(fcx.tcx()), self_expr.map(|e| e.repr(fcx.tcx())));
|
||||||
self_ty.repr(fcx.tcx()), expr.repr(fcx.tcx()),
|
|
||||||
self_expr.repr(fcx.tcx()));
|
|
||||||
|
|
||||||
lcx.push_bound_candidates(self_ty, Some(trait_did));
|
lcx.push_bound_candidates(self_ty, Some(trait_did));
|
||||||
lcx.push_extension_candidate(trait_did);
|
lcx.push_extension_candidate(trait_did);
|
||||||
lcx.search(self_ty)
|
lcx.search(self_ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LookupContext<'a> {
|
struct LookupContext<'a> {
|
||||||
fcx: @FnCtxt,
|
fcx: @FnCtxt,
|
||||||
expr: &'a ast::Expr,
|
span: Span,
|
||||||
self_expr: &'a ast::Expr,
|
self_expr: Option<&'a ast::Expr>,
|
||||||
m_name: ast::Name,
|
m_name: ast::Name,
|
||||||
supplied_tps: &'a [ty::t],
|
supplied_tps: &'a [ty::t],
|
||||||
impl_dups: @RefCell<HashSet<DefId>>,
|
impl_dups: @RefCell<HashSet<DefId>>,
|
||||||
|
@ -221,7 +217,7 @@ pub struct LookupContext<'a> {
|
||||||
* is of a suitable type.
|
* is of a suitable type.
|
||||||
*/
|
*/
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
pub struct Candidate {
|
struct Candidate {
|
||||||
rcvr_match_condition: RcvrMatchCondition,
|
rcvr_match_condition: RcvrMatchCondition,
|
||||||
rcvr_substs: ty::substs,
|
rcvr_substs: ty::substs,
|
||||||
method_ty: @ty::Method,
|
method_ty: @ty::Method,
|
||||||
|
@ -244,36 +240,35 @@ pub enum RcvrMatchCondition {
|
||||||
|
|
||||||
impl<'a> LookupContext<'a> {
|
impl<'a> LookupContext<'a> {
|
||||||
fn search(&self, self_ty: ty::t) -> Option<MethodCallee> {
|
fn search(&self, self_ty: ty::t) -> Option<MethodCallee> {
|
||||||
let mut self_ty = self_ty;
|
let span = self.self_expr.map_or(self.span, |e| e.span);
|
||||||
let mut autoderefs = 0;
|
let self_expr_id = self.self_expr.map(|e| e.id);
|
||||||
loop {
|
let (self_ty, autoderefs, result) =
|
||||||
|
check::autoderef(self.fcx, span, self_ty, self_expr_id,
|
||||||
|
PreferMutLvalue, |self_ty, autoderefs| {
|
||||||
|
|
||||||
debug!("loop: self_ty={} autoderefs={}",
|
debug!("loop: self_ty={} autoderefs={}",
|
||||||
self.ty_to_str(self_ty), autoderefs);
|
self.ty_to_str(self_ty), autoderefs);
|
||||||
|
|
||||||
match self.deref_args {
|
match self.deref_args {
|
||||||
check::DontDerefArgs => {
|
check::DontDerefArgs => {
|
||||||
match self.search_for_autoderefd_method(self_ty,
|
match self.search_for_autoderefd_method(self_ty, autoderefs) {
|
||||||
autoderefs) {
|
Some(result) => return Some(Some(result)),
|
||||||
Some(mme) => { return Some(mme); }
|
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.search_for_autoptrd_method(self_ty,
|
match self.search_for_autoptrd_method(self_ty, autoderefs) {
|
||||||
autoderefs) {
|
Some(result) => return Some(Some(result)),
|
||||||
Some(mme) => { return Some(mme); }
|
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
check::DoDerefArgs => {
|
check::DoDerefArgs => {
|
||||||
match self.search_for_autoptrd_method(self_ty,
|
match self.search_for_autoptrd_method(self_ty, autoderefs) {
|
||||||
autoderefs) {
|
Some(result) => return Some(Some(result)),
|
||||||
Some(mme) => { return Some(mme); }
|
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.search_for_autoderefd_method(self_ty,
|
match self.search_for_autoderefd_method(self_ty, autoderefs) {
|
||||||
autoderefs) {
|
Some(result) => return Some(Some(result)),
|
||||||
Some(mme) => { return Some(mme); }
|
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -281,30 +276,15 @@ impl<'a> LookupContext<'a> {
|
||||||
|
|
||||||
// Don't autoderef if we aren't supposed to.
|
// Don't autoderef if we aren't supposed to.
|
||||||
if self.autoderef_receiver == DontAutoderefReceiver {
|
if self.autoderef_receiver == DontAutoderefReceiver {
|
||||||
break;
|
Some(None)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Otherwise, perform autoderef.
|
match result {
|
||||||
match self.deref(self_ty) {
|
Some(Some(result)) => Some(result),
|
||||||
None => { break; }
|
_ => self.search_for_autosliced_method(self_ty, autoderefs)
|
||||||
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))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,8 +306,8 @@ impl<'a> LookupContext<'a> {
|
||||||
* we'll want to find the inherent impls for `C`.
|
* we'll want to find the inherent impls for `C`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let mut self_ty = self_ty;
|
let span = self.self_expr.map_or(self.span, |e| e.span);
|
||||||
loop {
|
check::autoderef(self.fcx, span, self_ty, None, PreferMutLvalue, |self_ty, _| {
|
||||||
match get(self_ty).sty {
|
match get(self_ty).sty {
|
||||||
ty_trait(did, ref substs, _, _, _) => {
|
ty_trait(did, ref substs, _, _, _) => {
|
||||||
self.push_inherent_candidates_from_object(did, substs);
|
self.push_inherent_candidates_from_object(did, substs);
|
||||||
|
@ -341,19 +321,18 @@ impl<'a> LookupContext<'a> {
|
||||||
_ => { /* No inherent methods in these types */ }
|
_ => { /* No inherent methods in these types */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
// n.b.: Generally speaking, we only loop if we hit the
|
// Don't autoderef if we aren't supposed to.
|
||||||
// fallthrough case in the match above. The exception
|
if self.autoderef_receiver == DontAutoderefReceiver {
|
||||||
// would be newtype enums.
|
Some(())
|
||||||
self_ty = match self.deref(self_ty) {
|
} else {
|
||||||
None => { return; }
|
None
|
||||||
Some(ty) => { ty }
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_bound_candidates(&self, self_ty: ty::t, restrict_to: Option<DefId>) {
|
fn push_bound_candidates(&self, self_ty: ty::t, restrict_to: Option<DefId>) {
|
||||||
let mut self_ty = self_ty;
|
let span = self.self_expr.map_or(self.span, |e| e.span);
|
||||||
loop {
|
check::autoderef(self.fcx, span, self_ty, None, PreferMutLvalue, |self_ty, _| {
|
||||||
match get(self_ty).sty {
|
match get(self_ty).sty {
|
||||||
ty_param(p) => {
|
ty_param(p) => {
|
||||||
self.push_inherent_candidates_from_param(self_ty, restrict_to, 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 */ }
|
_ => { /* No bound methods in these types */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
self_ty = match self.deref(self_ty) {
|
// Don't autoderef if we aren't supposed to.
|
||||||
None => { return; }
|
if self.autoderef_receiver == DontAutoderefReceiver {
|
||||||
Some(ty) => { ty }
|
Some(())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_extension_candidate(&self, trait_did: DefId) {
|
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
|
// If the method being called is associated with a trait, then
|
||||||
// find all the impls of that trait. Each of those are
|
// find all the impls of that trait. Each of those are
|
||||||
// candidates.
|
// 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 applicable_traits in opt_applicable_traits.move_iter() {
|
||||||
for trait_did in applicable_traits.iter() {
|
for trait_did in applicable_traits.iter() {
|
||||||
self.push_extension_candidate(*trait_did);
|
self.push_extension_candidate(*trait_did);
|
||||||
|
@ -591,8 +572,8 @@ impl<'a> LookupContext<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_candidates_from_impl(&self,
|
fn push_candidates_from_impl(&self,
|
||||||
candidates: &mut Vec<Candidate> ,
|
candidates: &mut Vec<Candidate>,
|
||||||
impl_info: &ty::Impl) {
|
impl_info: &ty::Impl) {
|
||||||
{
|
{
|
||||||
let mut impl_dups = self.impl_dups.borrow_mut();
|
let mut impl_dups = self.impl_dups.borrow_mut();
|
||||||
if !impl_dups.get().insert(impl_info.did) {
|
if !impl_dups.get().insert(impl_info.did) {
|
||||||
|
@ -619,12 +600,12 @@ impl<'a> LookupContext<'a> {
|
||||||
|
|
||||||
// determine the `self` of the impl with fresh
|
// determine the `self` of the impl with fresh
|
||||||
// variables for each parameter:
|
// 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 vcx = self.fcx.vtable_context();
|
||||||
let ty::ty_param_substs_and_ty {
|
let ty::ty_param_substs_and_ty {
|
||||||
substs: impl_substs,
|
substs: impl_substs,
|
||||||
ty: impl_ty
|
ty: impl_ty
|
||||||
} = impl_self_ty(&vcx, location_info, impl_info.did);
|
} = impl_self_ty(&vcx, span, impl_info.did);
|
||||||
|
|
||||||
candidates.push(Candidate {
|
candidates.push(Candidate {
|
||||||
rcvr_match_condition: RcvrMatchesIfSubtype(impl_ty),
|
rcvr_match_condition: RcvrMatchesIfSubtype(impl_ty),
|
||||||
|
@ -638,28 +619,45 @@ impl<'a> LookupContext<'a> {
|
||||||
// Candidate selection (see comment at start of file)
|
// Candidate selection (see comment at start of file)
|
||||||
|
|
||||||
fn search_for_autoderefd_method(&self,
|
fn search_for_autoderefd_method(&self,
|
||||||
self_ty: ty::t,
|
self_ty: ty::t,
|
||||||
autoderefs: uint)
|
autoderefs: uint)
|
||||||
-> Option<MethodCallee> {
|
-> Option<MethodCallee> {
|
||||||
let (self_ty, autoadjust) =
|
let (self_ty, auto_deref_ref) =
|
||||||
self.consider_reborrow(self_ty, autoderefs);
|
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) {
|
match self.search_for_method(self_ty) {
|
||||||
None => None,
|
None => None,
|
||||||
Some(mme) => {
|
Some(method) => {
|
||||||
debug!("(searching for autoderef'd method) writing \
|
debug!("(searching for autoderef'd method) writing \
|
||||||
adjustment ({}) to {}",
|
adjustment {:?}", adjustment);
|
||||||
autoderefs,
|
match adjustment {
|
||||||
self.self_expr.id);
|
Some((self_expr_id, adj)) => {
|
||||||
self.fcx.write_adjustment(self.self_expr.id, @autoadjust);
|
self.fcx.write_adjustment(self_expr_id, adj);
|
||||||
Some(mme)
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
Some(method)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_reborrow(&self,
|
fn consider_reborrow(&self,
|
||||||
self_ty: ty::t,
|
self_ty: ty::t,
|
||||||
autoderefs: uint)
|
autoderefs: uint)
|
||||||
-> (ty::t, ty::AutoAdjustment) {
|
-> (ty::t, ty::AutoDerefRef) {
|
||||||
/*!
|
/*!
|
||||||
* In the event that we are invoking a method with a receiver
|
* In the event that we are invoking a method with a receiver
|
||||||
* of a borrowed type like `&T`, `&mut T`, or `&mut [T]`,
|
* 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 {
|
return match ty::get(self_ty).sty {
|
||||||
ty::ty_rptr(_, self_mt) if default_method_hack(self_mt) => {
|
ty::ty_rptr(_, self_mt) if default_method_hack(self_mt) => {
|
||||||
(self_ty,
|
(self_ty,
|
||||||
ty::AutoDerefRef(ty::AutoDerefRef {
|
ty::AutoDerefRef {
|
||||||
autoderefs: autoderefs,
|
autoderefs: autoderefs,
|
||||||
autoref: None}))
|
autoref: None})
|
||||||
}
|
}
|
||||||
ty::ty_rptr(_, self_mt) => {
|
ty::ty_rptr(_, self_mt) => {
|
||||||
let region =
|
let region =
|
||||||
self.infcx().next_region_var(
|
self.infcx().next_region_var(infer::Autoref(self.span));
|
||||||
infer::Autoref(self.expr.span));
|
|
||||||
(ty::mk_rptr(tcx, region, self_mt),
|
(ty::mk_rptr(tcx, region, self_mt),
|
||||||
ty::AutoDerefRef(ty::AutoDerefRef {
|
ty::AutoDerefRef {
|
||||||
autoderefs: autoderefs+1,
|
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(_)) => {
|
ty::ty_vec(self_mt, vstore_slice(_)) => {
|
||||||
let region =
|
let region =
|
||||||
self.infcx().next_region_var(
|
self.infcx().next_region_var(infer::Autoref(self.span));
|
||||||
infer::Autoref(self.expr.span));
|
|
||||||
(ty::mk_vec(tcx, self_mt, vstore_slice(region)),
|
(ty::mk_vec(tcx, self_mt, vstore_slice(region)),
|
||||||
ty::AutoDerefRef(ty::AutoDerefRef {
|
ty::AutoDerefRef {
|
||||||
autoderefs: autoderefs,
|
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 =
|
let region =
|
||||||
self.infcx().next_region_var(
|
self.infcx().next_region_var(infer::Autoref(self.span));
|
||||||
infer::Autoref(self.expr.span));
|
|
||||||
(ty::mk_trait(tcx, did, substs.clone(),
|
(ty::mk_trait(tcx, did, substs.clone(),
|
||||||
ty::RegionTraitStore(region),
|
ty::RegionTraitStore(region),
|
||||||
mutbl, bounds),
|
mutbl, bounds),
|
||||||
ty::AutoDerefRef(ty::AutoDerefRef {
|
ty::AutoDerefRef {
|
||||||
autoderefs: autoderefs,
|
autoderefs: autoderefs,
|
||||||
autoref: Some(ty::AutoBorrowObj(region, mutbl))}))
|
autoref: Some(ty::AutoBorrowObj(region, mutbl))})
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
(self_ty,
|
(self_ty,
|
||||||
ty::AutoDerefRef(ty::AutoDerefRef {
|
ty::AutoDerefRef {
|
||||||
autoderefs: autoderefs,
|
autoderefs: autoderefs,
|
||||||
autoref: None}))
|
autoref: None})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -848,30 +843,43 @@ impl<'a> LookupContext<'a> {
|
||||||
mutbls: &[ast::Mutability],
|
mutbls: &[ast::Mutability],
|
||||||
mk_autoref_ty: |ast::Mutability, ty::Region| -> ty::t)
|
mk_autoref_ty: |ast::Mutability, ty::Region| -> ty::t)
|
||||||
-> Option<MethodCallee> {
|
-> 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
|
// This is hokey. We should have mutability inference as a
|
||||||
// variable. But for now, try &const, then &, then &mut:
|
// variable. But for now, try &const, then &, then &mut:
|
||||||
let region =
|
let region =
|
||||||
self.infcx().next_region_var(
|
self.infcx().next_region_var(infer::Autoref(self.span));
|
||||||
infer::Autoref(self.expr.span));
|
|
||||||
for mutbl in mutbls.iter() {
|
for mutbl in mutbls.iter() {
|
||||||
let autoref_ty = mk_autoref_ty(*mutbl, region);
|
let autoref_ty = mk_autoref_ty(*mutbl, region);
|
||||||
match self.search_for_method(autoref_ty) {
|
match self.search_for_method(autoref_ty) {
|
||||||
None => {}
|
None => {}
|
||||||
Some(mme) => {
|
Some(method) => {
|
||||||
self.fcx.write_adjustment(
|
match self_expr_id {
|
||||||
self.self_expr.id,
|
Some(self_expr_id) => {
|
||||||
@ty::AutoDerefRef(ty::AutoDerefRef {
|
self.fcx.write_adjustment(
|
||||||
autoderefs: autoderefs,
|
self_expr_id,
|
||||||
autoref: Some(kind(region, *mutbl))}));
|
@ty::AutoDerefRef(ty::AutoDerefRef {
|
||||||
return Some(mme);
|
autoderefs: autoderefs,
|
||||||
|
autoref: Some(kind(region, *mutbl))
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
return Some(method);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return None;
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn search_for_method(&self, rcvr_ty: ty::t)
|
fn search_for_method(&self, rcvr_ty: ty::t) -> Option<MethodCallee> {
|
||||||
-> Option<MethodCallee> {
|
|
||||||
debug!("search_for_method(rcvr_ty={})", self.ty_to_str(rcvr_ty));
|
debug!("search_for_method(rcvr_ty={})", self.ty_to_str(rcvr_ty));
|
||||||
let _indenter = indenter();
|
let _indenter = indenter();
|
||||||
|
|
||||||
|
@ -900,9 +908,8 @@ impl<'a> LookupContext<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_candidates(&self,
|
fn consider_candidates(&self, rcvr_ty: ty::t,
|
||||||
rcvr_ty: ty::t,
|
candidates: &mut Vec<Candidate>)
|
||||||
candidates: &mut Vec<Candidate> )
|
|
||||||
-> Option<MethodCallee> {
|
-> Option<MethodCallee> {
|
||||||
// FIXME(pcwalton): Do we need to clone here?
|
// FIXME(pcwalton): Do we need to clone here?
|
||||||
let relevant_candidates: Vec<Candidate> =
|
let relevant_candidates: Vec<Candidate> =
|
||||||
|
@ -918,7 +925,7 @@ impl<'a> LookupContext<'a> {
|
||||||
|
|
||||||
if relevant_candidates.len() > 1 {
|
if relevant_candidates.len() > 1 {
|
||||||
self.tcx().sess.span_err(
|
self.tcx().sess.span_err(
|
||||||
self.expr.span,
|
self.span,
|
||||||
"multiple applicable methods in scope");
|
"multiple applicable methods in scope");
|
||||||
for (idx, candidate) in relevant_candidates.iter().enumerate() {
|
for (idx, candidate) in relevant_candidates.iter().enumerate() {
|
||||||
self.report_candidate(idx, &candidate.origin);
|
self.report_candidate(idx, &candidate.origin);
|
||||||
|
@ -986,8 +993,7 @@ impl<'a> LookupContext<'a> {
|
||||||
|
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
|
|
||||||
debug!("confirm_candidate(expr={}, rcvr_ty={}, candidate={})",
|
debug!("confirm_candidate(rcvr_ty={}, candidate={})",
|
||||||
self.expr.repr(tcx),
|
|
||||||
self.ty_to_str(rcvr_ty),
|
self.ty_to_str(rcvr_ty),
|
||||||
candidate.repr(self.tcx()));
|
candidate.repr(self.tcx()));
|
||||||
|
|
||||||
|
@ -1007,12 +1013,12 @@ impl<'a> LookupContext<'a> {
|
||||||
self.fcx.infcx().next_ty_vars(num_method_tps)
|
self.fcx.infcx().next_ty_vars(num_method_tps)
|
||||||
} else if num_method_tps == 0u {
|
} else if num_method_tps == 0u {
|
||||||
tcx.sess.span_err(
|
tcx.sess.span_err(
|
||||||
self.expr.span,
|
self.span,
|
||||||
"this method does not take type parameters");
|
"this method does not take type parameters");
|
||||||
self.fcx.infcx().next_ty_vars(num_method_tps)
|
self.fcx.infcx().next_ty_vars(num_method_tps)
|
||||||
} else if num_supplied_tps != num_method_tps {
|
} else if num_supplied_tps != num_method_tps {
|
||||||
tcx.sess.span_err(
|
tcx.sess.span_err(
|
||||||
self.expr.span,
|
self.span,
|
||||||
"incorrect number of type \
|
"incorrect number of type \
|
||||||
parameters given for this method");
|
parameters given for this method");
|
||||||
self.fcx.infcx().next_ty_vars(num_method_tps)
|
self.fcx.infcx().next_ty_vars(num_method_tps)
|
||||||
|
@ -1025,11 +1031,11 @@ impl<'a> LookupContext<'a> {
|
||||||
// FIXME -- permit users to manually specify lifetimes
|
// FIXME -- permit users to manually specify lifetimes
|
||||||
let mut all_regions = match candidate.rcvr_substs.regions {
|
let mut all_regions = match candidate.rcvr_substs.regions {
|
||||||
NonerasedRegions(ref v) => v.clone(),
|
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 =
|
let m_regions =
|
||||||
self.fcx.infcx().region_vars_for_defs(
|
self.fcx.infcx().region_vars_for_defs(
|
||||||
self.expr.span,
|
self.span,
|
||||||
candidate.method_ty.generics.region_param_defs.deref().as_slice());
|
candidate.method_ty.generics.region_param_defs.deref().as_slice());
|
||||||
for &r in m_regions.iter() {
|
for &r in m_regions.iter() {
|
||||||
all_regions.push(r);
|
all_regions.push(r);
|
||||||
|
@ -1077,7 +1083,7 @@ impl<'a> LookupContext<'a> {
|
||||||
let (_, fn_sig) = replace_late_bound_regions_in_fn_sig(
|
let (_, fn_sig) = replace_late_bound_regions_in_fn_sig(
|
||||||
tcx, &fn_sig,
|
tcx, &fn_sig,
|
||||||
|br| self.fcx.infcx().next_region_var(
|
|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 transformed_self_ty = *fn_sig.inputs.get(0);
|
||||||
let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {
|
let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {
|
||||||
sig: fn_sig,
|
sig: fn_sig,
|
||||||
|
@ -1091,7 +1097,8 @@ impl<'a> LookupContext<'a> {
|
||||||
// variables to unify etc). Since we checked beforehand, and
|
// variables to unify etc). Since we checked beforehand, and
|
||||||
// nothing has changed in the meantime, this unification
|
// nothing has changed in the meantime, this unification
|
||||||
// should never fail.
|
// 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) {
|
rcvr_ty, transformed_self_ty) {
|
||||||
result::Ok(_) => {}
|
result::Ok(_) => {}
|
||||||
result::Err(_) => {
|
result::Err(_) => {
|
||||||
|
@ -1112,8 +1119,7 @@ impl<'a> LookupContext<'a> {
|
||||||
&self,
|
&self,
|
||||||
trait_def_id: ast::DefId,
|
trait_def_id: ast::DefId,
|
||||||
rcvr_substs: &ty::substs,
|
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
|
* This is a bit tricky. We have a match against a trait method
|
||||||
* being invoked on an object, and we want to generate the
|
* being invoked on an object, and we want to generate the
|
||||||
|
@ -1140,7 +1146,7 @@ impl<'a> LookupContext<'a> {
|
||||||
tps: rcvr_substs.tps.clone()};
|
tps: rcvr_substs.tps.clone()};
|
||||||
match method_ty.explicit_self {
|
match method_ty.explicit_self {
|
||||||
ast::SelfStatic => {
|
ast::SelfStatic => {
|
||||||
self.bug(~"static method for object type receiver");
|
self.bug("static method for object type receiver");
|
||||||
}
|
}
|
||||||
ast::SelfValue => {
|
ast::SelfValue => {
|
||||||
ty::mk_err() // error reported in `enforce_object_limitations()`
|
ty::mk_err() // error reported in `enforce_object_limitations()`
|
||||||
|
@ -1187,14 +1193,14 @@ impl<'a> LookupContext<'a> {
|
||||||
match candidate.method_ty.explicit_self {
|
match candidate.method_ty.explicit_self {
|
||||||
ast::SelfStatic => { // reason (a) above
|
ast::SelfStatic => { // reason (a) above
|
||||||
self.tcx().sess.span_err(
|
self.tcx().sess.span_err(
|
||||||
self.expr.span,
|
self.span,
|
||||||
"cannot call a method without a receiver \
|
"cannot call a method without a receiver \
|
||||||
through an object");
|
through an object");
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::SelfValue => { // reason (a) above
|
ast::SelfValue => { // reason (a) above
|
||||||
self.tcx().sess.span_err(
|
self.tcx().sess.span_err(
|
||||||
self.expr.span,
|
self.span,
|
||||||
"cannot call a method with a by-value receiver \
|
"cannot call a method with a by-value receiver \
|
||||||
through an object");
|
through an object");
|
||||||
}
|
}
|
||||||
|
@ -1206,7 +1212,7 @@ impl<'a> LookupContext<'a> {
|
||||||
let check_for_self_ty = |ty| {
|
let check_for_self_ty = |ty| {
|
||||||
if ty::type_has_self(ty) {
|
if ty::type_has_self(ty) {
|
||||||
self.tcx().sess.span_err(
|
self.tcx().sess.span_err(
|
||||||
self.expr.span,
|
self.span,
|
||||||
"cannot call a method whose type contains a \
|
"cannot call a method whose type contains a \
|
||||||
self-type through an object");
|
self-type through an object");
|
||||||
true
|
true
|
||||||
|
@ -1228,7 +1234,7 @@ impl<'a> LookupContext<'a> {
|
||||||
|
|
||||||
if candidate.method_ty.generics.has_type_params() { // reason (b) above
|
if candidate.method_ty.generics.has_type_params() { // reason (b) above
|
||||||
self.tcx().sess.span_err(
|
self.tcx().sess.span_err(
|
||||||
self.expr.span,
|
self.span,
|
||||||
"cannot call a generic method through an object");
|
"cannot call a generic method through an object");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1253,7 +1259,7 @@ impl<'a> LookupContext<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if bad {
|
if bad {
|
||||||
self.tcx().sess.span_err(self.expr.span,
|
self.tcx().sess.span_err(self.span,
|
||||||
"explicit call to destructor");
|
"explicit call to destructor");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1364,7 +1370,7 @@ impl<'a> LookupContext<'a> {
|
||||||
let span = if did.krate == ast::LOCAL_CRATE {
|
let span = if did.krate == ast::LOCAL_CRATE {
|
||||||
self.tcx().map.span(did.node)
|
self.tcx().map.span(did.node)
|
||||||
} else {
|
} else {
|
||||||
self.expr.span
|
self.span
|
||||||
};
|
};
|
||||||
self.tcx().sess.span_note(
|
self.tcx().sess.span_note(
|
||||||
span,
|
span,
|
||||||
|
@ -1375,7 +1381,7 @@ impl<'a> LookupContext<'a> {
|
||||||
|
|
||||||
fn report_param_candidate(&self, idx: uint, did: DefId) {
|
fn report_param_candidate(&self, idx: uint, did: DefId) {
|
||||||
self.tcx().sess.span_note(
|
self.tcx().sess.span_note(
|
||||||
self.expr.span,
|
self.span,
|
||||||
format!("candidate \\#{} derives from the bound `{}`",
|
format!("candidate \\#{} derives from the bound `{}`",
|
||||||
idx+1u,
|
idx+1u,
|
||||||
ty::item_path_str(self.tcx(), did)));
|
ty::item_path_str(self.tcx(), did)));
|
||||||
|
@ -1383,7 +1389,7 @@ impl<'a> LookupContext<'a> {
|
||||||
|
|
||||||
fn report_trait_candidate(&self, idx: uint, did: DefId) {
|
fn report_trait_candidate(&self, idx: uint, did: DefId) {
|
||||||
self.tcx().sess.span_note(
|
self.tcx().sess.span_note(
|
||||||
self.expr.span,
|
self.span,
|
||||||
format!("candidate \\#{} derives from the type of the receiver, \
|
format!("candidate \\#{} derives from the type of the receiver, \
|
||||||
which is the trait `{}`",
|
which is the trait `{}`",
|
||||||
idx+1u,
|
idx+1u,
|
||||||
|
@ -1406,8 +1412,9 @@ impl<'a> LookupContext<'a> {
|
||||||
ty::item_path_str(self.tcx(), did)
|
ty::item_path_str(self.tcx(), did)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bug(&self, s: ~str) -> ! {
|
fn bug(&self, s: &str) -> ! {
|
||||||
self.tcx().sess.span_bug(self.self_expr.span, s)
|
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::method::{DontAutoderefReceiver};
|
||||||
use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
|
use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
|
||||||
use middle::typeck::check::regionmanip::relate_free_regions;
|
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::CrateCtxt;
|
||||||
use middle::typeck::infer::{resolve_type, force_tvar};
|
use middle::typeck::infer::{resolve_type, force_tvar};
|
||||||
use middle::typeck::infer;
|
use middle::typeck::infer;
|
||||||
use middle::typeck::rscope::RegionScope;
|
use middle::typeck::rscope::RegionScope;
|
||||||
use middle::typeck::{lookup_def_ccx};
|
use middle::typeck::{lookup_def_ccx};
|
||||||
use middle::typeck::no_params;
|
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 middle::lang_items::TypeIdLangItem;
|
||||||
use util::common::{block_query, indenter, loop_query};
|
use util::common::{block_query, indenter, loop_query};
|
||||||
use util::ppaux;
|
use util::ppaux;
|
||||||
use util::ppaux::{UserString, Repr};
|
use util::ppaux::{UserString, Repr};
|
||||||
use util::nodemap::NodeMap;
|
use util::nodemap::{FnvHashMap, NodeMap};
|
||||||
|
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
|
@ -266,7 +267,7 @@ impl Inherited {
|
||||||
node_types: RefCell::new(NodeMap::new()),
|
node_types: RefCell::new(NodeMap::new()),
|
||||||
node_type_substs: RefCell::new(NodeMap::new()),
|
node_type_substs: RefCell::new(NodeMap::new()),
|
||||||
adjustments: 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()),
|
vtable_map: @RefCell::new(NodeMap::new()),
|
||||||
upvar_borrow_map: RefCell::new(HashMap::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 {
|
pub fn node_ty_substs(&self, id: ast::NodeId) -> ty::substs {
|
||||||
match self.inh.node_type_substs.borrow().get().find(&id) {
|
match self.inh.node_type_substs.borrow().get().find(&id) {
|
||||||
Some(ts) => (*ts).clone(),
|
Some(ts) => (*ts).clone(),
|
||||||
|
@ -1133,7 +1122,7 @@ impl FnCtxt {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn method_ty_substs(&self, id: ast::NodeId) -> ty::substs {
|
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(),
|
Some(method) => method.substs.clone(),
|
||||||
None => {
|
None => {
|
||||||
self.tcx().sess.bug(
|
self.tcx().sess.bug(
|
||||||
|
@ -1252,81 +1241,76 @@ pub enum LvaluePreference {
|
||||||
NoPreference
|
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
|
* Autoderefs the type `t` as many times as possible, returning a new type
|
||||||
* a new type and a counter for how many times the type was
|
* and an autoderef count. If the count is not zero, the receiver is
|
||||||
* deref'd. If the counter is non-zero, the receiver is responsible
|
* responsible for inserting an AutoAdjustment record into `tcx.adjustments`
|
||||||
* for inserting an AutoAdjustment record into `tcx.adjustments`
|
|
||||||
* so that trans/borrowck/etc know about this autoderef. */
|
* so that trans/borrowck/etc know about this autoderef. */
|
||||||
|
|
||||||
let mut t1 = t;
|
let mut t = t;
|
||||||
let mut enum_dids = Vec::new();
|
|
||||||
let mut autoderefs = 0;
|
let mut autoderefs = 0;
|
||||||
loop {
|
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:
|
// Some extra checks to detect weird cycles and so forth:
|
||||||
match *sty {
|
match ty::get(resolved_t).sty {
|
||||||
ty::ty_box(inner) | ty::ty_uniq(inner) => {
|
ty::ty_box(_) | ty::ty_uniq(_) | ty::ty_rptr(_, _) => {
|
||||||
match ty::get(t1).sty {
|
match ty::get(t).sty {
|
||||||
ty::ty_infer(ty::TyVar(v1)) => {
|
ty::ty_infer(ty::TyVar(v1)) => {
|
||||||
ty::occurs_check(fcx.ccx.tcx, sp, v1,
|
ty::occurs_check(fcx.ccx.tcx, sp, v1, resolved_t);
|
||||||
ty::mk_box(fcx.ccx.tcx, inner));
|
|
||||||
}
|
}
|
||||||
_ => ()
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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*/ }
|
_ => { /*ok*/ }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, deref if type is derefable:
|
match should_stop(resolved_t, autoderefs) {
|
||||||
match ty::deref_sty(sty, false) {
|
Some(x) => return (resolved_t, autoderefs, Some(x)),
|
||||||
None => {
|
None => {}
|
||||||
return (t1, autoderefs);
|
|
||||||
}
|
|
||||||
Some(mt) => {
|
|
||||||
autoderefs += 1;
|
|
||||||
t1 = mt.ty
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
// 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,
|
fn try_overloaded_deref(fcx: @FnCtxt,
|
||||||
expr: &ast::Expr,
|
span: Span,
|
||||||
base_expr: &ast::Expr,
|
method_call: Option<MethodCall>,
|
||||||
|
base_expr: Option<&ast::Expr>,
|
||||||
base_ty: ty::t,
|
base_ty: ty::t,
|
||||||
lvalue_pref: LvaluePreference)
|
lvalue_pref: LvaluePreference)
|
||||||
-> Option<ty::mt> {
|
-> Option<ty::mt> {
|
||||||
// Try DerefMut first, if preferred.
|
// Try DerefMut first, if preferred.
|
||||||
let method = match (lvalue_pref, fcx.tcx().lang_items.deref_mut_trait()) {
|
let method = match (lvalue_pref, fcx.tcx().lang_items.deref_mut_trait()) {
|
||||||
(PreferMutLvalue, Some(trait_did)) => {
|
(PreferMutLvalue, Some(trait_did)) => {
|
||||||
method::lookup_in_trait(fcx, expr, base_expr, token::intern("deref_mut"),
|
method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
|
||||||
trait_did, base_ty, [], DontAutoderefReceiver)
|
token::intern("deref_mut"), trait_did,
|
||||||
|
base_ty, [], DontAutoderefReceiver)
|
||||||
}
|
}
|
||||||
_ => None
|
_ => None
|
||||||
};
|
};
|
||||||
|
@ -1334,8 +1318,9 @@ fn try_overloaded_deref(fcx: @FnCtxt,
|
||||||
// Otherwise, fall back to Deref.
|
// Otherwise, fall back to Deref.
|
||||||
let method = match (method, fcx.tcx().lang_items.deref_trait()) {
|
let method = match (method, fcx.tcx().lang_items.deref_trait()) {
|
||||||
(None, Some(trait_did)) => {
|
(None, Some(trait_did)) => {
|
||||||
method::lookup_in_trait(fcx, expr, base_expr, token::intern("deref"),
|
method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
|
||||||
trait_did, base_ty, [], DontAutoderefReceiver)
|
token::intern("deref"), trait_did,
|
||||||
|
base_ty, [], DontAutoderefReceiver)
|
||||||
}
|
}
|
||||||
(method, _) => method
|
(method, _) => method
|
||||||
};
|
};
|
||||||
|
@ -1343,7 +1328,12 @@ fn try_overloaded_deref(fcx: @FnCtxt,
|
||||||
match method {
|
match method {
|
||||||
Some(method) => {
|
Some(method) => {
|
||||||
let ref_ty = ty::ty_fn_ret(method.ty);
|
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)
|
ty::deref(ref_ty, true)
|
||||||
}
|
}
|
||||||
None => None
|
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
|
// would return ($0, $1) where $0 and $1 are freshly instantiated type
|
||||||
// variables.
|
// variables.
|
||||||
pub fn impl_self_ty(vcx: &VtableContext,
|
pub fn impl_self_ty(vcx: &VtableContext,
|
||||||
location_info: &LocationInfo, // (potential) receiver for
|
span: Span, // (potential) receiver for this impl
|
||||||
// this impl
|
|
||||||
did: ast::DefId)
|
did: ast::DefId)
|
||||||
-> ty_param_substs_and_ty {
|
-> ty_param_substs_and_ty {
|
||||||
let tcx = vcx.tcx();
|
let tcx = vcx.tcx();
|
||||||
|
@ -1446,7 +1435,7 @@ pub fn impl_self_ty(vcx: &VtableContext,
|
||||||
ity.generics.region_param_defs(),
|
ity.generics.region_param_defs(),
|
||||||
ity.ty);
|
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 tps = vcx.infcx.next_ty_vars(n_tps);
|
||||||
|
|
||||||
let substs = substs {
|
let substs = substs {
|
||||||
|
@ -1921,7 +1910,8 @@ fn check_expr_with_unifier(fcx: @FnCtxt,
|
||||||
AutoderefReceiver) {
|
AutoderefReceiver) {
|
||||||
Some(method) => {
|
Some(method) => {
|
||||||
let method_ty = method.ty;
|
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
|
method_ty
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
@ -2001,15 +1991,17 @@ fn check_expr_with_unifier(fcx: @FnCtxt,
|
||||||
unbound_method: ||) -> ty::t {
|
unbound_method: ||) -> ty::t {
|
||||||
let method = match trait_did {
|
let method = match trait_did {
|
||||||
Some(trait_did) => {
|
Some(trait_did) => {
|
||||||
method::lookup_in_trait(fcx, op_ex, args[0], opname, trait_did,
|
method::lookup_in_trait(fcx, op_ex.span, Some(&*args[0]), opname,
|
||||||
self_t, [], autoderef_receiver)
|
trait_did, self_t, [], autoderef_receiver)
|
||||||
}
|
}
|
||||||
None => None
|
None => None
|
||||||
};
|
};
|
||||||
match method {
|
match method {
|
||||||
Some(method) => {
|
Some(method) => {
|
||||||
let method_ty = method.ty;
|
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,
|
check_method_argument_types(fcx, op_ex.span,
|
||||||
method_ty, op_ex,
|
method_ty, op_ex,
|
||||||
args, DoDerefArgs)
|
args, DoDerefArgs)
|
||||||
|
@ -2293,32 +2285,28 @@ fn check_expr_with_unifier(fcx: @FnCtxt,
|
||||||
field: ast::Name,
|
field: ast::Name,
|
||||||
tys: &[ast::P<ast::Ty>]) {
|
tys: &[ast::P<ast::Ty>]) {
|
||||||
let tcx = fcx.ccx.tcx;
|
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,
|
let expr_t = structurally_resolved_type(fcx, expr.span,
|
||||||
fcx.expr_ty(base));
|
fcx.expr_ty(base));
|
||||||
let (base_t, derefs) = do_autoderef(fcx, expr.span, expr_t);
|
// FIXME(eddyb) #12808 Integrate privacy into this auto-deref loop.
|
||||||
|
let (_, autoderefs, field_ty) =
|
||||||
match *structure_of(fcx, expr.span, base_t) {
|
autoderef(fcx, expr.span, expr_t, Some(base.id), lvalue_pref, |base_t, _| {
|
||||||
ty::ty_struct(base_id, ref substs) => {
|
match ty::get(base_t).sty {
|
||||||
// This is just for fields -- the same code handles
|
ty::ty_struct(base_id, ref substs) => {
|
||||||
// methods in both classes and traits
|
debug!("struct named {}", ppaux::ty_to_str(tcx, base_t));
|
||||||
|
let fields = ty::lookup_struct_fields(tcx, base_id);
|
||||||
// (1) verify that the class id actually has a field called
|
lookup_field_ty(tcx, base_id, fields.as_slice(), field, &(*substs))
|
||||||
// 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 => ()
|
|
||||||
}
|
}
|
||||||
|
_ => 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();
|
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 = structurally_resolved_type(fcx, expr.span, oprnd_t);
|
||||||
oprnd_t = match ty::deref(oprnd_t, true) {
|
oprnd_t = match ty::deref(oprnd_t, true) {
|
||||||
Some(mt) => mt.ty,
|
Some(mt) => mt.ty,
|
||||||
None => match try_overloaded_deref(fcx, expr, oprnd,
|
None => match try_overloaded_deref(fcx, expr.span,
|
||||||
oprnd_t, lvalue_pref) {
|
Some(MethodCall::expr(expr.id)),
|
||||||
|
Some(&*oprnd), oprnd_t, lvalue_pref) {
|
||||||
Some(mt) => mt.ty,
|
Some(mt) => mt.ty,
|
||||||
None => {
|
None => {
|
||||||
let is_newtype = match ty::get(oprnd_t).sty {
|
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) {
|
} else if ty::type_is_error(idx_t) || ty::type_is_bot(idx_t) {
|
||||||
fcx.write_ty(id, idx_t);
|
fcx.write_ty(id, idx_t);
|
||||||
} else {
|
} else {
|
||||||
let (base_t, derefs) = do_autoderef(fcx, expr.span, raw_base_t);
|
let (base_t, autoderefs, field_ty) =
|
||||||
let base_sty = structure_of(fcx, expr.span, base_t);
|
autoderef(fcx, expr.span, raw_base_t, Some(base.id),
|
||||||
match ty::index_sty(base_sty) {
|
lvalue_pref, |base_t, _| ty::index(base_t));
|
||||||
|
match field_ty {
|
||||||
Some(mt) => {
|
Some(mt) => {
|
||||||
require_integral(fcx, idx.span, idx_t);
|
require_integral(fcx, idx.span, idx_t);
|
||||||
fcx.write_ty(id, mt.ty);
|
fcx.write_ty(id, mt.ty);
|
||||||
fcx.write_autoderef_adjustment(base.id, derefs);
|
fcx.write_autoderef_adjustment(base.id, autoderefs);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let resolved = structurally_resolved_type(fcx,
|
let resolved = structurally_resolved_type(fcx,
|
||||||
expr.span,
|
expr.span,
|
||||||
raw_base_t);
|
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,
|
fcx.type_error_message(expr.span,
|
||||||
|actual| {
|
|actual| {
|
||||||
format!("cannot index a value \
|
format!("cannot index a value \
|
||||||
|
@ -3196,15 +3193,7 @@ fn check_expr_with_unifier(fcx: @FnCtxt,
|
||||||
},
|
},
|
||||||
base_t,
|
base_t,
|
||||||
None);
|
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);
|
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_and_force_all_but_regions;
|
||||||
use middle::typeck::infer::resolve_type;
|
use middle::typeck::infer::resolve_type;
|
||||||
use middle::typeck::infer;
|
use middle::typeck::infer;
|
||||||
|
use middle::typeck::MethodCall;
|
||||||
use middle::pat_util;
|
use middle::pat_util;
|
||||||
use util::ppaux::{ty_to_str, region_to_str, Repr};
|
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.
|
/// 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);
|
let t = self.fcx.node_ty(id);
|
||||||
self.resolve_type(t)
|
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.
|
/// Try to resolve the type for the given node.
|
||||||
pub fn resolve_expr_type_adjusted(&mut self, expr: &ast::Expr) -> ty::t {
|
pub fn resolve_expr_type_adjusted(&mut self, expr: &ast::Expr) -> ty::t {
|
||||||
let ty_unadjusted = self.resolve_node_type(expr.id);
|
let ty_unadjusted = self.resolve_node_type(expr.id);
|
||||||
|
@ -233,11 +240,9 @@ impl Rcx {
|
||||||
ty_unadjusted
|
ty_unadjusted
|
||||||
} else {
|
} else {
|
||||||
let tcx = self.fcx.tcx();
|
let tcx = self.fcx.tcx();
|
||||||
let adjustment = {
|
let adjustment = self.fcx.inh.adjustments.borrow().get().find_copy(&expr.id);
|
||||||
let adjustments = self.fcx.inh.adjustments.borrow();
|
ty::adjust_ty(tcx, expr.span, expr.id, ty_unadjusted, adjustment,
|
||||||
adjustments.get().find_copy(&expr.id)
|
|method_call| self.resolve_method_type(method_call))
|
||||||
};
|
|
||||||
ty::adjust_ty(tcx, expr.span, ty_unadjusted, adjustment)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -252,10 +257,8 @@ impl<'a> mc::Typer for &'a mut Rcx {
|
||||||
if ty::type_is_error(t) {Err(())} else {Ok(t)}
|
if ty::type_is_error(t) {Err(())} else {Ok(t)}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_method_ty(&mut self, id: ast::NodeId) -> Option<ty::t> {
|
fn node_method_ty(&mut self, method_call: MethodCall) -> Option<ty::t> {
|
||||||
self.fcx.inh.method_map.borrow().get().find(&id).map(|method| {
|
self.resolve_method_type(method_call)
|
||||||
self.resolve_type(method.ty)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn adjustment(&mut self, id: ast::NodeId) -> Option<@ty::AutoAdjustment> {
|
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 {
|
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> {
|
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={:?})",
|
debug!("regionck::visit_expr(e={}, repeating_scope={:?})",
|
||||||
expr.repr(rcx.fcx.tcx()), rcx.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.
|
// Check any autoderefs or autorefs that appear.
|
||||||
{
|
for &adjustment in rcx.fcx.inh.adjustments.borrow().get().find(&expr.id).iter() {
|
||||||
let adjustments = rcx.fcx.inh.adjustments.borrow();
|
debug!("adjustment={:?}", adjustment);
|
||||||
let r = adjustments.get().find(&expr.id);
|
match **adjustment {
|
||||||
for &adjustment in r.iter() {
|
ty::AutoDerefRef(ty::AutoDerefRef {autoderefs, autoref: opt_autoref}) => {
|
||||||
debug!("adjustment={:?}", adjustment);
|
let expr_ty = rcx.resolve_node_type(expr.id);
|
||||||
match **adjustment {
|
constrain_derefs(rcx, expr, autoderefs, expr_ty);
|
||||||
ty::AutoDerefRef(
|
for autoref in opt_autoref.iter() {
|
||||||
ty::AutoDerefRef {autoderefs: autoderefs, autoref: opt_autoref}) =>
|
link_autoref(rcx, expr, autoderefs, 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
|
// Require that the resulting region encompasses
|
||||||
// the current node.
|
// 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.
|
|
||||||
//
|
//
|
||||||
// Note: there is a subtle point here concerning type
|
// FIXME(#6268) remove to support nested method calls
|
||||||
// parameters. It is possible that the type of `source`
|
constrain_regions_in_type_of_node(
|
||||||
// contains type parameters, which in turn may contain
|
rcx, expr.id, ty::ReScope(expr.id),
|
||||||
// regions that are not visible to us (only the caller
|
infer::AutoBorrow(expr.span));
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
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) => {
|
ast::ExprUnary(ast::UnDeref, base) => {
|
||||||
// For *a, the lifetime of a must enclose the deref
|
// 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) => {
|
Some(method) => {
|
||||||
constrain_call(rcx, None, expr, Some(base), [], true);
|
constrain_call(rcx, None, expr, Some(base), [], true);
|
||||||
ty::ty_fn_ret(method.ty)
|
ty::ty_fn_ret(method.ty)
|
||||||
|
@ -769,7 +768,8 @@ fn constrain_call(rcx: &mut Rcx,
|
||||||
implicitly_ref_args);
|
implicitly_ref_args);
|
||||||
let callee_ty = match fn_expr_id {
|
let callee_ty = match fn_expr_id {
|
||||||
Some(id) => rcx.resolve_node_type(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) {
|
if ty::type_is_error(callee_ty) {
|
||||||
// Bail, as function type is unknown
|
// 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
|
// is going to fail anyway, so just stop here and let typeck
|
||||||
// report errors later on in the writeback phase.
|
// report errors later on in the writeback phase.
|
||||||
let ty0 = rcx.resolve_node_type(id);
|
let ty0 = rcx.resolve_node_type(id);
|
||||||
let adjustment = {
|
let adjustment = rcx.fcx.inh.adjustments.borrow().get().find_copy(&id);
|
||||||
let adjustments = rcx.fcx.inh.adjustments.borrow();
|
let ty = ty::adjust_ty(tcx, origin.span(), id, ty0, adjustment,
|
||||||
adjustments.get().find_copy(&id)
|
|method_call| rcx.resolve_method_type(method_call));
|
||||||
};
|
|
||||||
let ty = ty::adjust_ty(tcx, origin.span(), ty0, adjustment);
|
|
||||||
debug!("constrain_regions_in_type_of_node(\
|
debug!("constrain_regions_in_type_of_node(\
|
||||||
ty={}, ty0={}, id={}, minimum_lifetime={:?}, adjustment={:?})",
|
ty={}, ty0={}, id={}, minimum_lifetime={:?}, adjustment={:?})",
|
||||||
ty_to_str(tcx, ty), ty_to_str(tcx, ty0),
|
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_origin, vtable_res, vtable_param_res};
|
||||||
use middle::typeck::{vtable_static, vtable_param, impl_res};
|
use middle::typeck::{vtable_static, vtable_param, impl_res};
|
||||||
use middle::typeck::{param_numbered, param_self, param_index};
|
use middle::typeck::{param_numbered, param_self, param_index};
|
||||||
|
use middle::typeck::MethodCall;
|
||||||
use middle::subst::Subst;
|
use middle::subst::Subst;
|
||||||
use util::common::indenter;
|
use util::common::indenter;
|
||||||
use util::ppaux;
|
use util::ppaux;
|
||||||
|
@ -62,15 +63,6 @@ use syntax::visit::Visitor;
|
||||||
// It may be better to do something more clever, like processing fully
|
// It may be better to do something more clever, like processing fully
|
||||||
// resolved types first.
|
// 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
|
/// A vtable context includes an inference context, a crate context, and a
|
||||||
/// callback function to call in case of type error.
|
/// callback function to call in case of type error.
|
||||||
pub struct VtableContext<'a> {
|
pub struct VtableContext<'a> {
|
||||||
|
@ -88,14 +80,14 @@ fn has_trait_bounds(type_param_defs: &[ty::TypeParameterDef]) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lookup_vtables(vcx: &VtableContext,
|
fn lookup_vtables(vcx: &VtableContext,
|
||||||
location_info: &LocationInfo,
|
span: Span,
|
||||||
type_param_defs: &[ty::TypeParameterDef],
|
type_param_defs: &[ty::TypeParameterDef],
|
||||||
substs: &ty::substs,
|
substs: &ty::substs,
|
||||||
is_early: bool) -> vtable_res {
|
is_early: bool) -> vtable_res {
|
||||||
debug!("lookup_vtables(location_info={:?}, \
|
debug!("lookup_vtables(span={:?}, \
|
||||||
type_param_defs={}, \
|
type_param_defs={}, \
|
||||||
substs={}",
|
substs={}",
|
||||||
location_info,
|
span,
|
||||||
type_param_defs.repr(vcx.tcx()),
|
type_param_defs.repr(vcx.tcx()),
|
||||||
substs.repr(vcx.tcx()));
|
substs.repr(vcx.tcx()));
|
||||||
|
|
||||||
|
@ -105,18 +97,18 @@ fn lookup_vtables(vcx: &VtableContext,
|
||||||
substs.tps.rev_iter()
|
substs.tps.rev_iter()
|
||||||
.zip(type_param_defs.rev_iter())
|
.zip(type_param_defs.rev_iter())
|
||||||
.map(|(ty, def)|
|
.map(|(ty, def)|
|
||||||
lookup_vtables_for_param(vcx, location_info, Some(substs),
|
lookup_vtables_for_param(vcx, span, Some(substs),
|
||||||
&*def.bounds, *ty, is_early))
|
&*def.bounds, *ty, is_early))
|
||||||
.collect();
|
.collect();
|
||||||
result.reverse();
|
result.reverse();
|
||||||
|
|
||||||
assert_eq!(substs.tps.len(), result.len());
|
assert_eq!(substs.tps.len(), result.len());
|
||||||
debug!("lookup_vtables result(\
|
debug!("lookup_vtables result(\
|
||||||
location_info={:?}, \
|
span={:?}, \
|
||||||
type_param_defs={}, \
|
type_param_defs={}, \
|
||||||
substs={}, \
|
substs={}, \
|
||||||
result={})",
|
result={})",
|
||||||
location_info,
|
span,
|
||||||
type_param_defs.repr(vcx.tcx()),
|
type_param_defs.repr(vcx.tcx()),
|
||||||
substs.repr(vcx.tcx()),
|
substs.repr(vcx.tcx()),
|
||||||
result.repr(vcx.tcx()));
|
result.repr(vcx.tcx()));
|
||||||
|
@ -124,7 +116,7 @@ fn lookup_vtables(vcx: &VtableContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lookup_vtables_for_param(vcx: &VtableContext,
|
fn lookup_vtables_for_param(vcx: &VtableContext,
|
||||||
location_info: &LocationInfo,
|
span: Span,
|
||||||
// None for substs means the identity
|
// None for substs means the identity
|
||||||
substs: Option<&ty::substs>,
|
substs: Option<&ty::substs>,
|
||||||
type_param_bounds: &ty::ParamBounds,
|
type_param_bounds: &ty::ParamBounds,
|
||||||
|
@ -155,11 +147,10 @@ fn lookup_vtables_for_param(vcx: &VtableContext,
|
||||||
|
|
||||||
debug!("after subst: {}", trait_ref.repr(tcx));
|
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),
|
Some(vtable) => param_result.push(vtable),
|
||||||
None => {
|
None => {
|
||||||
vcx.tcx().sess.span_fatal(
|
vcx.tcx().sess.span_fatal(span,
|
||||||
location_info.span,
|
|
||||||
format!("failed to find an implementation of \
|
format!("failed to find an implementation of \
|
||||||
trait {} for {}",
|
trait {} for {}",
|
||||||
vcx.infcx.trait_ref_to_str(trait_ref),
|
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(\
|
debug!("lookup_vtables_for_param result(\
|
||||||
location_info={:?}, \
|
span={:?}, \
|
||||||
type_param_bounds={}, \
|
type_param_bounds={}, \
|
||||||
ty={}, \
|
ty={}, \
|
||||||
result={})",
|
result={})",
|
||||||
location_info,
|
span,
|
||||||
type_param_bounds.repr(vcx.tcx()),
|
type_param_bounds.repr(vcx.tcx()),
|
||||||
ty.repr(vcx.tcx()),
|
ty.repr(vcx.tcx()),
|
||||||
param_result.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,
|
fn relate_trait_refs(vcx: &VtableContext,
|
||||||
location_info: &LocationInfo,
|
span: Span,
|
||||||
act_trait_ref: @ty::TraitRef,
|
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
|
* 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,
|
match infer::mk_sub_trait_refs(vcx.infcx,
|
||||||
false,
|
false,
|
||||||
infer::RelateTraitRefs(location_info.span),
|
infer::RelateTraitRefs(span),
|
||||||
act_trait_ref,
|
act_trait_ref,
|
||||||
exp_trait_ref)
|
exp_trait_ref) {
|
||||||
{
|
|
||||||
result::Ok(()) => {} // Ok.
|
result::Ok(()) => {} // Ok.
|
||||||
result::Err(ref err) => {
|
result::Err(ref err) => {
|
||||||
// There is an error, but we need to do some work to make
|
// 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)
|
!ty::trait_ref_contains_error(&r_exp_trait_ref)
|
||||||
{
|
{
|
||||||
let tcx = vcx.tcx();
|
let tcx = vcx.tcx();
|
||||||
tcx.sess.span_err(
|
tcx.sess.span_err(span,
|
||||||
location_info.span,
|
|
||||||
format!("expected {}, but found {} ({})",
|
format!("expected {}, but found {} ({})",
|
||||||
ppaux::trait_ref_to_str(tcx, &r_exp_trait_ref),
|
ppaux::trait_ref_to_str(tcx, &r_exp_trait_ref),
|
||||||
ppaux::trait_ref_to_str(tcx, &r_act_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`
|
// Look up the vtable implementing the trait `trait_ref` at type `t`
|
||||||
fn lookup_vtable(vcx: &VtableContext,
|
fn lookup_vtable(vcx: &VtableContext,
|
||||||
location_info: &LocationInfo,
|
span: Span,
|
||||||
ty: ty::t,
|
ty: ty::t,
|
||||||
trait_ref: @ty::TraitRef,
|
trait_ref: @ty::TraitRef,
|
||||||
is_early: bool)
|
is_early: bool)
|
||||||
-> Option<vtable_origin>
|
-> Option<vtable_origin> {
|
||||||
{
|
|
||||||
debug!("lookup_vtable(ty={}, trait_ref={})",
|
debug!("lookup_vtable(ty={}, trait_ref={})",
|
||||||
vcx.infcx.ty_to_str(ty),
|
vcx.infcx.ty_to_str(ty),
|
||||||
vcx.infcx.trait_ref_to_str(trait_ref));
|
vcx.infcx.trait_ref_to_str(trait_ref));
|
||||||
let _i = indenter();
|
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,
|
Some(ty) => ty,
|
||||||
None => {
|
None => {
|
||||||
// fixup_ty can only fail if this is early resolution
|
// fixup_ty can only fail if this is early resolution
|
||||||
|
@ -261,8 +248,7 @@ fn lookup_vtable(vcx: &VtableContext,
|
||||||
.get(n)
|
.get(n)
|
||||||
.trait_bounds
|
.trait_bounds
|
||||||
.as_slice();
|
.as_slice();
|
||||||
lookup_vtable_from_bounds(vcx,
|
lookup_vtable_from_bounds(vcx, span,
|
||||||
location_info,
|
|
||||||
type_param_bounds,
|
type_param_bounds,
|
||||||
param_numbered(n),
|
param_numbered(n),
|
||||||
trait_ref)
|
trait_ref)
|
||||||
|
@ -270,8 +256,7 @@ fn lookup_vtable(vcx: &VtableContext,
|
||||||
|
|
||||||
ty::ty_self(_) => {
|
ty::ty_self(_) => {
|
||||||
let self_param_bound = vcx.param_env.self_param_bound.unwrap();
|
let self_param_bound = vcx.param_env.self_param_bound.unwrap();
|
||||||
lookup_vtable_from_bounds(vcx,
|
lookup_vtable_from_bounds(vcx, span,
|
||||||
location_info,
|
|
||||||
[self_param_bound],
|
[self_param_bound],
|
||||||
param_self,
|
param_self,
|
||||||
trait_ref)
|
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,
|
// If we aren't a self type or param, or it was, but we didn't find it,
|
||||||
// do a search.
|
// do a search.
|
||||||
return search_for_vtable(vcx, location_info,
|
search_for_vtable(vcx, span, ty, trait_ref, is_early)
|
||||||
ty, trait_ref, is_early)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Given a list of bounds on a type, search those bounds to see if any
|
// Given a list of bounds on a type, search those bounds to see if any
|
||||||
// of them are the vtable we are looking for.
|
// of them are the vtable we are looking for.
|
||||||
fn lookup_vtable_from_bounds(vcx: &VtableContext,
|
fn lookup_vtable_from_bounds(vcx: &VtableContext,
|
||||||
location_info: &LocationInfo,
|
span: Span,
|
||||||
bounds: &[@ty::TraitRef],
|
bounds: &[@ty::TraitRef],
|
||||||
param: param_index,
|
param: param_index,
|
||||||
trait_ref: @ty::TraitRef)
|
trait_ref: @ty::TraitRef)
|
||||||
|
@ -306,10 +290,7 @@ fn lookup_vtable_from_bounds(vcx: &VtableContext,
|
||||||
bound_trait_ref.repr(vcx.tcx()));
|
bound_trait_ref.repr(vcx.tcx()));
|
||||||
|
|
||||||
if bound_trait_ref.def_id == trait_ref.def_id {
|
if bound_trait_ref.def_id == trait_ref.def_id {
|
||||||
relate_trait_refs(vcx,
|
relate_trait_refs(vcx, span, bound_trait_ref, trait_ref);
|
||||||
location_info,
|
|
||||||
bound_trait_ref,
|
|
||||||
trait_ref);
|
|
||||||
let vtable = vtable_param(param, n_bound);
|
let vtable = vtable_param(param, n_bound);
|
||||||
debug!("found param vtable: {:?}",
|
debug!("found param vtable: {:?}",
|
||||||
vtable);
|
vtable);
|
||||||
|
@ -324,7 +305,7 @@ fn lookup_vtable_from_bounds(vcx: &VtableContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn search_for_vtable(vcx: &VtableContext,
|
fn search_for_vtable(vcx: &VtableContext,
|
||||||
location_info: &LocationInfo,
|
span: Span,
|
||||||
ty: ty::t,
|
ty: ty::t,
|
||||||
trait_ref: @ty::TraitRef,
|
trait_ref: @ty::TraitRef,
|
||||||
is_early: bool)
|
is_early: bool)
|
||||||
|
@ -385,11 +366,10 @@ fn search_for_vtable(vcx: &VtableContext,
|
||||||
let ty::ty_param_substs_and_ty {
|
let ty::ty_param_substs_and_ty {
|
||||||
substs: substs,
|
substs: substs,
|
||||||
ty: for_ty
|
ty: for_ty
|
||||||
} = impl_self_ty(vcx, location_info, im.did);
|
} = impl_self_ty(vcx, span, im.did);
|
||||||
match infer::mk_subty(vcx.infcx,
|
match infer::mk_subty(vcx.infcx,
|
||||||
false,
|
false,
|
||||||
infer::RelateSelfType(
|
infer::RelateSelfType(span),
|
||||||
location_info.span),
|
|
||||||
ty,
|
ty,
|
||||||
for_ty) {
|
for_ty) {
|
||||||
result::Err(_) => continue,
|
result::Err(_) => continue,
|
||||||
|
@ -418,7 +398,7 @@ fn search_for_vtable(vcx: &VtableContext,
|
||||||
vcx.infcx.trait_ref_to_str(of_trait_ref));
|
vcx.infcx.trait_ref_to_str(of_trait_ref));
|
||||||
|
|
||||||
let of_trait_ref = of_trait_ref.subst(tcx, &substs);
|
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 --
|
// 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.
|
// process of looking up bounds might constrain some of them.
|
||||||
let im_generics =
|
let im_generics =
|
||||||
ty::lookup_item_type(tcx, im.did).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,
|
im_generics.type_param_defs(), &substs,
|
||||||
is_early);
|
is_early);
|
||||||
|
|
||||||
|
|
||||||
// substs might contain type variables, so we call
|
// substs might contain type variables, so we call
|
||||||
// fixup_substs to resolve them.
|
// fixup_substs to resolve them.
|
||||||
let substs_f = match fixup_substs(vcx,
|
let substs_f = match fixup_substs(vcx, span,
|
||||||
location_info,
|
|
||||||
trait_ref.def_id,
|
trait_ref.def_id,
|
||||||
substs,
|
substs,
|
||||||
is_early) {
|
is_early) {
|
||||||
|
@ -463,7 +442,7 @@ fn search_for_vtable(vcx: &VtableContext,
|
||||||
// I am a little confused about this, since it seems to be
|
// I am a little confused about this, since it seems to be
|
||||||
// very similar to the relate_trait_refs we already do,
|
// very similar to the relate_trait_refs we already do,
|
||||||
// but problems crop up if it is removed, so... -sully
|
// 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
|
// Finally, we register that we found a matching impl, and
|
||||||
// record the def ID of the impl as well as the resolved list
|
// 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()),
|
1 => return Some(found.get(0).clone()),
|
||||||
_ => {
|
_ => {
|
||||||
if !is_early {
|
if !is_early {
|
||||||
vcx.tcx().sess.span_err(
|
vcx.tcx().sess.span_err(span, "multiple applicable methods in scope");
|
||||||
location_info.span,
|
|
||||||
"multiple applicable methods in scope");
|
|
||||||
}
|
}
|
||||||
return Some(found.get(0).clone());
|
return Some(found.get(0).clone());
|
||||||
}
|
}
|
||||||
|
@ -487,7 +464,7 @@ fn search_for_vtable(vcx: &VtableContext,
|
||||||
|
|
||||||
|
|
||||||
fn fixup_substs(vcx: &VtableContext,
|
fn fixup_substs(vcx: &VtableContext,
|
||||||
location_info: &LocationInfo,
|
span: Span,
|
||||||
id: ast::DefId,
|
id: ast::DefId,
|
||||||
substs: ty::substs,
|
substs: ty::substs,
|
||||||
is_early: bool)
|
is_early: bool)
|
||||||
|
@ -499,7 +476,7 @@ fn fixup_substs(vcx: &VtableContext,
|
||||||
ty::RegionTraitStore(ty::ReStatic),
|
ty::RegionTraitStore(ty::ReStatic),
|
||||||
ast::MutImmutable,
|
ast::MutImmutable,
|
||||||
ty::EmptyBuiltinBounds());
|
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 {
|
match ty::get(t_f).sty {
|
||||||
ty::ty_trait(_, ref substs_f, _, _, _) => (*substs_f).clone(),
|
ty::ty_trait(_, ref substs_f, _, _, _) => (*substs_f).clone(),
|
||||||
_ => fail!("t_f should be a trait")
|
_ => fail!("t_f should be a trait")
|
||||||
|
@ -508,7 +485,7 @@ fn fixup_substs(vcx: &VtableContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fixup_ty(vcx: &VtableContext,
|
fn fixup_ty(vcx: &VtableContext,
|
||||||
location_info: &LocationInfo,
|
span: Span,
|
||||||
ty: ty::t,
|
ty: ty::t,
|
||||||
is_early: bool)
|
is_early: bool)
|
||||||
-> Option<ty::t> {
|
-> Option<ty::t> {
|
||||||
|
@ -516,8 +493,7 @@ fn fixup_ty(vcx: &VtableContext,
|
||||||
match resolve_type(vcx.infcx, ty, resolve_and_force_all_but_regions) {
|
match resolve_type(vcx.infcx, ty, resolve_and_force_all_but_regions) {
|
||||||
Ok(new_type) => Some(new_type),
|
Ok(new_type) => Some(new_type),
|
||||||
Err(e) if !is_early => {
|
Err(e) if !is_early => {
|
||||||
tcx.sess.span_fatal(
|
tcx.sess.span_fatal(span,
|
||||||
location_info.span,
|
|
||||||
format!("cannot determine a type \
|
format!("cannot determine a type \
|
||||||
for this bounded type parameter: {}",
|
for this bounded type parameter: {}",
|
||||||
fixup_err_to_str(e)))
|
fixup_err_to_str(e)))
|
||||||
|
@ -529,7 +505,7 @@ fn fixup_ty(vcx: &VtableContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn connect_trait_tps(vcx: &VtableContext,
|
fn connect_trait_tps(vcx: &VtableContext,
|
||||||
location_info: &LocationInfo,
|
span: Span,
|
||||||
impl_substs: &ty::substs,
|
impl_substs: &ty::substs,
|
||||||
trait_ref: @ty::TraitRef,
|
trait_ref: @ty::TraitRef,
|
||||||
impl_did: ast::DefId) {
|
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) {
|
let impl_trait_ref = match ty::impl_trait_ref(tcx, impl_did) {
|
||||||
Some(t) => t,
|
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")
|
"connect_trait_tps invoked on a type impl")
|
||||||
};
|
};
|
||||||
|
|
||||||
let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs);
|
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) {
|
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);
|
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) {
|
pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
|
||||||
debug!("vtable: early_resolve_expr() ex with id {:?} (early: {}): {}",
|
debug!("vtable: early_resolve_expr() ex with id {:?} (early: {}): {}",
|
||||||
ex.id, is_early, expr_to_str(ex));
|
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"),
|
_ => fail!("shouldn't get here"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let location_info =
|
|
||||||
&location_info_for_expr(ex);
|
|
||||||
let vcx = fcx.vtable_context();
|
let vcx = fcx.vtable_context();
|
||||||
let target_trait_ref = @ty::TraitRef {
|
let target_trait_ref = @ty::TraitRef {
|
||||||
def_id: target_def_id,
|
def_id: target_def_id,
|
||||||
|
@ -626,7 +587,7 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
|
||||||
};
|
};
|
||||||
let vtables =
|
let vtables =
|
||||||
lookup_vtables_for_param(&vcx,
|
lookup_vtables_for_param(&vcx,
|
||||||
location_info,
|
ex.span,
|
||||||
None,
|
None,
|
||||||
¶m_bounds,
|
¶m_bounds,
|
||||||
typ,
|
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 {}",
|
debug!("early_resolve_expr: looking up vtables for type params {}",
|
||||||
item_ty.generics.type_param_defs().repr(fcx.tcx()));
|
item_ty.generics.type_param_defs().repr(fcx.tcx()));
|
||||||
let vcx = fcx.vtable_context();
|
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(),
|
item_ty.generics.type_param_defs(),
|
||||||
substs, is_early);
|
substs, is_early);
|
||||||
if !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::ExprAssignOp(_, _, _) |
|
||||||
ast::ExprIndex(_, _) |
|
ast::ExprIndex(_, _) |
|
||||||
ast::ExprMethodCall(_, _, _) => {
|
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) => {
|
Some(method) => {
|
||||||
debug!("vtable resolution on parameter bounds for method call {}",
|
debug!("vtable resolution on parameter bounds for method call {}",
|
||||||
ex.repr(fcx.tcx()));
|
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()) {
|
if has_trait_bounds(type_param_defs.deref().as_slice()) {
|
||||||
let substs = fcx.method_ty_substs(ex.id);
|
let substs = fcx.method_ty_substs(ex.id);
|
||||||
let vcx = fcx.vtable_context();
|
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()
|
type_param_defs.deref()
|
||||||
.as_slice(),
|
.as_slice(),
|
||||||
&substs, is_early);
|
&substs, is_early);
|
||||||
|
@ -782,13 +743,11 @@ pub fn resolve_impl(tcx: ty::ctxt,
|
||||||
|
|
||||||
let infcx = &infer::new_infer_ctxt(tcx);
|
let infcx = &infer::new_infer_ctxt(tcx);
|
||||||
let vcx = VtableContext { infcx: infcx, param_env: ¶m_env };
|
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
|
// First, check that the impl implements any trait bounds
|
||||||
// on the trait.
|
// on the trait.
|
||||||
let trait_def = ty::lookup_trait_def(tcx, impl_trait_ref.def_id);
|
let trait_def = ty::lookup_trait_def(tcx, impl_trait_ref.def_id);
|
||||||
let vtbls = lookup_vtables(&vcx,
|
let vtbls = lookup_vtables(&vcx, impl_item.span,
|
||||||
&loc_info,
|
|
||||||
trait_def.generics.type_param_defs(),
|
trait_def.generics.type_param_defs(),
|
||||||
&impl_trait_ref.substs,
|
&impl_trait_ref.substs,
|
||||||
false);
|
false);
|
||||||
|
@ -808,7 +767,7 @@ pub fn resolve_impl(tcx: ty::ctxt,
|
||||||
// We will need to make one so we can use this information
|
// We will need to make one so we can use this information
|
||||||
// for compiling default methods that refer to supertraits.
|
// for compiling default methods that refer to supertraits.
|
||||||
let self_vtable_res =
|
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);
|
¶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),
|
infcx: &infer::new_infer_ctxt(tcx),
|
||||||
param_env: &ty::construct_parameter_environment(tcx, None, [], [], [], [], id)
|
param_env: &ty::construct_parameter_environment(tcx, None, [], [], [], [], id)
|
||||||
};
|
};
|
||||||
let loc_info = LocationInfo {
|
|
||||||
id: id,
|
|
||||||
span: tcx.map.span(id)
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(lookup_vtables(&vcx,
|
Some(lookup_vtables(&vcx,
|
||||||
&loc_info,
|
tcx.map.span(id),
|
||||||
type_param_defs.as_slice(),
|
type_param_defs.as_slice(),
|
||||||
substs,
|
substs,
|
||||||
false))
|
false))
|
||||||
|
|
|
@ -20,7 +20,7 @@ use middle::typeck::check::FnCtxt;
|
||||||
use middle::typeck::infer::{force_all, resolve_all, resolve_region};
|
use middle::typeck::infer::{force_all, resolve_all, resolve_region};
|
||||||
use middle::typeck::infer::resolve_type;
|
use middle::typeck::infer::resolve_type;
|
||||||
use middle::typeck::infer;
|
use middle::typeck::infer;
|
||||||
use middle::typeck::MethodCallee;
|
use middle::typeck::{MethodCall, MethodCallee};
|
||||||
use middle::typeck::{vtable_res, vtable_origin};
|
use middle::typeck::{vtable_res, vtable_origin};
|
||||||
use middle::typeck::{vtable_static, vtable_param};
|
use middle::typeck::{vtable_static, vtable_param};
|
||||||
use middle::typeck::write_substs_to_tcx;
|
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()
|
}).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 fcx = wbcx.fcx;
|
||||||
let tcx = fcx.ccx.tcx;
|
let tcx = fcx.ccx.tcx;
|
||||||
|
|
||||||
// Resolve any method map entry
|
// 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) => {
|
Some(method) => {
|
||||||
debug!("writeback::resolve_method_map_entry(id={:?}, entry={:?})",
|
debug!("writeback::resolve_method_map_entry(call={:?}, entry={:?})",
|
||||||
id, method.repr(tcx));
|
method_call, method.repr(tcx));
|
||||||
let method_ty = match resolve_type_vars_in_type(fcx, sp, method.ty) {
|
let method_ty = match resolve_type_vars_in_type(fcx, sp, method.ty) {
|
||||||
Some(t) => t,
|
Some(t) => t,
|
||||||
None => {
|
None => {
|
||||||
|
@ -95,7 +95,7 @@ fn resolve_method_map_entry(wbcx: &mut WbCtxt, sp: Span, id: ast::NodeId) {
|
||||||
self_ty: None
|
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 => {}
|
None => {}
|
||||||
}
|
}
|
||||||
|
@ -142,10 +142,7 @@ fn resolve_type_vars_for_node(wbcx: &mut WbCtxt, sp: Span, id: ast::NodeId)
|
||||||
let tcx = fcx.ccx.tcx;
|
let tcx = fcx.ccx.tcx;
|
||||||
|
|
||||||
// Resolve any borrowings for the node with id `id`
|
// Resolve any borrowings for the node with id `id`
|
||||||
let adjustment = {
|
let adjustment = fcx.inh.adjustments.borrow().get().find_copy(&id);
|
||||||
let adjustments = fcx.inh.adjustments.borrow();
|
|
||||||
adjustments.get().find_copy(&id)
|
|
||||||
};
|
|
||||||
match adjustment {
|
match adjustment {
|
||||||
None => (),
|
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
|
// FIXME(eddyb) #2190 Allow only statically resolved
|
||||||
// bare functions to coerce to a closure to avoid
|
// bare functions to coerce to a closure to avoid
|
||||||
// constructing (slower) indirect call wrappers.
|
// constructing (slower) indirect call wrappers.
|
||||||
{
|
match tcx.def_map.borrow().get().find(&id) {
|
||||||
let def_map = tcx.def_map.borrow();
|
Some(&ast::DefFn(..)) |
|
||||||
match def_map.get().find(&id) {
|
Some(&ast::DefStaticMethod(..)) |
|
||||||
Some(&ast::DefFn(..)) |
|
Some(&ast::DefVariant(..)) |
|
||||||
Some(&ast::DefStaticMethod(..)) |
|
Some(&ast::DefStruct(_)) => {}
|
||||||
Some(&ast::DefVariant(..)) |
|
_ => tcx.sess.span_err(sp,
|
||||||
Some(&ast::DefStruct(_)) => {}
|
"cannot coerce non-statically resolved bare fn")
|
||||||
_ => tcx.sess.span_err(sp,
|
|
||||||
"cannot coerce non-statically resolved bare fn")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let resolved_adj = @ty::AutoAddEnv(r1, s);
|
let resolved_adj = @ty::AutoAddEnv(r1, s);
|
||||||
debug!("Adjustments for node {}: {:?}",
|
debug!("Adjustments for node {}: {:?}",
|
||||||
id,
|
id, resolved_adj);
|
||||||
resolved_adj);
|
tcx.adjustments.borrow_mut().get().insert(id, resolved_adj);
|
||||||
let mut adjustments = tcx.adjustments
|
|
||||||
.borrow_mut();
|
|
||||||
adjustments.get().insert(id, resolved_adj);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::AutoDerefRef(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| {
|
let fixup_region = |r| {
|
||||||
match resolve_region(fcx.infcx(),
|
match resolve_region(fcx.infcx(),
|
||||||
r,
|
r,
|
||||||
|
@ -218,14 +214,12 @@ fn resolve_type_vars_for_node(wbcx: &mut WbCtxt, sp: Span, id: ast::NodeId)
|
||||||
autoref: resolved_autoref,
|
autoref: resolved_autoref,
|
||||||
});
|
});
|
||||||
debug!("Adjustments for node {}: {:?}", id, resolved_adj);
|
debug!("Adjustments for node {}: {:?}", id, resolved_adj);
|
||||||
let mut adjustments = tcx.adjustments.borrow_mut();
|
tcx.adjustments.borrow_mut().get().insert(id, resolved_adj);
|
||||||
adjustments.get().insert(id, resolved_adj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::AutoObject(..) => {
|
ty::AutoObject(..) => {
|
||||||
debug!("Adjustments for node {}: {:?}", id, adjustment);
|
debug!("Adjustments for node {}: {:?}", id, adjustment);
|
||||||
let mut adjustments = tcx.adjustments.borrow_mut();
|
tcx.adjustments.borrow_mut().get().insert(id, adjustment);
|
||||||
adjustments.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_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);
|
resolve_vtable_map_entry(wbcx.fcx, e.span, e.id);
|
||||||
|
|
||||||
match e.node {
|
match e.node {
|
||||||
|
|
|
@ -68,7 +68,7 @@ use middle::ty;
|
||||||
use util::common::time;
|
use util::common::time;
|
||||||
use util::ppaux::Repr;
|
use util::ppaux::Repr;
|
||||||
use util::ppaux;
|
use util::ppaux;
|
||||||
use util::nodemap::{DefIdMap, NodeMap};
|
use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -149,9 +149,31 @@ pub struct MethodCallee {
|
||||||
substs: ty::substs
|
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
|
// maps from an expression id that corresponds to a method call to the details
|
||||||
// of the method to be invoked
|
// 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> ;
|
pub type vtable_param_res = @Vec<vtable_origin> ;
|
||||||
// Resolutions for bounds of all parameters, left to right, for a given path.
|
// 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 time_passes = tcx.sess.time_passes();
|
||||||
let ccx = @CrateCtxt {
|
let ccx = @CrateCtxt {
|
||||||
trait_map: trait_map,
|
trait_map: trait_map,
|
||||||
method_map: @RefCell::new(NodeMap::new()),
|
method_map: @RefCell::new(FnvHashMap::new()),
|
||||||
vtable_map: @RefCell::new(NodeMap::new()),
|
vtable_map: @RefCell::new(NodeMap::new()),
|
||||||
tcx: tcx
|
tcx: tcx
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,9 +16,11 @@ use std::io;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
|
||||||
#[cfg(not(stage0))]
|
#[cfg(not(stage0))]
|
||||||
pub type NodeMap<T> = HashMap<ast::NodeId, T, FnvHasher>;
|
pub type FnvHashMap<K, V> = HashMap<K, V, FnvHasher>;
|
||||||
#[cfg(not(stage0))]
|
|
||||||
pub type DefIdMap<T> = HashMap<ast::DefId, T, FnvHasher>;
|
pub type NodeMap<T> = FnvHashMap<ast::NodeId, T>;
|
||||||
|
pub type DefIdMap<T> = FnvHashMap<ast::DefId, T>;
|
||||||
|
|
||||||
#[cfg(not(stage0))]
|
#[cfg(not(stage0))]
|
||||||
pub type NodeSet = HashSet<ast::NodeId, FnvHasher>;
|
pub type NodeSet = HashSet<ast::NodeId, FnvHasher>;
|
||||||
#[cfg(not(stage0))]
|
#[cfg(not(stage0))]
|
||||||
|
@ -26,12 +28,23 @@ pub type DefIdSet = HashSet<ast::DefId, FnvHasher>;
|
||||||
|
|
||||||
// Hacks to get good names
|
// Hacks to get good names
|
||||||
#[cfg(not(stage0))]
|
#[cfg(not(stage0))]
|
||||||
pub mod NodeMap {
|
pub mod FnvHashMap {
|
||||||
|
use std::hash::Hash;
|
||||||
use collections::HashMap;
|
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)
|
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))]
|
#[cfg(not(stage0))]
|
||||||
pub mod NodeSet {
|
pub mod NodeSet {
|
||||||
use collections::HashSet;
|
use collections::HashSet;
|
||||||
|
@ -40,13 +53,6 @@ pub mod NodeSet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(stage0))]
|
#[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 {
|
pub mod DefIdSet {
|
||||||
use collections::HashSet;
|
use collections::HashSet;
|
||||||
pub fn new() -> super::DefIdSet {
|
pub fn new() -> super::DefIdSet {
|
||||||
|
@ -55,9 +61,8 @@ pub mod DefIdSet {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(stage0)]
|
#[cfg(stage0)]
|
||||||
pub type NodeMap<T> = HashMap<ast::NodeId, T>;
|
pub type FnvHashMap<K, V> = HashMap<K, V>;
|
||||||
#[cfg(stage0)]
|
|
||||||
pub type DefIdMap<T> = HashMap<ast::DefId, T>;
|
|
||||||
#[cfg(stage0)]
|
#[cfg(stage0)]
|
||||||
pub type NodeSet = HashSet<ast::NodeId>;
|
pub type NodeSet = HashSet<ast::NodeId>;
|
||||||
#[cfg(stage0)]
|
#[cfg(stage0)]
|
||||||
|
@ -65,9 +70,10 @@ pub type DefIdSet = HashSet<ast::DefId>;
|
||||||
|
|
||||||
// Hacks to get good names
|
// Hacks to get good names
|
||||||
#[cfg(stage0)]
|
#[cfg(stage0)]
|
||||||
pub mod NodeMap {
|
pub mod FnvHashMap {
|
||||||
|
use std::hash::Hash;
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
pub fn new<T>() -> super::NodeMap<T> {
|
pub fn new<K: Hash + Eq, V>() -> super::FnvHashMap<K, V> {
|
||||||
HashMap::new()
|
HashMap::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,13 +85,6 @@ pub mod NodeSet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(stage0)]
|
#[cfg(stage0)]
|
||||||
pub mod DefIdMap {
|
|
||||||
use collections::HashMap;
|
|
||||||
pub fn new<T>() -> super::DefIdMap<T> {
|
|
||||||
HashMap::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[cfg(stage0)]
|
|
||||||
pub mod DefIdSet {
|
pub mod DefIdSet {
|
||||||
use collections::HashSet;
|
use collections::HashSet;
|
||||||
pub fn new() -> super::DefIdSet {
|
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