Skip to content

Commit 27c6244

Browse files
committed
Region + borrow checker support and tests for overloaded autoderef.
1 parent feedd37 commit 27c6244

File tree

8 files changed

+540
-24
lines changed

8 files changed

+540
-24
lines changed

src/librustc/middle/borrowck/gather_loans/mod.rs

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,39 @@ impl<'a> GatherLoanCtxt<'a> {
326326
assert_eq!(id, popped);
327327
}
328328

329+
pub fn guarantee_autoderefs(&mut self,
330+
expr: &ast::Expr,
331+
autoderefs: uint) {
332+
let method_map = self.bccx.method_map.borrow();
333+
for i in range(0, autoderefs) {
334+
match method_map.get().find(&MethodCall::autoderef(expr.id, i as u32)) {
335+
Some(method) => {
336+
// Treat overloaded autoderefs as if an AutoRef adjustment
337+
// was applied on the base type, as that is always the case.
338+
let mut mc = self.bccx.mc();
339+
let cmt = match mc.cat_expr_autoderefd(expr, i) {
340+
Ok(v) => v,
341+
Err(()) => self.tcx().sess.span_bug(expr.span, "Err from mc")
342+
};
343+
let self_ty = *ty::ty_fn_args(method.ty).get(0);
344+
let (m, r) = match ty::get(self_ty).sty {
345+
ty::ty_rptr(r, ref m) => (m.mutbl, r),
346+
_ => self.tcx().sess.span_bug(expr.span,
347+
format!("bad overloaded deref type {}",
348+
method.ty.repr(self.tcx())))
349+
};
350+
self.guarantee_valid(expr.id,
351+
expr.span,
352+
cmt,
353+
m,
354+
r,
355+
AutoRef);
356+
}
357+
None => {}
358+
}
359+
}
360+
}
361+
329362
pub fn guarantee_adjustments(&mut self,
330363
expr: &ast::Expr,
331364
adjustment: &ty::AutoAdjustment) {
@@ -341,15 +374,17 @@ impl<'a> GatherLoanCtxt<'a> {
341374

342375
ty::AutoDerefRef(
343376
ty::AutoDerefRef {
344-
autoref: None, .. }) => {
377+
autoref: None, autoderefs }) => {
345378
debug!("no autoref");
379+
self.guarantee_autoderefs(expr, autoderefs);
346380
return;
347381
}
348382

349383
ty::AutoDerefRef(
350384
ty::AutoDerefRef {
351385
autoref: Some(ref autoref),
352-
autoderefs: autoderefs}) => {
386+
autoderefs}) => {
387+
self.guarantee_autoderefs(expr, autoderefs);
353388
let mut mc = self.bccx.mc();
354389
let cmt = match mc.cat_expr_autoderefd(expr, autoderefs) {
355390
Ok(v) => v,

src/librustc/middle/typeck/check/regionck.rs

Lines changed: 57 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,19 @@ use syntax::codemap::Span;
141141
use syntax::visit;
142142
use syntax::visit::Visitor;
143143

144+
// If mem categorization results in an error, it's because the type
145+
// check failed (or will fail, when the error is uncovered and
146+
// reported during writeback). In this case, we just ignore this part
147+
// of the code and don't try to add any more region constraints.
148+
macro_rules! ignore_err(
149+
($inp: expr) => (
150+
match $inp {
151+
Ok(v) => v,
152+
Err(()) => return
153+
}
154+
)
155+
)
156+
144157
pub struct Rcx {
145158
fcx: @FnCtxt,
146159
errors_reported: uint,
@@ -395,7 +408,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
395408
match **adjustment {
396409
ty::AutoDerefRef(ty::AutoDerefRef {autoderefs, autoref: opt_autoref}) => {
397410
let expr_ty = rcx.resolve_node_type(expr.id);
398-
constrain_derefs(rcx, expr, autoderefs, expr_ty);
411+
constrain_autoderefs(rcx, expr, autoderefs, expr_ty);
399412
for autoref in opt_autoref.iter() {
400413
link_autoref(rcx, expr, autoderefs, autoref);
401414

@@ -494,7 +507,13 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
494507
}
495508
None => rcx.resolve_node_type(base.id)
496509
};
497-
constrain_derefs(rcx, expr, 1, base_ty);
510+
match ty::get(base_ty).sty {
511+
ty::ty_rptr(r_ptr, _) => {
512+
mk_subregion_due_to_derefence(rcx, expr.span,
513+
ty::ReScope(expr.id), r_ptr);
514+
}
515+
_ => {}
516+
}
498517

499518
visit::walk_expr(rcx, expr, ());
500519
}
@@ -819,11 +838,10 @@ fn constrain_call(rcx: &mut Rcx,
819838
fn_sig.output);
820839
}
821840

822-
fn constrain_derefs(rcx: &mut Rcx,
823-
deref_expr: &ast::Expr,
824-
derefs: uint,
825-
mut derefd_ty: ty::t)
826-
{
841+
fn constrain_autoderefs(rcx: &mut Rcx,
842+
deref_expr: &ast::Expr,
843+
derefs: uint,
844+
mut derefd_ty: ty::t) {
827845
/*!
828846
* Invoked on any dereference that occurs, whether explicitly
829847
* or through an auto-deref. Checks that if this is a region
@@ -832,16 +850,46 @@ fn constrain_derefs(rcx: &mut Rcx,
832850
*/
833851
let r_deref_expr = ty::ReScope(deref_expr.id);
834852
for i in range(0u, derefs) {
835-
debug!("constrain_derefs(deref_expr=?, derefd_ty={}, derefs={:?}/{:?}",
853+
debug!("constrain_autoderefs(deref_expr=?, derefd_ty={}, derefs={:?}/{:?}",
836854
rcx.fcx.infcx().ty_to_str(derefd_ty),
837855
i, derefs);
838856

857+
let method_call = MethodCall::autoderef(deref_expr.id, i as u32);
858+
derefd_ty = match rcx.fcx.inh.method_map.get().find(&method_call) {
859+
Some(method) => {
860+
// Treat overloaded autoderefs as if an AutoRef adjustment
861+
// was applied on the base type, as that is always the case.
862+
let fn_sig = ty::ty_fn_sig(method.ty);
863+
let self_ty = *fn_sig.inputs.get(0);
864+
let (m, r) = match ty::get(self_ty).sty {
865+
ty::ty_rptr(r, ref m) => (m.mutbl, r),
866+
_ => rcx.tcx().sess.span_bug(deref_expr.span,
867+
format!("bad overloaded deref type {}",
868+
method.ty.repr(rcx.tcx())))
869+
};
870+
{
871+
let mut mc = mc::MemCategorizationContext { typer: &mut *rcx };
872+
let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i));
873+
link_region(mc.typer, deref_expr.span, r, m, self_cmt);
874+
}
875+
876+
// Specialized version of constrain_call.
877+
constrain_regions_in_type(rcx, r_deref_expr,
878+
infer::CallRcvr(deref_expr.span),
879+
self_ty);
880+
constrain_regions_in_type(rcx, r_deref_expr,
881+
infer::CallReturn(deref_expr.span),
882+
fn_sig.output);
883+
fn_sig.output
884+
}
885+
None => derefd_ty
886+
};
887+
839888
match ty::get(derefd_ty).sty {
840889
ty::ty_rptr(r_ptr, _) => {
841890
mk_subregion_due_to_derefence(rcx, deref_expr.span,
842891
r_deref_expr, r_ptr);
843892
}
844-
845893
_ => {}
846894
}
847895

@@ -965,19 +1013,6 @@ fn constrain_regions_in_type(
9651013
return e == rcx.errors_reported;
9661014
}
9671015

968-
// If mem categorization results in an error, it's because the type
969-
// check failed (or will fail, when the error is uncovered and
970-
// reported during writeback). In this case, we just ignore this part
971-
// of the code and don't try to add any more region constraints.
972-
macro_rules! ignore_err(
973-
($inp: expr) => (
974-
match $inp {
975-
Ok(v) => { v }
976-
Err(()) => { return; }
977-
}
978-
)
979-
)
980-
9811016
fn link_addr_of(rcx: &mut Rcx, expr: &ast::Expr,
9821017
mutability: ast::Mutability, base: &ast::Expr) {
9831018
/*!
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test how overloaded deref interacts with borrows when DerefMut
12+
// is implemented.
13+
14+
use std::ops::{Deref, DerefMut};
15+
16+
struct Own<T> {
17+
value: *mut T
18+
}
19+
20+
impl<T> Deref<T> for Own<T> {
21+
fn deref<'a>(&'a self) -> &'a T {
22+
unsafe { &*self.value }
23+
}
24+
}
25+
26+
impl<T> DerefMut<T> for Own<T> {
27+
fn deref_mut<'a>(&'a mut self) -> &'a mut T {
28+
unsafe { &mut *self.value }
29+
}
30+
}
31+
32+
struct Point {
33+
x: int,
34+
y: int
35+
}
36+
37+
impl Point {
38+
fn get(&self) -> (int, int) {
39+
(self.x, self.y)
40+
}
41+
42+
fn set(&mut self, x: int, y: int) {
43+
self.x = x;
44+
self.y = y;
45+
}
46+
47+
fn x_ref<'a>(&'a self) -> &'a int {
48+
&self.x
49+
}
50+
51+
fn y_mut<'a>(&'a mut self) -> &'a mut int {
52+
&mut self.y
53+
}
54+
}
55+
56+
fn deref_imm_field(x: Own<Point>) {
57+
let _i = &x.y;
58+
}
59+
60+
fn deref_mut_field1(x: Own<Point>) {
61+
let _i = &mut x.y; //~ ERROR cannot borrow
62+
}
63+
64+
fn deref_mut_field2(mut x: Own<Point>) {
65+
let _i = &mut x.y;
66+
}
67+
68+
fn deref_extend_field<'a>(x: &'a Own<Point>) -> &'a int {
69+
&x.y
70+
}
71+
72+
fn deref_extend_mut_field1<'a>(x: &'a Own<Point>) -> &'a mut int {
73+
&mut x.y //~ ERROR cannot borrow
74+
}
75+
76+
fn deref_extend_mut_field2<'a>(x: &'a mut Own<Point>) -> &'a mut int {
77+
&mut x.y
78+
}
79+
80+
fn assign_field1<'a>(x: Own<Point>) {
81+
x.y = 3; //~ ERROR cannot borrow
82+
}
83+
84+
fn assign_field2<'a>(x: &'a Own<Point>) {
85+
x.y = 3; //~ ERROR cannot assign
86+
}
87+
88+
fn assign_field3<'a>(x: &'a mut Own<Point>) {
89+
x.y = 3;
90+
}
91+
92+
// FIXME(eddyb) #12825 This shouldn't attempt to call deref_mut.
93+
/*
94+
fn deref_imm_method(x: Own<Point>) {
95+
let _i = x.get();
96+
}
97+
*/
98+
99+
fn deref_mut_method1(x: Own<Point>) {
100+
x.set(0, 0); //~ ERROR cannot borrow
101+
}
102+
103+
fn deref_mut_method2(mut x: Own<Point>) {
104+
x.set(0, 0);
105+
}
106+
107+
fn deref_extend_method<'a>(x: &'a Own<Point>) -> &'a int {
108+
x.x_ref()
109+
}
110+
111+
fn deref_extend_mut_method1<'a>(x: &'a Own<Point>) -> &'a mut int {
112+
x.y_mut() //~ ERROR cannot borrow
113+
}
114+
115+
fn deref_extend_mut_method2<'a>(x: &'a mut Own<Point>) -> &'a mut int {
116+
x.y_mut()
117+
}
118+
119+
fn assign_method1<'a>(x: Own<Point>) {
120+
*x.y_mut() = 3; //~ ERROR cannot borrow
121+
}
122+
123+
fn assign_method2<'a>(x: &'a Own<Point>) {
124+
*x.y_mut() = 3; //~ ERROR cannot borrow
125+
}
126+
127+
fn assign_method3<'a>(x: &'a mut Own<Point>) {
128+
*x.y_mut() = 3;
129+
}
130+
131+
pub fn main() {}

0 commit comments

Comments
 (0)