Created
March 7, 2014 16:22
-
-
Save nikomatsakis/9414596 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| commit 23a1d59063159b233cfb559f77c6149df5be62d6 | |
| Author: Niko Matsakis <[email protected]> | |
| Date: Fri Mar 7 11:10:14 2014 -0500 | |
| WIP nits | |
| diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs | |
| index a48c640..ad7a418 100644 | |
| --- a/src/librustc/middle/trans/callee.rs | |
| +++ b/src/librustc/middle/trans/callee.rs | |
| @@ -171,10 +171,13 @@ pub fn trans_fn_ref(bcx: &Block, def_id: ast::DefId, node: ExprOrMethodCall) -> | |
| let type_params = node_id_type_params(bcx, node); | |
| let vtables = match node { | |
| ExprId(id) => node_vtables(bcx, id), | |
| - MethodCall(method_call) if method_call.autoderef == 0 => { | |
| - node_vtables(bcx, method_call.expr_id) | |
| + MethodCall(ref method_call) => { | |
| + if method_call.autoderef == 0 { | |
| + node_vtables(bcx, method_call.expr_id) | |
| + } else { | |
| + None | |
| + } | |
| } | |
| - _ => None | |
| }; | |
| debug!("trans_fn_ref(def_id={}, node={:?}, type_params={}, vtables={})", | |
| def_id.repr(bcx.tcx()), node, type_params.repr(bcx.tcx()), | |
| @@ -376,15 +379,15 @@ pub fn trans_fn_ref_with_vtables( | |
| // Should be either intra-crate or inlined. | |
| assert_eq!(def_id.krate, ast::LOCAL_CRATE); | |
| - let ref_id = match node { | |
| - ExprId(id) if id != 0 => Some(id), | |
| - _ => None | |
| + let opt_ref_id = match node { | |
| + ExprId(id) => if id != 0 { Some(id) } else { None }, | |
| + MethodCall(_) => None, | |
| }; | |
| let (val, must_cast) = | |
| monomorphize::monomorphic_fn(ccx, def_id, &substs, | |
| vtables, self_vtables, | |
| - ref_id); | |
| + opt_ref_id); | |
| let mut val = val; | |
| if must_cast && node != ExprId(0) { | |
| // Monotype of the REFERENCE to the function (type params | |
| @@ -748,9 +751,19 @@ pub fn trans_call_inner<'a>( | |
| } | |
| pub enum CallArgs<'a> { | |
| + // Supply value of arguments as a list of expressions that must be | |
| + // translated. This is used in the common case of `foo(bar, qux)`. | |
| ArgExprs(&'a [@ast::Expr]), | |
| + | |
| + // Supply value of arguments as a list of LLVM value refs; frequently | |
| + // used with lang items and so forth, when the argument is an internal | |
| + // value. | |
| + ArgVals(&'a [ValueRef]), | |
| + | |
| + // For overloaded operators: `(lhs, Option(rhs, rhs_id))`. `lhs` | |
| + // is the left-hand-side and `rhs/rhs_id` is the datum/expr-id of | |
| + // the right-hand-side (if any). | |
| ArgOverloadedOp(Datum<Expr>, Option<(Datum<Expr>, ast::NodeId)>), | |
| - ArgVals(&'a [ValueRef]) | |
| } | |
| fn trans_args<'a>(cx: &'a Block<'a>, | |
| diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs | |
| index bb8b62a..2d231d8 100644 | |
| --- a/src/librustc/middle/trans/common.rs | |
| +++ b/src/librustc/middle/trans/common.rs | |
| @@ -807,9 +807,16 @@ pub fn expr_ty_adjusted(bcx: &Block, ex: &ast::Expr) -> ty::t { | |
| monomorphize_type(bcx, t) | |
| } | |
| +// Meta comment: This looks fine for now, but I feel like there is a way | |
| +// to better align our lookup tables so that we don't need this type. | |
| + | |
| +// Key used to lookup values supplied for type parameters in an expr. | |
| #[deriving(Eq)] | |
| pub enum ExprOrMethodCall { | |
| + // Type parameters for a path like `None::<int>` | |
| ExprId(ast::NodeId), | |
| + | |
| + // Type parameters for a method call like `a.foo::<int>()` | |
| MethodCall(typeck::MethodCall) | |
| } | |
| diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs | |
| index 207d889..8fe4117 100644 | |
| --- a/src/librustc/middle/trans/expr.rs | |
| +++ b/src/librustc/middle/trans/expr.rs | |
| @@ -1159,9 +1159,13 @@ fn trans_unary<'a>(bcx: &'a Block<'a>, | |
| let _icx = push_ctxt("trans_unary_datum"); | |
| let method_call = MethodCall::expr(expr.id); | |
| - let overloaded = bcx.ccx().maps.method_map.borrow().get().contains_key(&method_call); | |
| - // if overloaded, would be RvalueDpsExpr | |
| - assert!(!overloaded || op == ast::UnDeref); | |
| + | |
| + // The only overloaded operator that is translated to a datum | |
| + // is an overloaded deref, since it is always yields a `&T`. | |
| + // Otherwise, we should be in the RvalueDpsExpr path. | |
| + assert!( | |
| + op == ast::UnDeref || | |
| + !bcx.ccx().maps.method_map.borrow().get().contains_key(&method_call)); | |
| let un_ty = expr_ty(bcx, expr); | |
| @@ -1778,6 +1782,7 @@ fn deref_once<'a>(bcx: &'a Block<'a>, | |
| let mut bcx = bcx; | |
| + // Check for overloaded deref. | |
| let method_call = MethodCall { | |
| expr_id: expr.id, | |
| autoderef: derefs as u32 | |
| @@ -1786,6 +1791,11 @@ fn deref_once<'a>(bcx: &'a Block<'a>, | |
| .find(&method_call).map(|method| method.ty); | |
| let datum = match method_ty { | |
| Some(method_ty) => { | |
| + // Overloaded. Evaluate `trans_overloaded_op`, which will | |
| + // invoke the user's deref() method, which basically | |
| + // converts from the `Shaht<T>` pointer that we have into | |
| + // a `&T` pointer. We can then proceed down the normal | |
| + // path (below) to dereference that `&T`. | |
| let datum = if derefs == 0 { | |
| datum | |
| } else { | |
| @@ -1797,7 +1807,10 @@ fn deref_once<'a>(bcx: &'a Block<'a>, | |
| let ref_ty = ty::ty_fn_ret(monomorphize_type(bcx, method_ty)); | |
| Datum(val, ref_ty, RvalueExpr(Rvalue(ByValue))) | |
| } | |
| - None => datum | |
| + None => { | |
| + // Not overloaded. We already have a pointer we know how to deref. | |
| + datum | |
| + } | |
| }; | |
| let r = match ty::get(datum.ty).sty { | |
| diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs | |
| index 703c7a9..d783e0d 100644 | |
| --- a/src/librustc/middle/trans/meth.rs | |
| +++ b/src/librustc/middle/trans/meth.rs | |
| @@ -335,10 +335,13 @@ fn combine_impl_and_methods_tps(bcx: &Block, | |
| // exist, in which case we need to make them. | |
| 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) | |
| + MethodCall(method_call) => { | |
| + if method_call.autoderef == 0 { | |
| + node_vtables(bcx, method_call.expr_id) | |
| + } else { | |
| + None | |
| + } | |
| } | |
| - _ => None | |
| }; | |
| let r_m_origins = match vtables { | |
| Some(vt) => vt, | |
| diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs | |
| index 0628900..5baa8cd 100644 | |
| --- a/src/librustc/middle/ty.rs | |
| +++ b/src/librustc/middle/ty.rs | |
| @@ -223,7 +223,7 @@ pub struct AutoDerefRef { | |
| autoref: Option<AutoRef> | |
| } | |
| -#[deriving(Decodable, Encodable)] | |
| +#[deriving(Decodable, Encodable, Eq, Show)] | |
| pub enum AutoRef { | |
| /// Convert from T to &T | |
| AutoPtr(Region, ast::Mutability), | |
| @@ -3261,11 +3261,15 @@ pub fn expr_kind(tcx: ctxt, | |
| expr: &ast::Expr) -> ExprKind { | |
| if method_map.borrow().get().contains_key(&MethodCall::expr(expr.id)) { | |
| // Overloaded operations are generally calls, and hence they are | |
| - // generated via DPS. However, assign_op (e.g., `x += y`) is an | |
| - // exception, as its result is always unit. | |
| + // generated via DPS, but there are two exceptions: | |
| return match expr.node { | |
| + // `a += b` has a unit result. | |
| ast::ExprAssignOp(..) => RvalueStmtExpr, | |
| + | |
| + // the deref method invoked for `*a` always yields an `&T` | |
| ast::ExprUnary(ast::UnDeref, _) => LvalueExpr, | |
| + | |
| + // in the general case, result could be any type, use DPS | |
| _ => RvalueDpsExpr | |
| }; | |
| } | |
| diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs | |
| index dd3ef4b..435a939 100644 | |
| --- a/src/librustc/middle/typeck/check/method.rs | |
| +++ b/src/librustc/middle/typeck/check/method.rs | |
| @@ -200,7 +200,13 @@ pub fn lookup_in_trait<'a>( | |
| struct LookupContext<'a> { | |
| fcx: @FnCtxt, | |
| span: Span, | |
| + | |
| + // The receiver to the method call. Only `None` in the case of | |
| + // an overloaded autoderef, where the receiver may be an intermediate | |
| + // state like "the expression `x` when it has been autoderef'd | |
| + // twice already". | |
| self_expr: Option<&'a ast::Expr>, | |
| + | |
| m_name: ast::Name, | |
| supplied_tps: &'a [ty::t], | |
| impl_dups: @RefCell<HashSet<DefId>>, | |
| @@ -242,51 +248,69 @@ impl<'a> LookupContext<'a> { | |
| let span = self.self_expr.map_or(self.span, |e| e.span); | |
| let self_expr_id = self.self_expr.map(|e| e.id); | |
| let (self_ty, autoderefs, result) = | |
| - check::autoderef(self.fcx, span, self_ty, self_expr_id, | |
| - PreferMutLvalue, |self_ty, autoderefs| { | |
| - | |
| - debug!("loop: self_ty={} autoderefs={}", | |
| - self.ty_to_str(self_ty), autoderefs); | |
| + check::autoderef( | |
| + self.fcx, span, self_ty, self_expr_id, PreferMutLvalue, | |
| + |self_ty, autoderefs| self.search_step(self_ty, autoderefs)); | |
| - match self.deref_args { | |
| - check::DontDerefArgs => { | |
| - match self.search_for_autoderefd_method(self_ty, autoderefs) { | |
| - Some(result) => return Some(Some(result)), | |
| - None => {} | |
| - } | |
| + match result { | |
| + Some(Some(result)) => Some(result), | |
| + _ => { | |
| + if self.is_overloaded_deref() { | |
| + // If we are searching for an overloaded deref, no | |
| + // need to try coercing a `~[T]` to an `&[T]` and | |
| + // searching for an overloaded deref on *that*. | |
| + None | |
| + } else { | |
| + self.search_for_autosliced_method(self_ty, autoderefs) | |
| + } | |
| + } | |
| + } | |
| + } | |
| - match self.search_for_autoptrd_method(self_ty, autoderefs) { | |
| - Some(result) => return Some(Some(result)), | |
| - None => {} | |
| - } | |
| + fn search_step(&self, | |
| + self_ty: ty::t, | |
| + autoderefs: uint) | |
| + -> Option<Option<MethodCallee>> { | |
| + debug!("search_step: self_ty={} autoderefs={}", | |
| + self.ty_to_str(self_ty), autoderefs); | |
| + | |
| + match self.deref_args { | |
| + check::DontDerefArgs => { | |
| + match self.search_for_autoderefd_method(self_ty, autoderefs) { | |
| + Some(result) => return Some(Some(result)), | |
| + None => {} | |
| } | |
| - check::DoDerefArgs => { | |
| - match self.search_for_autoptrd_method(self_ty, autoderefs) { | |
| - Some(result) => return Some(Some(result)), | |
| - None => {} | |
| - } | |
| - match self.search_for_autoderefd_method(self_ty, autoderefs) { | |
| - Some(result) => return Some(Some(result)), | |
| - None => {} | |
| - } | |
| + match self.search_for_autoptrd_method(self_ty, autoderefs) { | |
| + Some(result) => return Some(Some(result)), | |
| + None => {} | |
| } | |
| } | |
| + check::DoDerefArgs => { | |
| + match self.search_for_autoptrd_method(self_ty, autoderefs) { | |
| + Some(result) => return Some(Some(result)), | |
| + None => {} | |
| + } | |
| - // Don't autoderef if we aren't supposed to. | |
| - if self.autoderef_receiver == DontAutoderefReceiver { | |
| - Some(None) | |
| - } else { | |
| - None | |
| + match self.search_for_autoderefd_method(self_ty, autoderefs) { | |
| + Some(result) => return Some(Some(result)), | |
| + None => {} | |
| + } | |
| } | |
| - }); | |
| + } | |
| - match result { | |
| - Some(Some(result)) => Some(result), | |
| - _ => self.search_for_autosliced_method(self_ty, autoderefs) | |
| + // Don't autoderef if we aren't supposed to. | |
| + if self.autoderef_receiver == DontAutoderefReceiver { | |
| + Some(None) | |
| + } else { | |
| + None | |
| } | |
| } | |
| + fn is_overloaded_deref(&self) -> bool { | |
| + self.self_expr.is_none() | |
| + } | |
| + | |
| // ______________________________________________________________________ | |
| // Candidate collection (see comment at start of file) | |
| @@ -615,17 +639,13 @@ impl<'a> LookupContext<'a> { | |
| let (self_ty, auto_deref_ref) = | |
| self.consider_reborrow(self_ty, autoderefs); | |
| - // HACK(eddyb) only overloaded auto-deref calls should be missing | |
| - // adjustments, because we imply an AutoPtr adjustment for them. | |
| - let adjustment = match auto_deref_ref { | |
| - ty::AutoDerefRef { | |
| - autoderefs: 0, | |
| - autoref: Some(ty::AutoPtr(..)) | |
| - } => None, | |
| - _ => match self.self_expr { | |
| - Some(expr) => Some((expr.id, @ty::AutoDerefRef(auto_deref_ref))), | |
| - None => return None | |
| - } | |
| + // Hacky. For overloaded derefs, there may be an adjustment | |
| + // added to the expression from the outside context, so we do not store | |
| + // an explicit adjustment, but rather we hardwire the single deref | |
| + // that occurs in trans and mem_categorization. | |
| + let adjustment = match self.self_expr { | |
| + Some(expr) => Some((expr.id, @ty::AutoDerefRef(auto_deref_ref))), | |
| + None => return None | |
| }; | |
| match self.search_for_method(self_ty) { | |
| @@ -723,9 +743,9 @@ impl<'a> LookupContext<'a> { | |
| autoderefs: uint) | |
| -> Option<MethodCallee> { | |
| /*! | |
| - * | |
| * Searches for a candidate by converting things like | |
| - * `~[]` to `&[]`. */ | |
| + * `~[]` to `&[]`. | |
| + */ | |
| let tcx = self.tcx(); | |
| let sty = ty::get(self_ty).sty.clone(); | |
| @@ -833,15 +853,20 @@ impl<'a> LookupContext<'a> { | |
| mutbls: &[ast::Mutability], | |
| mk_autoref_ty: |ast::Mutability, ty::Region| -> ty::t) | |
| -> Option<MethodCallee> { | |
| - // HACK(eddyb) only overloaded auto-deref calls should be missing | |
| - // adjustments, because we imply an AutoPtr adjustment for them. | |
| + // Hacky. For overloaded derefs, there may be an adjustment | |
| + // added to the expression from the outside context, so we do not store | |
| + // an explicit adjustment, but rather we hardwire the single deref | |
| + // that occurs in trans and mem_categorization. | |
| 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 | |
| + None => { | |
| + assert_eq!(autoderefs, 0); | |
| + assert_eq!(kind(ty::ReEmpty, ast::MutImmutable), | |
| + ty::AutoPtr(ty::ReEmpty, ast::MutImmutable)); | |
| + None | |
| } | |
| }; | |
| + | |
| // This is hokey. We should have mutability inference as a | |
| // variable. But for now, try &const, then &, then &mut: | |
| let region = | |
| @@ -898,7 +923,8 @@ impl<'a> LookupContext<'a> { | |
| } | |
| } | |
| - fn consider_candidates(&self, rcvr_ty: ty::t, | |
| + fn consider_candidates(&self, | |
| + rcvr_ty: ty::t, | |
| candidates: &mut ~[Candidate]) | |
| -> Option<MethodCallee> { | |
| // FIXME(pcwalton): Do we need to clone here? | |
| @@ -1090,7 +1116,8 @@ impl<'a> LookupContext<'a> { | |
| &self, | |
| trait_def_id: ast::DefId, | |
| rcvr_substs: &ty::substs, | |
| - method_ty: &ty::Method) -> ty::t { | |
| + method_ty: &ty::Method) | |
| + -> ty::t { | |
| /*! | |
| * This is a bit tricky. We have a match against a trait method | |
| * being invoked on an object, and we want to generate the | |
| diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs | |
| index c05eae4..2faf358 100644 | |
| --- a/src/librustc/middle/typeck/check/mod.rs | |
| +++ b/src/librustc/middle/typeck/check/mod.rs | |
| @@ -1243,11 +1243,14 @@ pub fn autoderef<T>(fcx: @FnCtxt, sp: Span, base_ty: ty::t, | |
| should_stop: |ty::t, uint| -> Option<T>) | |
| -> (ty::t, uint, Option<T>) { | |
| /*! | |
| + * Executes an autoderef loop for the type `t`. At each step, invokes | |
| + * `should_stop` to decide whether to terminate the loop. Returns | |
| + * the final type and number of derefs that it performed. | |
| * | |
| - * Autoderefs the type `t` as many times as possible, returning a new type | |
| - * and an autoderef count. If the count is not zero, the receiver is | |
| - * responsible for inserting an AutoAdjustment record into `tcx.adjustments` | |
| - * so that trans/borrowck/etc know about this autoderef. */ | |
| + * Note: this method does not modify the adjustments table. The caller is | |
| + * responsible for inserting an AutoAdjustment record into the `fcx` | |
| + * using one of the suitable methods. | |
| + */ | |
| let mut t = base_ty; | |
| for autoderefs in range(0, fcx.tcx().sess.recursion_limit.get()) { | |
| @@ -2281,15 +2284,15 @@ fn check_expr_with_unifier(fcx: @FnCtxt, | |
| fcx.expr_ty(base)); | |
| let (_, autoderefs, field_ty) = | |
| autoderef(fcx, expr.span, expr_t, Some(base.id), lvalue_pref, |base_t, _| { | |
| - match ty::get(base_t).sty { | |
| - ty::ty_struct(base_id, ref substs) => { | |
| - debug!("struct named {}", ppaux::ty_to_str(tcx, base_t)); | |
| - let fields = ty::lookup_struct_fields(tcx, base_id); | |
| - lookup_field_ty(tcx, base_id, fields, field, &(*substs)) | |
| + match ty::get(base_t).sty { | |
| + ty::ty_struct(base_id, ref substs) => { | |
| + debug!("struct named {}", ppaux::ty_to_str(tcx, base_t)); | |
| + let fields = ty::lookup_struct_fields(tcx, base_id); | |
| + lookup_field_ty(tcx, base_id, fields, field, &(*substs)) | |
| + } | |
| + _ => None | |
| } | |
| - _ => None | |
| - } | |
| - }); | |
| + }); | |
| match field_ty { | |
| Some(field_ty) => { | |
| fcx.write_ty(expr.id, field_ty); | |
| diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs | |
| index 7efae93..42818fc 100644 | |
| --- a/src/libsyntax/ast.rs | |
| +++ b/src/libsyntax/ast.rs | |
| @@ -387,7 +387,7 @@ pub enum Pat_ { | |
| PatVec(Vec<@Pat> , Option<@Pat>, Vec<@Pat> ) | |
| } | |
| -#[deriving(Clone, Eq, Encodable, Decodable, Hash)] | |
| +#[deriving(Clone, Eq, Encodable, Decodable, Hash, Show)] | |
| pub enum Mutability { | |
| MutMutable, | |
| MutImmutable, |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment