Region + borrow checker support and tests for overloaded autoderef.
This commit is contained in:
parent
feedd37653
commit
27c62449db
8 changed files with 540 additions and 24 deletions
|
@ -326,6 +326,39 @@ impl<'a> GatherLoanCtxt<'a> {
|
|||
assert_eq!(id, popped);
|
||||
}
|
||||
|
||||
pub fn guarantee_autoderefs(&mut self,
|
||||
expr: &ast::Expr,
|
||||
autoderefs: uint) {
|
||||
let method_map = self.bccx.method_map.borrow();
|
||||
for i in range(0, autoderefs) {
|
||||
match method_map.get().find(&MethodCall::autoderef(expr.id, i as u32)) {
|
||||
Some(method) => {
|
||||
// Treat overloaded autoderefs as if an AutoRef adjustment
|
||||
// was applied on the base type, as that is always the case.
|
||||
let mut mc = self.bccx.mc();
|
||||
let cmt = match mc.cat_expr_autoderefd(expr, i) {
|
||||
Ok(v) => v,
|
||||
Err(()) => self.tcx().sess.span_bug(expr.span, "Err from mc")
|
||||
};
|
||||
let self_ty = *ty::ty_fn_args(method.ty).get(0);
|
||||
let (m, r) = match ty::get(self_ty).sty {
|
||||
ty::ty_rptr(r, ref m) => (m.mutbl, r),
|
||||
_ => self.tcx().sess.span_bug(expr.span,
|
||||
format!("bad overloaded deref type {}",
|
||||
method.ty.repr(self.tcx())))
|
||||
};
|
||||
self.guarantee_valid(expr.id,
|
||||
expr.span,
|
||||
cmt,
|
||||
m,
|
||||
r,
|
||||
AutoRef);
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn guarantee_adjustments(&mut self,
|
||||
expr: &ast::Expr,
|
||||
adjustment: &ty::AutoAdjustment) {
|
||||
|
@ -341,15 +374,17 @@ impl<'a> GatherLoanCtxt<'a> {
|
|||
|
||||
ty::AutoDerefRef(
|
||||
ty::AutoDerefRef {
|
||||
autoref: None, .. }) => {
|
||||
autoref: None, autoderefs }) => {
|
||||
debug!("no autoref");
|
||||
self.guarantee_autoderefs(expr, autoderefs);
|
||||
return;
|
||||
}
|
||||
|
||||
ty::AutoDerefRef(
|
||||
ty::AutoDerefRef {
|
||||
autoref: Some(ref autoref),
|
||||
autoderefs: autoderefs}) => {
|
||||
autoderefs}) => {
|
||||
self.guarantee_autoderefs(expr, autoderefs);
|
||||
let mut mc = self.bccx.mc();
|
||||
let cmt = match mc.cat_expr_autoderefd(expr, autoderefs) {
|
||||
Ok(v) => v,
|
||||
|
|
|
@ -141,6 +141,19 @@ use syntax::codemap::Span;
|
|||
use syntax::visit;
|
||||
use syntax::visit::Visitor;
|
||||
|
||||
// If mem categorization results in an error, it's because the type
|
||||
// check failed (or will fail, when the error is uncovered and
|
||||
// reported during writeback). In this case, we just ignore this part
|
||||
// of the code and don't try to add any more region constraints.
|
||||
macro_rules! ignore_err(
|
||||
($inp: expr) => (
|
||||
match $inp {
|
||||
Ok(v) => v,
|
||||
Err(()) => return
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
pub struct Rcx {
|
||||
fcx: @FnCtxt,
|
||||
errors_reported: uint,
|
||||
|
@ -395,7 +408,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
|
|||
match **adjustment {
|
||||
ty::AutoDerefRef(ty::AutoDerefRef {autoderefs, autoref: opt_autoref}) => {
|
||||
let expr_ty = rcx.resolve_node_type(expr.id);
|
||||
constrain_derefs(rcx, expr, autoderefs, expr_ty);
|
||||
constrain_autoderefs(rcx, expr, autoderefs, expr_ty);
|
||||
for autoref in opt_autoref.iter() {
|
||||
link_autoref(rcx, expr, autoderefs, autoref);
|
||||
|
||||
|
@ -494,7 +507,13 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
|
|||
}
|
||||
None => rcx.resolve_node_type(base.id)
|
||||
};
|
||||
constrain_derefs(rcx, expr, 1, base_ty);
|
||||
match ty::get(base_ty).sty {
|
||||
ty::ty_rptr(r_ptr, _) => {
|
||||
mk_subregion_due_to_derefence(rcx, expr.span,
|
||||
ty::ReScope(expr.id), r_ptr);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
visit::walk_expr(rcx, expr, ());
|
||||
}
|
||||
|
@ -819,11 +838,10 @@ fn constrain_call(rcx: &mut Rcx,
|
|||
fn_sig.output);
|
||||
}
|
||||
|
||||
fn constrain_derefs(rcx: &mut Rcx,
|
||||
deref_expr: &ast::Expr,
|
||||
derefs: uint,
|
||||
mut derefd_ty: ty::t)
|
||||
{
|
||||
fn constrain_autoderefs(rcx: &mut Rcx,
|
||||
deref_expr: &ast::Expr,
|
||||
derefs: uint,
|
||||
mut derefd_ty: ty::t) {
|
||||
/*!
|
||||
* Invoked on any dereference that occurs, whether explicitly
|
||||
* or through an auto-deref. Checks that if this is a region
|
||||
|
@ -832,16 +850,46 @@ fn constrain_derefs(rcx: &mut Rcx,
|
|||
*/
|
||||
let r_deref_expr = ty::ReScope(deref_expr.id);
|
||||
for i in range(0u, derefs) {
|
||||
debug!("constrain_derefs(deref_expr=?, derefd_ty={}, derefs={:?}/{:?}",
|
||||
debug!("constrain_autoderefs(deref_expr=?, derefd_ty={}, derefs={:?}/{:?}",
|
||||
rcx.fcx.infcx().ty_to_str(derefd_ty),
|
||||
i, derefs);
|
||||
|
||||
let method_call = MethodCall::autoderef(deref_expr.id, i as u32);
|
||||
derefd_ty = match rcx.fcx.inh.method_map.get().find(&method_call) {
|
||||
Some(method) => {
|
||||
// Treat overloaded autoderefs as if an AutoRef adjustment
|
||||
// was applied on the base type, as that is always the case.
|
||||
let fn_sig = ty::ty_fn_sig(method.ty);
|
||||
let self_ty = *fn_sig.inputs.get(0);
|
||||
let (m, r) = match ty::get(self_ty).sty {
|
||||
ty::ty_rptr(r, ref m) => (m.mutbl, r),
|
||||
_ => rcx.tcx().sess.span_bug(deref_expr.span,
|
||||
format!("bad overloaded deref type {}",
|
||||
method.ty.repr(rcx.tcx())))
|
||||
};
|
||||
{
|
||||
let mut mc = mc::MemCategorizationContext { typer: &mut *rcx };
|
||||
let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i));
|
||||
link_region(mc.typer, deref_expr.span, r, m, self_cmt);
|
||||
}
|
||||
|
||||
// Specialized version of constrain_call.
|
||||
constrain_regions_in_type(rcx, r_deref_expr,
|
||||
infer::CallRcvr(deref_expr.span),
|
||||
self_ty);
|
||||
constrain_regions_in_type(rcx, r_deref_expr,
|
||||
infer::CallReturn(deref_expr.span),
|
||||
fn_sig.output);
|
||||
fn_sig.output
|
||||
}
|
||||
None => derefd_ty
|
||||
};
|
||||
|
||||
match ty::get(derefd_ty).sty {
|
||||
ty::ty_rptr(r_ptr, _) => {
|
||||
mk_subregion_due_to_derefence(rcx, deref_expr.span,
|
||||
r_deref_expr, r_ptr);
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
@ -965,19 +1013,6 @@ fn constrain_regions_in_type(
|
|||
return e == rcx.errors_reported;
|
||||
}
|
||||
|
||||
// If mem categorization results in an error, it's because the type
|
||||
// check failed (or will fail, when the error is uncovered and
|
||||
// reported during writeback). In this case, we just ignore this part
|
||||
// of the code and don't try to add any more region constraints.
|
||||
macro_rules! ignore_err(
|
||||
($inp: expr) => (
|
||||
match $inp {
|
||||
Ok(v) => { v }
|
||||
Err(()) => { return; }
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
fn link_addr_of(rcx: &mut Rcx, expr: &ast::Expr,
|
||||
mutability: ast::Mutability, base: &ast::Expr) {
|
||||
/*!
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
// Copyright 2014 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.
|
||||
|
||||
// Test how overloaded deref interacts with borrows when DerefMut
|
||||
// is implemented.
|
||||
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
struct Own<T> {
|
||||
value: *mut T
|
||||
}
|
||||
|
||||
impl<T> Deref<T> for Own<T> {
|
||||
fn deref<'a>(&'a self) -> &'a T {
|
||||
unsafe { &*self.value }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DerefMut<T> for Own<T> {
|
||||
fn deref_mut<'a>(&'a mut self) -> &'a mut T {
|
||||
unsafe { &mut *self.value }
|
||||
}
|
||||
}
|
||||
|
||||
struct Point {
|
||||
x: int,
|
||||
y: int
|
||||
}
|
||||
|
||||
impl Point {
|
||||
fn get(&self) -> (int, int) {
|
||||
(self.x, self.y)
|
||||
}
|
||||
|
||||
fn set(&mut self, x: int, y: int) {
|
||||
self.x = x;
|
||||
self.y = y;
|
||||
}
|
||||
|
||||
fn x_ref<'a>(&'a self) -> &'a int {
|
||||
&self.x
|
||||
}
|
||||
|
||||
fn y_mut<'a>(&'a mut self) -> &'a mut int {
|
||||
&mut self.y
|
||||
}
|
||||
}
|
||||
|
||||
fn deref_imm_field(x: Own<Point>) {
|
||||
let _i = &x.y;
|
||||
}
|
||||
|
||||
fn deref_mut_field1(x: Own<Point>) {
|
||||
let _i = &mut x.y; //~ ERROR cannot borrow
|
||||
}
|
||||
|
||||
fn deref_mut_field2(mut x: Own<Point>) {
|
||||
let _i = &mut x.y;
|
||||
}
|
||||
|
||||
fn deref_extend_field<'a>(x: &'a Own<Point>) -> &'a int {
|
||||
&x.y
|
||||
}
|
||||
|
||||
fn deref_extend_mut_field1<'a>(x: &'a Own<Point>) -> &'a mut int {
|
||||
&mut x.y //~ ERROR cannot borrow
|
||||
}
|
||||
|
||||
fn deref_extend_mut_field2<'a>(x: &'a mut Own<Point>) -> &'a mut int {
|
||||
&mut x.y
|
||||
}
|
||||
|
||||
fn assign_field1<'a>(x: Own<Point>) {
|
||||
x.y = 3; //~ ERROR cannot borrow
|
||||
}
|
||||
|
||||
fn assign_field2<'a>(x: &'a Own<Point>) {
|
||||
x.y = 3; //~ ERROR cannot assign
|
||||
}
|
||||
|
||||
fn assign_field3<'a>(x: &'a mut Own<Point>) {
|
||||
x.y = 3;
|
||||
}
|
||||
|
||||
// FIXME(eddyb) #12825 This shouldn't attempt to call deref_mut.
|
||||
/*
|
||||
fn deref_imm_method(x: Own<Point>) {
|
||||
let _i = x.get();
|
||||
}
|
||||
*/
|
||||
|
||||
fn deref_mut_method1(x: Own<Point>) {
|
||||
x.set(0, 0); //~ ERROR cannot borrow
|
||||
}
|
||||
|
||||
fn deref_mut_method2(mut x: Own<Point>) {
|
||||
x.set(0, 0);
|
||||
}
|
||||
|
||||
fn deref_extend_method<'a>(x: &'a Own<Point>) -> &'a int {
|
||||
x.x_ref()
|
||||
}
|
||||
|
||||
fn deref_extend_mut_method1<'a>(x: &'a Own<Point>) -> &'a mut int {
|
||||
x.y_mut() //~ ERROR cannot borrow
|
||||
}
|
||||
|
||||
fn deref_extend_mut_method2<'a>(x: &'a mut Own<Point>) -> &'a mut int {
|
||||
x.y_mut()
|
||||
}
|
||||
|
||||
fn assign_method1<'a>(x: Own<Point>) {
|
||||
*x.y_mut() = 3; //~ ERROR cannot borrow
|
||||
}
|
||||
|
||||
fn assign_method2<'a>(x: &'a Own<Point>) {
|
||||
*x.y_mut() = 3; //~ ERROR cannot borrow
|
||||
}
|
||||
|
||||
fn assign_method3<'a>(x: &'a mut Own<Point>) {
|
||||
*x.y_mut() = 3;
|
||||
}
|
||||
|
||||
pub fn main() {}
|
122
src/test/compile-fail/borrowck-borrow-overloaded-auto-deref.rs
Normal file
122
src/test/compile-fail/borrowck-borrow-overloaded-auto-deref.rs
Normal file
|
@ -0,0 +1,122 @@
|
|||
// Copyright 2014 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.
|
||||
|
||||
// Test how overloaded deref interacts with borrows when only
|
||||
// Deref and not DerefMut is implemented.
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
struct Rc<T> {
|
||||
value: *T
|
||||
}
|
||||
|
||||
impl<T> Deref<T> for Rc<T> {
|
||||
fn deref<'a>(&'a self) -> &'a T {
|
||||
unsafe { &*self.value }
|
||||
}
|
||||
}
|
||||
|
||||
struct Point {
|
||||
x: int,
|
||||
y: int
|
||||
}
|
||||
|
||||
impl Point {
|
||||
fn get(&self) -> (int, int) {
|
||||
(self.x, self.y)
|
||||
}
|
||||
|
||||
fn set(&mut self, x: int, y: int) {
|
||||
self.x = x;
|
||||
self.y = y;
|
||||
}
|
||||
|
||||
fn x_ref<'a>(&'a self) -> &'a int {
|
||||
&self.x
|
||||
}
|
||||
|
||||
fn y_mut<'a>(&'a mut self) -> &'a mut int {
|
||||
&mut self.y
|
||||
}
|
||||
}
|
||||
|
||||
fn deref_imm_field(x: Rc<Point>) {
|
||||
let _i = &x.y;
|
||||
}
|
||||
|
||||
fn deref_mut_field1(x: Rc<Point>) {
|
||||
let _i = &mut x.y; //~ ERROR cannot borrow
|
||||
}
|
||||
|
||||
fn deref_mut_field2(mut x: Rc<Point>) {
|
||||
let _i = &mut x.y; //~ ERROR cannot borrow
|
||||
}
|
||||
|
||||
fn deref_extend_field<'a>(x: &'a Rc<Point>) -> &'a int {
|
||||
&x.y
|
||||
}
|
||||
|
||||
fn deref_extend_mut_field1<'a>(x: &'a Rc<Point>) -> &'a mut int {
|
||||
&mut x.y //~ ERROR cannot borrow
|
||||
}
|
||||
|
||||
fn deref_extend_mut_field2<'a>(x: &'a mut Rc<Point>) -> &'a mut int {
|
||||
&mut x.y //~ ERROR cannot borrow
|
||||
}
|
||||
|
||||
fn assign_field1<'a>(x: Rc<Point>) {
|
||||
x.y = 3; //~ ERROR cannot assign
|
||||
}
|
||||
|
||||
fn assign_field2<'a>(x: &'a Rc<Point>) {
|
||||
x.y = 3; //~ ERROR cannot assign
|
||||
}
|
||||
|
||||
fn assign_field3<'a>(x: &'a mut Rc<Point>) {
|
||||
x.y = 3; //~ ERROR cannot assign
|
||||
}
|
||||
|
||||
fn deref_imm_method(x: Rc<Point>) {
|
||||
let _i = x.get();
|
||||
}
|
||||
|
||||
fn deref_mut_method1(x: Rc<Point>) {
|
||||
x.set(0, 0); //~ ERROR cannot borrow
|
||||
}
|
||||
|
||||
fn deref_mut_method2(mut x: Rc<Point>) {
|
||||
x.set(0, 0); //~ ERROR cannot borrow
|
||||
}
|
||||
|
||||
fn deref_extend_method<'a>(x: &'a Rc<Point>) -> &'a int {
|
||||
x.x_ref()
|
||||
}
|
||||
|
||||
fn deref_extend_mut_method1<'a>(x: &'a Rc<Point>) -> &'a mut int {
|
||||
x.y_mut() //~ ERROR cannot borrow
|
||||
}
|
||||
|
||||
fn deref_extend_mut_method2<'a>(x: &'a mut Rc<Point>) -> &'a mut int {
|
||||
x.y_mut() //~ ERROR cannot borrow
|
||||
}
|
||||
|
||||
fn assign_method1<'a>(x: Rc<Point>) {
|
||||
*x.y_mut() = 3; //~ ERROR cannot borrow
|
||||
}
|
||||
|
||||
fn assign_method2<'a>(x: &'a Rc<Point>) {
|
||||
*x.y_mut() = 3; //~ ERROR cannot borrow
|
||||
}
|
||||
|
||||
fn assign_method3<'a>(x: &'a mut Rc<Point>) {
|
||||
*x.y_mut() = 3; //~ ERROR cannot borrow
|
||||
}
|
||||
|
||||
pub fn main() {}
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2014 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::rc::Rc;
|
||||
|
||||
pub fn main() {
|
||||
let _x = Rc::new(vec!(1, 2)).move_iter();
|
||||
//~^ ERROR cannot move out of dereference of `&`-pointer
|
||||
}
|
82
src/test/run-pass/overloaded-autoderef-count.rs
Normal file
82
src/test/run-pass/overloaded-autoderef-count.rs
Normal file
|
@ -0,0 +1,82 @@
|
|||
// Copyright 2014 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::cell::Cell;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::vec_ng::Vec;
|
||||
|
||||
#[deriving(Eq)]
|
||||
struct DerefCounter<T> {
|
||||
count_imm: Cell<uint>,
|
||||
count_mut: uint,
|
||||
value: T
|
||||
}
|
||||
|
||||
impl<T> DerefCounter<T> {
|
||||
fn new(value: T) -> DerefCounter<T> {
|
||||
DerefCounter {
|
||||
count_imm: Cell::new(0),
|
||||
count_mut: 0,
|
||||
value: value
|
||||
}
|
||||
}
|
||||
|
||||
fn counts(&self) -> (uint, uint) {
|
||||
(self.count_imm.get(), self.count_mut)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref<T> for DerefCounter<T> {
|
||||
fn deref<'a>(&'a self) -> &'a T {
|
||||
self.count_imm.set(self.count_imm.get() + 1);
|
||||
&self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DerefMut<T> for DerefCounter<T> {
|
||||
fn deref_mut<'a>(&'a mut self) -> &'a mut T {
|
||||
self.count_mut += 1;
|
||||
&mut self.value
|
||||
}
|
||||
}
|
||||
|
||||
#[deriving(Eq, Show)]
|
||||
struct Point {
|
||||
x: int,
|
||||
y: int
|
||||
}
|
||||
|
||||
impl Point {
|
||||
fn get(&self) -> (int, int) {
|
||||
(self.x, self.y)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let mut p = DerefCounter::new(Point {x: 0, y: 0});
|
||||
|
||||
let _ = p.x;
|
||||
assert_eq!(p.counts(), (1, 0));
|
||||
|
||||
let _ = &p.x;
|
||||
assert_eq!(p.counts(), (2, 0));
|
||||
|
||||
let _ = &mut p.y;
|
||||
assert_eq!(p.counts(), (2, 1));
|
||||
|
||||
p.x += 3;
|
||||
assert_eq!(p.counts(), (2, 2));
|
||||
|
||||
p.get();
|
||||
assert_eq!(p.counts(), (2, 3));
|
||||
|
||||
// Check the final state.
|
||||
assert_eq!(*p, Point {x: 3, y: 0});
|
||||
}
|
24
src/test/run-pass/overloaded-autoderef-indexing.rs
Normal file
24
src/test/run-pass/overloaded-autoderef-indexing.rs
Normal file
|
@ -0,0 +1,24 @@
|
|||
// Copyright 2014 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.
|
||||
|
||||
struct DerefArray<'a, T> {
|
||||
inner: &'a [T]
|
||||
}
|
||||
|
||||
impl<'a, T> Deref<&'a [T]> for DerefArray<'a, T> {
|
||||
fn deref<'b>(&'b self) -> &'b &'a [T] {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let a = &[1, 2, 3];
|
||||
assert_eq!(DerefArray {inner: a}[1], 2);
|
||||
}
|
71
src/test/run-pass/overloaded-autoderef-order.rs
Normal file
71
src/test/run-pass/overloaded-autoderef-order.rs
Normal file
|
@ -0,0 +1,71 @@
|
|||
// Copyright 2014 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::rc::Rc;
|
||||
|
||||
struct DerefWrapper<X, Y> {
|
||||
x: X,
|
||||
y: Y
|
||||
}
|
||||
|
||||
impl<X, Y> DerefWrapper<X, Y> {
|
||||
fn get_x(self) -> X {
|
||||
self.x
|
||||
}
|
||||
}
|
||||
|
||||
impl<X, Y> Deref<Y> for DerefWrapper<X, Y> {
|
||||
fn deref<'a>(&'a self) -> &'a Y {
|
||||
&self.y
|
||||
}
|
||||
}
|
||||
|
||||
mod priv_test {
|
||||
pub struct DerefWrapperHideX<X, Y> {
|
||||
priv x: X,
|
||||
y: Y
|
||||
}
|
||||
|
||||
impl<X, Y> DerefWrapperHideX<X, Y> {
|
||||
pub fn new(x: X, y: Y) -> DerefWrapperHideX<X, Y> {
|
||||
DerefWrapperHideX {
|
||||
x: x,
|
||||
y: y
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<X, Y> Deref<Y> for DerefWrapperHideX<X, Y> {
|
||||
fn deref<'a>(&'a self) -> &'a Y {
|
||||
&self.y
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let nested = DerefWrapper {x: true, y: DerefWrapper {x: 0, y: 1}};
|
||||
|
||||
// Use the first field that you can find.
|
||||
assert_eq!(nested.x, true);
|
||||
assert_eq!((*nested).x, 0);
|
||||
|
||||
// Same for methods, even though there are multiple
|
||||
// candidates (at different nesting levels).
|
||||
assert_eq!(nested.get_x(), true);
|
||||
assert_eq!((*nested).get_x(), 0);
|
||||
|
||||
// Also go through multiple levels of indirection.
|
||||
assert_eq!(Rc::new(nested).x, true);
|
||||
|
||||
let nested_priv = priv_test::DerefWrapperHideX::new(true, DerefWrapper {x: 0, y: 1});
|
||||
// FIXME(eddyb) #12808 should skip private fields.
|
||||
// assert_eq!(nested_priv.x, 0);
|
||||
assert_eq!((*nested_priv).x, 0);
|
||||
}
|
Loading…
Add table
Reference in a new issue