Implement deref coercions (rust-lang/rfcs#241).
This commit is contained in:
parent
b48c4c8cf4
commit
ae076e1e3b
8 changed files with 260 additions and 59 deletions
|
@ -21,6 +21,7 @@ use super::LvaluePreference;
|
||||||
use super::method;
|
use super::method;
|
||||||
use super::structurally_resolved_type;
|
use super::structurally_resolved_type;
|
||||||
use super::TupleArgumentsFlag;
|
use super::TupleArgumentsFlag;
|
||||||
|
use super::UnresolvedTypeAction;
|
||||||
use super::write_call;
|
use super::write_call;
|
||||||
|
|
||||||
use middle::infer;
|
use middle::infer;
|
||||||
|
@ -77,6 +78,7 @@ pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||||
callee_expr.span,
|
callee_expr.span,
|
||||||
original_callee_ty,
|
original_callee_ty,
|
||||||
Some(callee_expr),
|
Some(callee_expr),
|
||||||
|
UnresolvedTypeAction::Error,
|
||||||
LvaluePreference::NoPreference,
|
LvaluePreference::NoPreference,
|
||||||
|adj_ty, idx| {
|
|adj_ty, idx| {
|
||||||
let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None };
|
let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None };
|
||||||
|
|
|
@ -60,7 +60,7 @@
|
||||||
//! sort of a minor point so I've opted to leave it for later---after all
|
//! sort of a minor point so I've opted to leave it for later---after all
|
||||||
//! we may want to adjust precisely when coercions occur.
|
//! we may want to adjust precisely when coercions occur.
|
||||||
|
|
||||||
use check::FnCtxt;
|
use check::{autoderef, FnCtxt, NoPreference, PreferMutLvalue, UnresolvedTypeAction};
|
||||||
|
|
||||||
use middle::infer::{self, cres, Coercion, TypeTrace};
|
use middle::infer::{self, cres, Coercion, TypeTrace};
|
||||||
use middle::infer::combine::Combine;
|
use middle::infer::combine::Combine;
|
||||||
|
@ -98,7 +98,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||||
f(self.fcx.infcx().shallow_resolve(a))
|
f(self.fcx.infcx().shallow_resolve(a))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
|
fn coerce(&self,
|
||||||
|
expr_a: &ast::Expr,
|
||||||
|
a: Ty<'tcx>,
|
||||||
|
b: Ty<'tcx>)
|
||||||
|
-> CoerceResult<'tcx> {
|
||||||
debug!("Coerce.tys({} => {})",
|
debug!("Coerce.tys({} => {})",
|
||||||
a.repr(self.tcx()),
|
a.repr(self.tcx()),
|
||||||
b.repr(self.tcx()));
|
b.repr(self.tcx()));
|
||||||
|
@ -124,7 +128,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||||
|
|
||||||
ty::ty_rptr(_, mt_b) => {
|
ty::ty_rptr(_, mt_b) => {
|
||||||
return self.unpack_actual_value(a, |a| {
|
return self.unpack_actual_value(a, |a| {
|
||||||
self.coerce_borrowed_pointer(a, b, mt_b.mutbl)
|
self.coerce_borrowed_pointer(expr_a, a, b, mt_b.mutbl)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,8 +151,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// ~T -> &T or &mut T -> &T (including where T = [U] or str)
|
/// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.
|
||||||
|
/// To match `A` with `B`, autoderef will be performed,
|
||||||
|
/// calling `deref`/`deref_mut` where necessary.
|
||||||
fn coerce_borrowed_pointer(&self,
|
fn coerce_borrowed_pointer(&self,
|
||||||
|
expr_a: &ast::Expr,
|
||||||
a: Ty<'tcx>,
|
a: Ty<'tcx>,
|
||||||
b: Ty<'tcx>,
|
b: Ty<'tcx>,
|
||||||
mutbl_b: ast::Mutability)
|
mutbl_b: ast::Mutability)
|
||||||
|
@ -163,30 +170,63 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||||
// to type check, we will construct the type that `&M*expr` would
|
// to type check, we will construct the type that `&M*expr` would
|
||||||
// yield.
|
// yield.
|
||||||
|
|
||||||
let coercion = Coercion(self.trace.clone());
|
match a.sty {
|
||||||
let r_borrow = self.fcx.infcx().next_region_var(coercion);
|
|
||||||
|
|
||||||
let inner_ty = match a.sty {
|
|
||||||
ty::ty_rptr(_, mt_a) => {
|
ty::ty_rptr(_, mt_a) => {
|
||||||
if !can_coerce_mutbls(mt_a.mutbl, mutbl_b) {
|
if !can_coerce_mutbls(mt_a.mutbl, mutbl_b) {
|
||||||
return Err(ty::terr_mutability);
|
return Err(ty::terr_mutability);
|
||||||
}
|
}
|
||||||
mt_a.ty
|
|
||||||
}
|
}
|
||||||
_ => return self.subtype(a, b)
|
_ => return self.subtype(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
let coercion = Coercion(self.trace.clone());
|
||||||
|
let r_borrow = self.fcx.infcx().next_region_var(coercion);
|
||||||
|
let autoref = Some(AutoPtr(r_borrow, mutbl_b, None));
|
||||||
|
|
||||||
|
let r_borrow = self.tcx().mk_region(r_borrow);
|
||||||
|
let lvalue_pref = match mutbl_b {
|
||||||
|
ast::MutMutable => PreferMutLvalue,
|
||||||
|
ast::MutImmutable => NoPreference
|
||||||
};
|
};
|
||||||
|
let mut first_error = None;
|
||||||
let a_borrowed = ty::mk_rptr(self.tcx(),
|
let (_, autoderefs, success) = autoderef(self.fcx,
|
||||||
self.tcx().mk_region(r_borrow),
|
expr_a.span,
|
||||||
|
a,
|
||||||
|
Some(expr_a),
|
||||||
|
UnresolvedTypeAction::Ignore,
|
||||||
|
lvalue_pref,
|
||||||
|
|inner_ty, autoderef| {
|
||||||
|
if autoderef == 0 {
|
||||||
|
// Don't let this pass, otherwise it would cause
|
||||||
|
// &T to autoref to &&T.
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let ty = ty::mk_rptr(self.tcx(), r_borrow,
|
||||||
mt {ty: inner_ty, mutbl: mutbl_b});
|
mt {ty: inner_ty, mutbl: mutbl_b});
|
||||||
try!(self.subtype(a_borrowed, b));
|
if let Err(err) = self.fcx.infcx().try(|_| self.subtype(ty, b)) {
|
||||||
if let Err(original_err) = self.subtype(a_borrowed, b) {
|
if first_error.is_none() {
|
||||||
|
first_error = Some(err);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
match success {
|
||||||
|
Some(_) => {
|
||||||
Ok(Some(AdjustDerefRef(AutoDerefRef {
|
Ok(Some(AdjustDerefRef(AutoDerefRef {
|
||||||
autoderefs: 1,
|
autoderefs: autoderefs,
|
||||||
autoref: Some(AutoPtr(r_borrow, mutbl_b, None))
|
autoref: autoref
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
None => {
|
||||||
|
// Return original error as if overloaded deref was never
|
||||||
|
// attempted, to avoid irrelevant/confusing error messages.
|
||||||
|
Err(first_error.expect("coerce_borrowed_pointer failed with no error?"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// &[T, ..n] or &mut [T, ..n] -> &[T]
|
// &[T, ..n] or &mut [T, ..n] -> &[T]
|
||||||
|
@ -426,7 +466,7 @@ pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||||
Coerce {
|
Coerce {
|
||||||
fcx: fcx,
|
fcx: fcx,
|
||||||
trace: infer::TypeTrace::types(origin, false, a, b)
|
trace: infer::TypeTrace::types(origin, false, a, b)
|
||||||
}.coerce(a, b)
|
}.coerce(expr, a, b)
|
||||||
})
|
})
|
||||||
}));
|
}));
|
||||||
if let Some(adjustment) = adjustment {
|
if let Some(adjustment) = adjustment {
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
use super::probe;
|
use super::probe;
|
||||||
|
|
||||||
use check::{self, FnCtxt, NoPreference, PreferMutLvalue, callee, demand};
|
use check::{self, FnCtxt, NoPreference, PreferMutLvalue, callee, demand};
|
||||||
|
use check::UnresolvedTypeAction;
|
||||||
use middle::mem_categorization::Typer;
|
use middle::mem_categorization::Typer;
|
||||||
use middle::subst::{self};
|
use middle::subst::{self};
|
||||||
use middle::traits;
|
use middle::traits;
|
||||||
|
@ -141,10 +142,19 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
||||||
|
|
||||||
// Commit the autoderefs by calling `autoderef again, but this
|
// Commit the autoderefs by calling `autoderef again, but this
|
||||||
// time writing the results into the various tables.
|
// time writing the results into the various tables.
|
||||||
let (autoderefd_ty, n, result) =
|
let (autoderefd_ty, n, result) = check::autoderef(self.fcx,
|
||||||
check::autoderef(
|
self.span,
|
||||||
self.fcx, self.span, unadjusted_self_ty, Some(self.self_expr), NoPreference,
|
unadjusted_self_ty,
|
||||||
|_, n| if n == auto_deref_ref.autoderefs { Some(()) } else { None });
|
Some(self.self_expr),
|
||||||
|
UnresolvedTypeAction::Error,
|
||||||
|
NoPreference,
|
||||||
|
|_, n| {
|
||||||
|
if n == auto_deref_ref.autoderefs {
|
||||||
|
Some(())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
});
|
||||||
assert_eq!(n, auto_deref_ref.autoderefs);
|
assert_eq!(n, auto_deref_ref.autoderefs);
|
||||||
assert_eq!(result, Some(()));
|
assert_eq!(result, Some(()));
|
||||||
|
|
||||||
|
@ -302,9 +312,12 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
||||||
// yield an object-type (e.g., `&Object` or `Box<Object>`
|
// yield an object-type (e.g., `&Object` or `Box<Object>`
|
||||||
// etc).
|
// etc).
|
||||||
|
|
||||||
let (_, _, result) =
|
let (_, _, result) = check::autoderef(self.fcx,
|
||||||
check::autoderef(
|
self.span,
|
||||||
self.fcx, self.span, self_ty, None, NoPreference,
|
self_ty,
|
||||||
|
None,
|
||||||
|
UnresolvedTypeAction::Error,
|
||||||
|
NoPreference,
|
||||||
|ty, _| {
|
|ty, _| {
|
||||||
match ty.sty {
|
match ty.sty {
|
||||||
ty::ty_trait(ref data) => Some(closure(self, ty, &**data)),
|
ty::ty_trait(ref data) => Some(closure(self, ty, &**data)),
|
||||||
|
@ -517,6 +530,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
||||||
expr.span,
|
expr.span,
|
||||||
self.fcx.expr_ty(expr),
|
self.fcx.expr_ty(expr),
|
||||||
Some(expr),
|
Some(expr),
|
||||||
|
UnresolvedTypeAction::Error,
|
||||||
PreferMutLvalue,
|
PreferMutLvalue,
|
||||||
|_, autoderefs| {
|
|_, autoderefs| {
|
||||||
if autoderefs == autoderef_count + 1 {
|
if autoderefs == autoderef_count + 1 {
|
||||||
|
|
|
@ -14,7 +14,7 @@ use super::{CandidateSource,ImplSource,TraitSource};
|
||||||
use super::suggest;
|
use super::suggest;
|
||||||
|
|
||||||
use check;
|
use check;
|
||||||
use check::{FnCtxt, NoPreference};
|
use check::{FnCtxt, NoPreference, UnresolvedTypeAction};
|
||||||
use middle::fast_reject;
|
use middle::fast_reject;
|
||||||
use middle::subst;
|
use middle::subst;
|
||||||
use middle::subst::Subst;
|
use middle::subst::Subst;
|
||||||
|
@ -169,16 +169,19 @@ fn create_steps<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||||
-> Option<Vec<CandidateStep<'tcx>>> {
|
-> Option<Vec<CandidateStep<'tcx>>> {
|
||||||
let mut steps = Vec::new();
|
let mut steps = Vec::new();
|
||||||
|
|
||||||
let (fully_dereferenced_ty, dereferences, _) =
|
let (final_ty, dereferences, _) = check::autoderef(fcx,
|
||||||
check::autoderef(
|
span,
|
||||||
fcx, span, self_ty, None, NoPreference,
|
self_ty,
|
||||||
|
None,
|
||||||
|
UnresolvedTypeAction::Error,
|
||||||
|
NoPreference,
|
||||||
|t, d| {
|
|t, d| {
|
||||||
let adjustment = AutoDeref(d);
|
let adjustment = AutoDeref(d);
|
||||||
steps.push(CandidateStep { self_ty: t, adjustment: adjustment });
|
steps.push(CandidateStep { self_ty: t, adjustment: adjustment });
|
||||||
None::<()> // keep iterating until we can't anymore
|
None::<()> // keep iterating until we can't anymore
|
||||||
});
|
});
|
||||||
|
|
||||||
match fully_dereferenced_ty.sty {
|
match final_ty.sty {
|
||||||
ty::ty_vec(elem_ty, Some(len)) => {
|
ty::ty_vec(elem_ty, Some(len)) => {
|
||||||
steps.push(CandidateStep {
|
steps.push(CandidateStep {
|
||||||
self_ty: ty::mk_vec(fcx.tcx(), elem_ty, None),
|
self_ty: ty::mk_vec(fcx.tcx(), elem_ty, None),
|
||||||
|
|
|
@ -1865,6 +1865,17 @@ pub enum LvaluePreference {
|
||||||
NoPreference
|
NoPreference
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether `autoderef` requires types to resolve.
|
||||||
|
#[derive(Copy, Show, PartialEq, Eq)]
|
||||||
|
pub enum UnresolvedTypeAction {
|
||||||
|
/// Produce an error and return `ty_err` whenever a type cannot
|
||||||
|
/// be resolved (i.e. it is `ty_infer`).
|
||||||
|
Error,
|
||||||
|
/// Go on without emitting any errors, and return the unresolved
|
||||||
|
/// type. Useful for probing, e.g. in coercions.
|
||||||
|
Ignore
|
||||||
|
}
|
||||||
|
|
||||||
/// Executes an autoderef loop for the type `t`. At each step, invokes `should_stop` to decide
|
/// Executes an autoderef loop for the type `t`. At each step, invokes `should_stop` to decide
|
||||||
/// whether to terminate the loop. Returns the final type and number of derefs that it performed.
|
/// whether to terminate the loop. Returns the final type and number of derefs that it performed.
|
||||||
///
|
///
|
||||||
|
@ -1874,6 +1885,7 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||||
sp: Span,
|
sp: Span,
|
||||||
base_ty: Ty<'tcx>,
|
base_ty: Ty<'tcx>,
|
||||||
opt_expr: Option<&ast::Expr>,
|
opt_expr: Option<&ast::Expr>,
|
||||||
|
unresolved_type_action: UnresolvedTypeAction,
|
||||||
mut lvalue_pref: LvaluePreference,
|
mut lvalue_pref: LvaluePreference,
|
||||||
mut should_stop: F)
|
mut should_stop: F)
|
||||||
-> (Ty<'tcx>, uint, Option<T>)
|
-> (Ty<'tcx>, uint, Option<T>)
|
||||||
|
@ -1886,11 +1898,22 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||||
|
|
||||||
let mut t = base_ty;
|
let mut t = base_ty;
|
||||||
for autoderefs in 0..fcx.tcx().sess.recursion_limit.get() {
|
for autoderefs in 0..fcx.tcx().sess.recursion_limit.get() {
|
||||||
|
let resolved_t = match unresolved_type_action {
|
||||||
|
UnresolvedTypeAction::Error => {
|
||||||
let resolved_t = structurally_resolved_type(fcx, sp, t);
|
let resolved_t = structurally_resolved_type(fcx, sp, t);
|
||||||
|
|
||||||
if ty::type_is_error(resolved_t) {
|
if ty::type_is_error(resolved_t) {
|
||||||
return (resolved_t, autoderefs, None);
|
return (resolved_t, autoderefs, None);
|
||||||
}
|
}
|
||||||
|
resolved_t
|
||||||
|
}
|
||||||
|
UnresolvedTypeAction::Ignore => {
|
||||||
|
// We can continue even when the type cannot be resolved
|
||||||
|
// (i.e. it is an inference variable) because `ty::deref`
|
||||||
|
// and `try_overloaded_deref` both simply return `None`
|
||||||
|
// in such a case without producing spurious errors.
|
||||||
|
fcx.resolve_type_vars_if_possible(t)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
match should_stop(resolved_t, autoderefs) {
|
match should_stop(resolved_t, autoderefs) {
|
||||||
Some(x) => return (resolved_t, autoderefs, Some(x)),
|
Some(x) => return (resolved_t, autoderefs, Some(x)),
|
||||||
|
@ -2011,8 +2034,13 @@ fn autoderef_for_index<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||||
// autoderef that normal method probing does. They could likely be
|
// autoderef that normal method probing does. They could likely be
|
||||||
// consolidated.
|
// consolidated.
|
||||||
|
|
||||||
let (ty, autoderefs, final_mt) =
|
let (ty, autoderefs, final_mt) = autoderef(fcx,
|
||||||
autoderef(fcx, base_expr.span, base_ty, Some(base_expr), lvalue_pref, |adj_ty, idx| {
|
base_expr.span,
|
||||||
|
base_ty,
|
||||||
|
Some(base_expr),
|
||||||
|
UnresolvedTypeAction::Error,
|
||||||
|
lvalue_pref,
|
||||||
|
|adj_ty, idx| {
|
||||||
let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None };
|
let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None };
|
||||||
step(adj_ty, autoderefref)
|
step(adj_ty, autoderefref)
|
||||||
});
|
});
|
||||||
|
@ -3053,8 +3081,13 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||||
let expr_t = structurally_resolved_type(fcx, expr.span,
|
let expr_t = structurally_resolved_type(fcx, expr.span,
|
||||||
fcx.expr_ty(base));
|
fcx.expr_ty(base));
|
||||||
// FIXME(eddyb) #12808 Integrate privacy into this auto-deref loop.
|
// FIXME(eddyb) #12808 Integrate privacy into this auto-deref loop.
|
||||||
let (_, autoderefs, field_ty) =
|
let (_, autoderefs, field_ty) = autoderef(fcx,
|
||||||
autoderef(fcx, expr.span, expr_t, Some(base), lvalue_pref, |base_t, _| {
|
expr.span,
|
||||||
|
expr_t,
|
||||||
|
Some(base),
|
||||||
|
UnresolvedTypeAction::Error,
|
||||||
|
lvalue_pref,
|
||||||
|
|base_t, _| {
|
||||||
match base_t.sty {
|
match base_t.sty {
|
||||||
ty::ty_struct(base_id, substs) => {
|
ty::ty_struct(base_id, substs) => {
|
||||||
debug!("struct named {}", ppaux::ty_to_string(tcx, base_t));
|
debug!("struct named {}", ppaux::ty_to_string(tcx, base_t));
|
||||||
|
@ -3146,8 +3179,13 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||||
fcx.expr_ty(base));
|
fcx.expr_ty(base));
|
||||||
let mut tuple_like = false;
|
let mut tuple_like = false;
|
||||||
// FIXME(eddyb) #12808 Integrate privacy into this auto-deref loop.
|
// FIXME(eddyb) #12808 Integrate privacy into this auto-deref loop.
|
||||||
let (_, autoderefs, field_ty) =
|
let (_, autoderefs, field_ty) = autoderef(fcx,
|
||||||
autoderef(fcx, expr.span, expr_t, Some(base), lvalue_pref, |base_t, _| {
|
expr.span,
|
||||||
|
expr_t,
|
||||||
|
Some(base),
|
||||||
|
UnresolvedTypeAction::Error,
|
||||||
|
lvalue_pref,
|
||||||
|
|base_t, _| {
|
||||||
match base_t.sty {
|
match base_t.sty {
|
||||||
ty::ty_struct(base_id, substs) => {
|
ty::ty_struct(base_id, substs) => {
|
||||||
tuple_like = ty::is_tuple_struct(tcx, base_id);
|
tuple_like = ty::is_tuple_struct(tcx, base_id);
|
||||||
|
|
40
src/test/compile-fail/coerce-overloaded-autoderef.rs
Normal file
40
src/test/compile-fail/coerce-overloaded-autoderef.rs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
fn borrow_mut<T>(x: &mut T) -> &mut T { x }
|
||||||
|
fn borrow<T>(x: &T) -> &T { x }
|
||||||
|
|
||||||
|
fn borrow_mut2<T>(_: &mut T, _: &mut T) {}
|
||||||
|
fn borrow2<T>(_: &mut T, _: &T) {}
|
||||||
|
|
||||||
|
fn double_mut_borrow<T>(x: &mut Box<T>) {
|
||||||
|
let y = borrow_mut(x);
|
||||||
|
let z = borrow_mut(x);
|
||||||
|
//~^ ERROR cannot borrow `*x` as mutable more than once at a time
|
||||||
|
}
|
||||||
|
|
||||||
|
fn double_imm_borrow(x: &mut Box<i32>) {
|
||||||
|
let y = borrow(x);
|
||||||
|
let z = borrow(x);
|
||||||
|
**x += 1;
|
||||||
|
//~^ ERROR cannot assign to `**x` because it is borrowed
|
||||||
|
}
|
||||||
|
|
||||||
|
fn double_mut_borrow2<T>(x: &mut Box<T>) {
|
||||||
|
borrow_mut2(x, x);
|
||||||
|
//~^ ERROR cannot borrow `*x` as mutable more than once at a time
|
||||||
|
}
|
||||||
|
|
||||||
|
fn double_borrow2<T>(x: &mut Box<T>) {
|
||||||
|
borrow2(x, x);
|
||||||
|
//~^ ERROR cannot borrow `*x` as immutable because it is also borrowed as mutable
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {}
|
|
@ -23,11 +23,6 @@ fn main() {
|
||||||
//~| found `Foo`
|
//~| found `Foo`
|
||||||
//~| expected &-ptr
|
//~| expected &-ptr
|
||||||
//~| found struct `Foo`
|
//~| found struct `Foo`
|
||||||
Foo::bar(&&x); //~ ERROR mismatched types
|
|
||||||
//~| expected `&Foo`
|
|
||||||
//~| found `&&Foo`
|
|
||||||
//~| expected struct `Foo`
|
|
||||||
//~| found &-ptr
|
|
||||||
Foo::bar(&42is); //~ ERROR mismatched types
|
Foo::bar(&42is); //~ ERROR mismatched types
|
||||||
//~| expected `&Foo`
|
//~| expected `&Foo`
|
||||||
//~| found `&isize`
|
//~| found `&isize`
|
||||||
|
|
69
src/test/run-pass/coerce-overloaded-autoderef.rs
Normal file
69
src/test/run-pass/coerce-overloaded-autoderef.rs
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// Examples from the "deref coercions" RFC, at rust-lang/rfcs#241.
|
||||||
|
|
||||||
|
fn use_ref<T>(_: &T) {}
|
||||||
|
fn use_mut<T>(_: &mut T) {}
|
||||||
|
|
||||||
|
fn use_rc<T>(t: Rc<T>) {
|
||||||
|
use_ref(&*t); // what you have to write today
|
||||||
|
use_ref(&t); // what you'd be able to write
|
||||||
|
use_ref(&&&&&&t);
|
||||||
|
use_ref(&mut &&&&&t);
|
||||||
|
use_ref(&&&mut &&&t);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn use_mut_box<T>(mut t: &mut Box<T>) {
|
||||||
|
use_mut(&mut *t); // what you have to write today
|
||||||
|
use_mut(t); // what you'd be able to write
|
||||||
|
use_mut(&mut &mut &mut t);
|
||||||
|
|
||||||
|
use_ref(&*t); // what you have to write today
|
||||||
|
use_ref(t); // what you'd be able to write
|
||||||
|
use_ref(&&&&&&t);
|
||||||
|
use_ref(&mut &&&&&t);
|
||||||
|
use_ref(&&&mut &&&t);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn use_nested<T>(t: &Box<T>) {
|
||||||
|
use_ref(&**t); // what you have to write today
|
||||||
|
use_ref(t); // what you'd be able to write (note: recursive deref)
|
||||||
|
use_ref(&&&&&&t);
|
||||||
|
use_ref(&mut &&&&&t);
|
||||||
|
use_ref(&&&mut &&&t);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn use_slice(_: &[u8]) {}
|
||||||
|
fn use_slice_mut(_: &mut [u8]) {}
|
||||||
|
|
||||||
|
fn use_vec(mut v: Vec<u8>) {
|
||||||
|
use_slice_mut(&mut v[]); // what you have to write today
|
||||||
|
use_slice_mut(&mut v); // what you'd be able to write
|
||||||
|
use_slice_mut(&mut &mut &mut v);
|
||||||
|
|
||||||
|
use_slice(&v[]); // what you have to write today
|
||||||
|
use_slice(&v); // what you'd be able to write
|
||||||
|
use_slice(&&&&&&v);
|
||||||
|
use_slice(&mut &&&&&v);
|
||||||
|
use_slice(&&&mut &&&v);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn use_vec_ref(v: &Vec<u8>) {
|
||||||
|
use_slice(&v[]); // what you have to write today
|
||||||
|
use_slice(v); // what you'd be able to write
|
||||||
|
use_slice(&&&&&&v);
|
||||||
|
use_slice(&mut &&&&&v);
|
||||||
|
use_slice(&&&mut &&&v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {}
|
Loading…
Reference in a new issue