Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

try to fix lvalue ops for real #41828

Merged
merged 1 commit into from
May 9, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 31 additions & 17 deletions src/librustc_typeck/check/method/confirm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,22 +433,11 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
for (i, &expr) in exprs.iter().rev().enumerate() {
debug!("convert_lvalue_derefs_to_mutable: i={} expr={:?}", i, expr);

// Fix up the adjustment.
let autoderefs = match self.tables.borrow_mut().adjustments.get_mut(&expr.id) {
Some(&mut Adjustment {
kind: Adjust::DerefRef { autoderefs, ref mut autoref, .. }, ref mut target
}) => {
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
}
// Fix up the autoderefs. Autorefs can only occur immediately preceding
// overloaded lvalue ops, and will be fixed by them in order to get
// the correct region.
let autoderefs = match self.tables.borrow().adjustments.get(&expr.id) {
Some(&Adjustment { kind: Adjust::DerefRef { autoderefs, .. }, .. }) => autoderefs,
Some(_) | None => 0
};

Expand Down Expand Up @@ -502,10 +491,35 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {

let method = self.try_overloaded_lvalue_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);
debug!("convert_lvalue_op_to_mutable: method={:?}", 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?");
}
}
}

///////////////////////////////////////////////////////////////////////////
Expand Down
17 changes: 17 additions & 0 deletions src/test/compile-fail/issue-41726.rs
Original file line number Diff line number Diff line change
@@ -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
}
}
35 changes: 35 additions & 0 deletions src/test/compile-fail/issue-41742.rs
Original file line number Diff line number Diff line change
@@ -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
}
26 changes: 26 additions & 0 deletions src/test/compile-fail/regions-adjusted-lvalue-op.rs
Original file line number Diff line number Diff line change
@@ -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
}