use super::method;
use super::structurally_resolved_type;
use super::TupleArgumentsFlag;
+use super::UnresolvedTypeAction;
use super::write_call;
use middle::infer;
callee_expr.span,
original_callee_ty,
Some(callee_expr),
+ UnresolvedTypeAction::Error,
LvaluePreference::NoPreference,
|adj_ty, idx| {
let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None };
//! 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.
-use check::FnCtxt;
+use check::{autoderef, FnCtxt, NoPreference, PreferMutLvalue, UnresolvedTypeAction};
use middle::infer::{self, cres, Coercion, TypeTrace};
use middle::infer::combine::Combine;
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({} => {})",
a.repr(self.tcx()),
b.repr(self.tcx()));
ty::ty_rptr(_, mt_b) => {
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)
});
}
})
}
- // ~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,
+ expr_a: &ast::Expr,
a: Ty<'tcx>,
b: Ty<'tcx>,
mutbl_b: ast::Mutability)
// to type check, we will construct the type that `&M*expr` would
// yield.
- let coercion = Coercion(self.trace.clone());
- let r_borrow = self.fcx.infcx().next_region_var(coercion);
-
- let inner_ty = match a.sty {
+ match a.sty {
ty::ty_rptr(_, mt_a) => {
if !can_coerce_mutbls(mt_a.mutbl, mutbl_b) {
return Err(ty::terr_mutability);
}
- mt_a.ty
}
_ => return self.subtype(a, b)
- };
+ }
- let a_borrowed = ty::mk_rptr(self.tcx(),
- self.tcx().mk_region(r_borrow),
- mt {ty: inner_ty, mutbl: mutbl_b});
- try!(self.subtype(a_borrowed, b));
- if let Err(original_err) = self.subtype(a_borrowed, 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));
- Ok(Some(AdjustDerefRef(AutoDerefRef {
- autoderefs: 1,
- 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 (_, autoderefs, success) = autoderef(self.fcx,
+ 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});
+ if let Err(err) = self.fcx.infcx().try(|_| self.subtype(ty, b)) {
+ if first_error.is_none() {
+ first_error = Some(err);
+ }
+ None
+ } else {
+ Some(())
+ }
+ });
+
+ match success {
+ Some(_) => {
+ Ok(Some(AdjustDerefRef(AutoDerefRef {
+ autoderefs: autoderefs,
+ 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?"))
+ }
+ }
}
Coerce {
fcx: fcx,
trace: infer::TypeTrace::types(origin, false, a, b)
- }.coerce(a, b)
+ }.coerce(expr, a, b)
})
}));
if let Some(adjustment) = adjustment {
use super::probe;
use check::{self, FnCtxt, NoPreference, PreferMutLvalue, callee, demand};
+use check::UnresolvedTypeAction;
use middle::mem_categorization::Typer;
use middle::subst::{self};
use middle::traits;
// Commit the autoderefs by calling `autoderef again, but this
// time writing the results into the various tables.
- let (autoderefd_ty, n, result) =
- check::autoderef(
- self.fcx, self.span, unadjusted_self_ty, Some(self.self_expr), NoPreference,
- |_, n| if n == auto_deref_ref.autoderefs { Some(()) } else { None });
+ let (autoderefd_ty, n, result) = check::autoderef(self.fcx,
+ self.span,
+ unadjusted_self_ty,
+ 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!(result, Some(()));
// yield an object-type (e.g., `&Object` or `Box<Object>`
// etc).
- let (_, _, result) =
- check::autoderef(
- self.fcx, self.span, self_ty, None, NoPreference,
- |ty, _| {
- match ty.sty {
- ty::ty_trait(ref data) => Some(closure(self, ty, &**data)),
- _ => None,
- }
- });
+ let (_, _, result) = check::autoderef(self.fcx,
+ self.span,
+ self_ty,
+ None,
+ UnresolvedTypeAction::Error,
+ NoPreference,
+ |ty, _| {
+ match ty.sty {
+ ty::ty_trait(ref data) => Some(closure(self, ty, &**data)),
+ _ => None,
+ }
+ });
match result {
Some(r) => r,
expr.span,
self.fcx.expr_ty(expr),
Some(expr),
+ UnresolvedTypeAction::Error,
PreferMutLvalue,
|_, autoderefs| {
if autoderefs == autoderef_count + 1 {
use super::suggest;
use check;
-use check::{FnCtxt, NoPreference};
+use check::{FnCtxt, NoPreference, UnresolvedTypeAction};
use middle::fast_reject;
use middle::subst;
use middle::subst::Subst;
-> Option<Vec<CandidateStep<'tcx>>> {
let mut steps = Vec::new();
- let (fully_dereferenced_ty, dereferences, _) =
- check::autoderef(
- fcx, span, self_ty, None, NoPreference,
- |t, d| {
- let adjustment = AutoDeref(d);
- steps.push(CandidateStep { self_ty: t, adjustment: adjustment });
- None::<()> // keep iterating until we can't anymore
- });
-
- match fully_dereferenced_ty.sty {
+ let (final_ty, dereferences, _) = check::autoderef(fcx,
+ span,
+ self_ty,
+ None,
+ UnresolvedTypeAction::Error,
+ NoPreference,
+ |t, d| {
+ let adjustment = AutoDeref(d);
+ steps.push(CandidateStep { self_ty: t, adjustment: adjustment });
+ None::<()> // keep iterating until we can't anymore
+ });
+
+ match final_ty.sty {
ty::ty_vec(elem_ty, Some(len)) => {
steps.push(CandidateStep {
self_ty: ty::mk_vec(fcx.tcx(), elem_ty, None),
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
/// whether to terminate the loop. Returns the final type and number of derefs that it performed.
///
sp: Span,
base_ty: Ty<'tcx>,
opt_expr: Option<&ast::Expr>,
+ unresolved_type_action: UnresolvedTypeAction,
mut lvalue_pref: LvaluePreference,
mut should_stop: F)
-> (Ty<'tcx>, uint, Option<T>)
let mut t = base_ty;
for autoderefs in 0..fcx.tcx().sess.recursion_limit.get() {
- let resolved_t = structurally_resolved_type(fcx, sp, t);
-
- if ty::type_is_error(resolved_t) {
- return (resolved_t, autoderefs, None);
- }
+ let resolved_t = match unresolved_type_action {
+ UnresolvedTypeAction::Error => {
+ let resolved_t = structurally_resolved_type(fcx, sp, t);
+ if ty::type_is_error(resolved_t) {
+ 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) {
Some(x) => return (resolved_t, autoderefs, Some(x)),
// autoderef that normal method probing does. They could likely be
// consolidated.
- let (ty, autoderefs, final_mt) =
- autoderef(fcx, base_expr.span, base_ty, Some(base_expr), lvalue_pref, |adj_ty, idx| {
+ let (ty, autoderefs, final_mt) = autoderef(fcx,
+ base_expr.span,
+ base_ty,
+ Some(base_expr),
+ UnresolvedTypeAction::Error,
+ lvalue_pref,
+ |adj_ty, idx| {
let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None };
step(adj_ty, autoderefref)
});
let expr_t = structurally_resolved_type(fcx, expr.span,
fcx.expr_ty(base));
// FIXME(eddyb) #12808 Integrate privacy into this auto-deref loop.
- let (_, autoderefs, field_ty) =
- autoderef(fcx, expr.span, expr_t, Some(base), lvalue_pref, |base_t, _| {
+ let (_, autoderefs, field_ty) = autoderef(fcx,
+ expr.span,
+ expr_t,
+ Some(base),
+ UnresolvedTypeAction::Error,
+ lvalue_pref,
+ |base_t, _| {
match base_t.sty {
ty::ty_struct(base_id, substs) => {
debug!("struct named {}", ppaux::ty_to_string(tcx, base_t));
fcx.expr_ty(base));
let mut tuple_like = false;
// FIXME(eddyb) #12808 Integrate privacy into this auto-deref loop.
- let (_, autoderefs, field_ty) =
- autoderef(fcx, expr.span, expr_t, Some(base), lvalue_pref, |base_t, _| {
+ let (_, autoderefs, field_ty) = autoderef(fcx,
+ expr.span,
+ expr_t,
+ Some(base),
+ UnresolvedTypeAction::Error,
+ lvalue_pref,
+ |base_t, _| {
match base_t.sty {
ty::ty_struct(base_id, substs) => {
tuple_like = ty::is_tuple_struct(tcx, base_id);
--- /dev/null
+// 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() {}
//~| found `Foo`
//~| expected &-ptr
//~| found struct `Foo`
- Foo::bar(&&x); //~ ERROR mismatched types
- //~| expected `&Foo`
- //~| found `&&Foo`
- //~| expected struct `Foo`
- //~| found &-ptr
Foo::bar(&42is); //~ ERROR mismatched types
//~| expected `&Foo`
//~| found `&isize`
--- /dev/null
+// 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() {}