try to fix lvalue ops for real

Hopefully this is the last PR needed.

Fixes #41726.
Fixes #41742.
Fixes #41774.
This commit is contained in:
Ariel Ben-Yehuda 2017-05-08 17:05:03 +03:00
parent ced823e267
commit 052d071bb2
4 changed files with 109 additions and 17 deletions

View File

@ -433,22 +433,11 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
for (i, &expr) in exprs.iter().rev().enumerate() { for (i, &expr) in exprs.iter().rev().enumerate() {
debug!("convert_lvalue_derefs_to_mutable: i={} expr={:?}", i, expr); debug!("convert_lvalue_derefs_to_mutable: i={} expr={:?}", i, expr);
// Fix up the adjustment. // Fix up the autoderefs. Autorefs can only occur immediately preceding
let autoderefs = match self.tables.borrow_mut().adjustments.get_mut(&expr.id) { // overloaded lvalue ops, and will be fixed by them in order to get
Some(&mut Adjustment { // the correct region.
kind: Adjust::DerefRef { autoderefs, ref mut autoref, .. }, ref mut target let autoderefs = match self.tables.borrow().adjustments.get(&expr.id) {
}) => { Some(&Adjustment { kind: Adjust::DerefRef { autoderefs, .. }, .. }) => autoderefs,
if let &mut Some(AutoBorrow::Ref(_, ref mut mutbl)) = autoref {
*mutbl = hir::Mutability::MutMutable;
*target = match target.sty {
ty::TyRef(r, ty::TypeAndMut { ty, .. }) =>
self.tcx.mk_ref(r, ty::TypeAndMut { ty, mutbl: *mutbl }),
_ => span_bug!(expr.span, "AutoBorrow::Ref resulted in non-ref {:?}",
target)
};
}
autoderefs
}
Some(_) | None => 0 Some(_) | None => 0
}; };
@ -502,10 +491,35 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
let method = self.try_overloaded_lvalue_op( let method = self.try_overloaded_lvalue_op(
expr.span, None, base_ty, arg_tys, PreferMutLvalue, op); expr.span, None, base_ty, arg_tys, PreferMutLvalue, op);
let ok = method.expect("re-trying op failed"); let ok = match method {
Some(method) => method,
None => return self.tcx.sess.delay_span_bug(expr.span, "re-trying op failed")
};
let method = self.register_infer_ok_obligations(ok); let method = self.register_infer_ok_obligations(ok);
debug!("convert_lvalue_op_to_mutable: method={:?}", method); debug!("convert_lvalue_op_to_mutable: method={:?}", method);
self.tables.borrow_mut().method_map.insert(method_call, method); self.tables.borrow_mut().method_map.insert(method_call, method);
// Convert the autoref in the base expr to mutable with the correct
// region and mutability.
if let Some(&mut Adjustment {
ref mut target, kind: Adjust::DerefRef {
autoref: Some(AutoBorrow::Ref(ref mut r, ref mut mutbl)), ..
}
}) = self.tables.borrow_mut().adjustments.get_mut(&base_expr.id) {
debug!("convert_lvalue_op_to_mutable: converting autoref of {:?}", target);
// extract method return type, which will be &mut T;
// all LB regions should have been instantiated during method lookup
let method_sig = self.tcx.no_late_bound_regions(&method.ty.fn_sig()).unwrap();
*target = method_sig.inputs()[0];
if let ty::TyRef(r_, mt) = target.sty {
*r = r_;
*mutbl = mt.mutbl;
} else {
span_bug!(expr.span, "input to lvalue op is not a ref?");
}
}
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,17 @@
// Copyright 2017 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::collections::HashMap;
fn main() {
let things: HashMap<String, Vec<String>> = HashMap::new();
for src in things.keys() {
things[src.as_str()].sort(); //~ ERROR cannot borrow immutable
}
}

View File

@ -0,0 +1,35 @@
// Copyright 2017 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::ops::{Index, IndexMut};
struct S;
struct H;
impl S {
fn f(&mut self) {}
}
impl Index<u32> for H {
type Output = S;
fn index(&self, index: u32) -> &S {
unimplemented!()
}
}
impl IndexMut<u32> for H {
fn index_mut(&mut self, index: u32) -> &mut S {
unimplemented!()
}
}
fn main() {
H["?"].f(); //~ ERROR mismatched types
}

View File

@ -0,0 +1,26 @@
// Copyright 2017 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.
// check that we link regions in mutable lvalue ops correctly - issue #41774
struct Data(i32);
trait OhNo {
fn oh_no(&mut self, other: &Vec<Data>) { loop {} }
}
impl OhNo for Data {}
impl OhNo for [Data] {}
fn main() {
let mut v = vec![Data(0)];
v[0].oh_no(&v); //~ ERROR cannot borrow `v` as immutable because
(*v).oh_no(&v); //~ ERROR cannot borrow `v` as immutable because
}