Change:
Previously to , there were no real issues with the current method lookup implementation, which collects candidates and picks the first one in the auto-deref chain, without caring too much about mutability. The problematic case introduces was where is an overloaded dereference, calling either or . However, the method could take - which we can't know until we've picked one of or and continued to the lookup of . The choice I've made was to always try (if not obviously immutable, e.g. x having a type of instead of or ) first, and that will work for 's , which only had a mutable method previously. In it gets worse as the issue can happen at any auto-deref level, and here's a test case that fails to compile: cc
cc me
Another test case: This fail to compile, but if it's changed to it compiles just fine.
I've been working, by the way, on a prototype of a new trait / method resolution algorithm that resolves issue (among many others). I hope to include it in a general RFC for very shortly.
Same issue with Index/IndexMut, ftr.
Nominating, if this is going to block vec switching to -syntax I believe this is a 1.0 blocker.
Assigning 1.0 milestone, P-backcompat-lang.
I'm going to go ahead and assign this to
We need to change precedence so that inherent and trait impls are on equal footing instead of having inherent impls be first.
Is this really fixed? example from above still fails to compile, and is incidentally very similar to the example in , which also does not compile.
Should this issue be reopend or un-comment the ?
I've confirmed that is still not working properly, so we still can't provide full indexing notation on vectors. Note that this is why this issue was nominated and approved as a 1.0 blocker. would you prefer me to re-open this issue or create a new one?
Reopening.

Discussion:
} } <del> // FIXME(#12825) Indexing will always try IndexMut first and that causes issues. /*impl<T> IndexMut<uint,T> for Vec<T> { </del> <ins> #[cfg(not(stage0))] impl<T> IndexMut<uint,T> for Vec<T> { </ins> #[inline] fn index_mut<'a>(&'a mut self, index: &uint) -> &'a mut T { self.get_mut(*index) } <del> }*/ </del> <ins> } </ins> #[cfg(stage0)] impl<T> ops::Slice<uint, [T]> for Vec<T> {

match result { Some(Some(result)) => { <del> self.fixup_derefs_on_method_receiver_if_necessary(&result, self_ty); </del> <ins> self.fixup_derefs_on_method_receiver_if_necessary(&result); </ins> Some(result) } _ => None

fn fixup_derefs_on_method_receiver_if_necessary( &self, <del> method_callee: &MethodCallee, self_ty: ty::t) { </del> <ins> method_callee: &MethodCallee) { </ins> let sig = match ty::get(method_callee.ty).sty { ty::ty_bare_fn(ref f) => f.sig.clone(), ty::ty_closure(ref f) => f.sig.clone(),

_ => return, } <del> // Fix up autoderefs and derefs. let mut self_expr = match self.self_expr { Some(expr) => expr, None => return, }; </del> <ins> // Gather up expressions we want to munge. let mut exprs = Vec::new(); match self.self_expr { Some(expr) => exprs.push(expr), None => {} } </ins> loop { <ins> if exprs.len() == 0 { break } let last = exprs[exprs.len() - 1]; match last.node { ast::ExprParen(ref expr) | ast::ExprField(ref expr, _, _) | ast::ExprTupField(ref expr, _, _) | ast::ExprSlice(ref expr, _, _, _) | ast::ExprIndex(ref expr, _) | ast::ExprUnary(ast::UnDeref, ref expr) => exprs.push(&**expr), _ => break, } } // Fix up autoderefs and derefs. for (i, expr) in exprs.iter().rev().enumerate() { </ins> // Count autoderefs. let autoderef_count = match self.fcx .inh .adjustments .borrow() <del> .find(&self_expr.id) { </del> <ins> .find(&expr.id) { </ins> Some(&ty::AdjustDerefRef(ty::AutoDerefRef { autoderefs: autoderef_count, autoref: _ <del> })) if autoderef_count > 0 => autoderef_count, Some(_) | None => return, </del> <ins> })) => autoderef_count, Some(_) | None => 0, </ins> }; <del> check::autoderef(self.fcx, self_expr.span, self.fcx.expr_ty(self_expr), Some(self_expr.id), PreferMutLvalue, |_, autoderefs| { if autoderefs == autoderef_count + 1 { Some(()) } else { None } }); match self_expr.node { ast::ExprParen(ref expr) | ast::ExprIndex(ref expr, _) | ast::ExprField(ref expr, _, _) | ast::ExprTupField(ref expr, _, _) | ast::ExprSlice(ref expr, _, _, _) => self_expr = &**expr, ast::ExprUnary(ast::UnDeref, ref expr) => { drop(check::try_overloaded_deref( self.fcx, self_expr.span, Some(MethodCall::expr(self_expr.id)), Some(self_expr), self_ty, PreferMutLvalue)); self_expr = &**expr </del> <ins> if autoderef_count > 0 { check::autoderef(self.fcx, expr.span, self.fcx.expr_ty(*expr), Some(expr.id), PreferMutLvalue, |_, autoderefs| { if autoderefs == autoderef_count + 1 { Some(()) } else { None } }); } // Don't retry the first one or we might infinite loop! if i != 0 { match expr.node { ast::ExprIndex(ref base_expr, ref index_expr) => { check::try_overloaded_index( self.fcx, Some(MethodCall::expr(expr.id)), *expr, &**base_expr, self.fcx.expr_ty(&**base_expr), index_expr, PreferMutLvalue); } ast::ExprUnary(ast::UnDeref, ref base_expr) => { check::try_overloaded_deref( self.fcx, expr.span, Some(MethodCall::expr(expr.id)), Some(&**base_expr), self.fcx.expr_ty(&**base_expr), PreferMutLvalue); } _ => {} </ins> } <del> _ => break, </del> } } }

expr: &ast::Expr, method_name: ast::SpannedIdent, args: &[P<ast::Expr>], <del> tps: &[P<ast::Ty>]) { </del> <ins> tps: &[P<ast::Ty>], lvalue_pref: LvaluePreference) { </ins> let rcvr = &*args[0]; <del> // We can't know if we need &mut self before we look up the method, // so treat the receiver as mutable just in case - only explicit // overloaded dereferences care about the distinction. check_expr_with_lvalue_pref(fcx, &*rcvr, PreferMutLvalue); </del> <ins> check_expr_with_lvalue_pref(fcx, &*rcvr, lvalue_pref); </ins> // no need to check for bot/err -- callee does that let expr_t = structurally_resolved_type(fcx,

} } ast::ExprMethodCall(ident, ref tps, ref args) => { <del> check_method_call(fcx, expr, ident, args.as_slice(), tps.as_slice()); </del> <ins> check_method_call(fcx, expr, ident, args.as_slice(), tps.as_slice(), lvalue_pref); </ins> let mut arg_tys = args.iter().map(|a| fcx.expr_ty(&**a)); let (args_bot, args_err) = arg_tys.fold((false, false), |(rest_bot, rest_err), a| {

*n -= 3; // Mutable deref + assignment with binary operation. assert_eq!(n.counts(), (2, 3)); <del> // Mutable deref used for calling a method taking &self. // N.B. This is required because method lookup hasn't been performed so // we don't know whether the called method takes mutable self, before // the dereference itself is type-checked (a chicken-and-egg problem). </del> <ins> // Immutable deref used for calling a method taking &self. (The // typechecker is smarter now about doing this.) </ins> (*n).to_string(); <del> assert_eq!(n.counts(), (2, 4)); </del> <ins> assert_eq!(n.counts(), (3, 3)); </ins> // Mutable deref used for calling a method taking &mut self. (*v).push(2);