]> git.lizzy.rs Git - rust.git/commitdiff
Rewrite the coercion code to be more readable, more sound, and to reborrow when
authorNiko Matsakis <niko@alum.mit.edu>
Wed, 23 Jan 2013 01:20:08 +0000 (17:20 -0800)
committerNiko Matsakis <niko@alum.mit.edu>
Mon, 28 Jan 2013 18:01:59 +0000 (10:01 -0800)
needed.

Regarding soundness: there was a subtle bug in how it was done before; see the
compile-fail test for an example.

Regarding reborrowing: reborrowing allows mut and const
slices/borrowed-pointers to be used with pure fns that expect immutable data.

r=brson

23 files changed:
src/librustc/middle/typeck/check/_match.rs
src/librustc/middle/typeck/check/demand.rs
src/librustc/middle/typeck/check/method.rs
src/librustc/middle/typeck/check/mod.rs
src/librustc/middle/typeck/check/writeback.rs
src/librustc/middle/typeck/infer/coercion.rs
src/librustc/middle/typeck/infer/mod.rs
src/librustc/middle/typeck/infer/resolve.rs
src/test/compile-fail/borrowck-borrowed-uniq-rvalue.rs
src/test/compile-fail/coerce-bad-variance.rs [new file with mode: 0644]
src/test/compile-fail/issue-4500.rs
src/test/compile-fail/kindck-owned-trait-contains.rs
src/test/compile-fail/regions-scoping.rs
src/test/run-pass/coerce-reborrow-imm-ptr-arg.rs [new file with mode: 0644]
src/test/run-pass/coerce-reborrow-imm-ptr-rcvr.rs [new file with mode: 0644]
src/test/run-pass/coerce-reborrow-imm-vec-arg.rs [new file with mode: 0644]
src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs [new file with mode: 0644]
src/test/run-pass/coerce-reborrow-mut-ptr-arg.rs [new file with mode: 0644]
src/test/run-pass/coerce-reborrow-mut-ptr-rcvr.rs [new file with mode: 0644]
src/test/run-pass/coerce-reborrow-mut-vec-arg.rs [new file with mode: 0644]
src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs [new file with mode: 0644]
src/test/run-pass/issue-3026.rs
src/test/run-pass/let-assignability.rs

index 2e82d531e155911b371039f97146e9ae34dada88..ebfce27a4c8bb6d3dbbc25bb1332c302fb360a4c 100644 (file)
@@ -15,7 +15,7 @@
 use middle::ty;
 use middle::typeck::check::demand;
 use middle::typeck::check::{check_block, check_expr_has_type, fn_ctxt};
-use middle::typeck::check::{instantiate_path, lookup_def, lookup_local};
+use middle::typeck::check::{instantiate_path, lookup_def};
 use middle::typeck::check::{structure_of, valid_range_bounds};
 use middle::typeck::require_same_types;
 
@@ -365,8 +365,7 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) {
         fcx.write_ty(pat.id, const_tpt.ty);
       }
       ast::pat_ident(bm, name, sub) if pat_is_binding(tcx.def_map, pat) => {
-        let vid = lookup_local(fcx, pat.span, pat.id);
-        let mut typ = ty::mk_var(tcx, vid);
+        let typ = fcx.local_ty(pat.span, pat.id);
 
         match bm {
           ast::bind_by_ref(mutbl) => {
@@ -389,8 +388,7 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) {
 
         let canon_id = pcx.map.get(ast_util::path_to_ident(name));
         if canon_id != pat.id {
-            let tv_id = lookup_local(fcx, pat.span, canon_id);
-            let ct = ty::mk_var(tcx, tv_id);
+            let ct = fcx.local_ty(pat.span, canon_id);
             demand::eqtype(fcx, pat.span, ct, typ);
         }
         fcx.write_ty(pat.id, typ);
index c8aaf2ca61b495cc3f461549802e398e7421edbb..c8a644fef101ce42493186d829cc74b3a6ba9d69 100644 (file)
@@ -50,7 +50,10 @@ fn eqtype(fcx: @fn_ctxt, sp: span, expected: ty::t, actual: ty::t) {
 }
 
 // Checks that the type `actual` can be coerced to `expected`.
-fn coerce(fcx: @fn_ctxt, sp: span, expected: ty::t, expr: @ast::expr) {
+fn coerce(fcx: @fn_ctxt,
+          sp: span,
+          expected: ty::t,
+          expr: @ast::expr) {
     let expr_ty = fcx.expr_ty(expr);
     match fcx.mk_assignty(expr, expr_ty, expected) {
       result::Ok(()) => { /* ok */ }
index 7ef6ae598803e3b0b1af67c471c1c41acebc807d..238e4e8c3f7726278811a277fd1dc6761c1b9917 100644 (file)
@@ -700,6 +700,8 @@ fn search_for_autoderefd_method(
         autoderefs: uint)
         -> Option<method_map_entry>
     {
+        let (self_ty, autoadjust) =
+            self.consider_reborrow(self_ty, autoderefs);
         match self.search_for_method(self_ty) {
             None => None,
             Some(move mme) => {
@@ -707,13 +709,82 @@ fn search_for_autoderefd_method(
                        adjustment (%u) to %d",
                        autoderefs,
                        self.self_expr.id);
-                self.fcx.write_autoderef_adjustment(
-                    self.self_expr.id, autoderefs);
+                self.fcx.write_adjustment(self.self_expr.id, @autoadjust);
                 Some(mme)
             }
         }
     }
 
+    fn consider_reborrow(&self,
+                         self_ty: ty::t,
+                         autoderefs: uint) -> (ty::t, ty::AutoAdjustment)
+    {
+        /*!
+         *
+         * In the event that we are invoking a method with a receiver
+         * of a linear borrowed type like `&mut T` or `&[mut T]`,
+         * we will "reborrow" the receiver implicitly.  For example, if
+         * you have a call `r.inc()` and where `r` has type `&mut T`,
+         * then we treat that like `(&mut *r).inc()`.  This avoids
+         * consuming the original pointer.
+         *
+         * You might think that this would be a natural byproduct of
+         * the auto-deref/auto-ref process.  This is true for `@mut T`
+         * but not for an `&mut T` receiver.  With `@mut T`, we would
+         * begin by testing for methods with a self type `@mut T`,
+         * then autoderef to `T`, then autoref to `&mut T`.  But with
+         * an `&mut T` receiver the process begins with `&mut T`, only
+         * without any autoadjustments.
+         */
+
+        let tcx = self.tcx();
+        return match ty::get(self_ty).sty {
+            ty::ty_rptr(self_r, self_mt) if self_mt.mutbl == m_mutbl => {
+                let region = fresh_region(self, self_r);
+                (ty::mk_rptr(tcx, region, self_mt),
+                 ty::AutoAdjustment {
+                     autoderefs: autoderefs+1,
+                     autoref: Some(ty::AutoRef {kind: AutoPtr,
+                                                region: region,
+                                                mutbl: self_mt.mutbl})})
+            }
+            ty::ty_evec(self_mt, vstore_slice(self_r))
+            if self_mt.mutbl == m_mutbl => {
+                let region = fresh_region(self, self_r);
+                (ty::mk_evec(tcx, self_mt, vstore_slice(region)),
+                 ty::AutoAdjustment {
+                    autoderefs: autoderefs,
+                    autoref: Some(ty::AutoRef {kind: AutoBorrowVec,
+                                               region: region,
+                                               mutbl: self_mt.mutbl})})
+            }
+            _ => {
+                (self_ty, ty::AutoAdjustment {autoderefs: autoderefs,
+                                              autoref: None})
+            }
+        };
+
+        fn fresh_region(self: &LookupContext,
+                        self_r: ty::Region) -> ty::Region {
+            let region = self.infcx().next_region_var(self.expr.span,
+                                                      self.expr.id);
+
+            // FIXME(#3148)---in principle this dependency should
+            // be done more generally as part of regionck
+            match infer::mk_subr(self.infcx(), true, self.expr.span,
+                                 region, self_r) {
+                Ok(_) => {}
+                Err(e) => {
+                    self.tcx().sess.span_bug(
+                        self.expr.span,
+                        fmt!("Failed with error: %?", e));
+                }
+            }
+
+            return region;
+        }
+    }
+
     fn search_for_autosliced_method(
         &self,
         self_ty: ty::t,
@@ -729,6 +800,7 @@ fn search_for_autosliced_method(
         match ty::get(self_ty).sty {
             ty_evec(mt, vstore_box) |
             ty_evec(mt, vstore_uniq) |
+            ty_evec(mt, vstore_slice(_)) | // NDM(#3148)
             ty_evec(mt, vstore_fixed(_)) => {
                 // First try to borrow to a slice
                 let entry = self.search_for_some_kind_of_autorefd_method(
index 2d823ff02dd9103e8c8505a245de7e846e5bc1cc..cf13fcb86e8180cddd356f201774525ed34f112b 100644 (file)
 export demand;
 export method;
 export fn_ctxt;
-export lookup_local;
 export impl_self_ty;
 export DerefArgs;
 export DontDerefArgs;
 /// share the inherited fields.
 struct inherited {
     infcx: @infer::InferCtxt,
-    locals: HashMap<ast::node_id, TyVid>,
+    locals: HashMap<ast::node_id, ty::t>,
     node_types: HashMap<ast::node_id, ty::t>,
     node_type_substs: HashMap<ast::node_id, ty::substs>,
     adjustments: HashMap<ast::node_id, @ty::AutoAdjustment>
@@ -376,8 +375,7 @@ fn check_fn(ccx: @crate_ctxt,
         }
     };
 
-    // XXX: Bad copy.
-    gather_locals(fcx, decl, body, copy arg_tys, self_info);
+    gather_locals(fcx, decl, body, arg_tys, self_info);
     check_block(fcx, body);
 
     // We unify the tail expr's type with the
@@ -414,30 +412,31 @@ fn check_fn(ccx: @crate_ctxt,
     fn gather_locals(fcx: @fn_ctxt,
                      decl: &ast::fn_decl,
                      body: ast::blk,
-                     arg_tys: ~[ty::t],
+                     arg_tys: &[ty::t],
                      self_info: Option<self_info>) {
         let tcx = fcx.ccx.tcx;
 
-        let assign = fn@(span: span, nid: ast::node_id,
-                         ty_opt: Option<ty::t>) {
-            let var_id = fcx.infcx().next_ty_var_id();
-            fcx.inh.locals.insert(nid, var_id);
+        let assign = fn@(nid: ast::node_id, ty_opt: Option<ty::t>) {
             match ty_opt {
-                None => {/* nothing to do */ }
+                None => {
+                    // infer the variable's type
+                    let var_id = fcx.infcx().next_ty_var_id();
+                    let var_ty = ty::mk_var(fcx.tcx(), var_id);
+                    fcx.inh.locals.insert(nid, var_ty);
+                }
                 Some(typ) => {
-                    infer::mk_eqty(fcx.infcx(), false, span,
-                                   ty::mk_var(tcx, var_id), typ);
+                    // take type that the user specified
+                    fcx.inh.locals.insert(nid, typ);
                 }
             }
         };
 
         // Add the self parameter
         for self_info.each |self_info| {
-            assign(self_info.explicit_self.span,
-                   self_info.self_id,
-                   Some(self_info.self_ty));
+            assign(self_info.self_id, Some(self_info.self_ty));
             debug!("self is assigned to %s",
-                   fcx.inh.locals.get(self_info.self_id).to_str());
+                   fcx.infcx().ty_to_str(
+                       fcx.inh.locals.get(self_info.self_id)));
         }
 
         // Add formal parameters.
@@ -445,7 +444,7 @@ fn gather_locals(fcx: @fn_ctxt,
             // Create type variables for each argument.
             do pat_util::pat_bindings(tcx.def_map, input.pat)
                     |_bm, pat_id, _sp, _path| {
-                assign(input.ty.span, pat_id, None);
+                assign(pat_id, None);
             }
 
             // Check the pattern.
@@ -466,10 +465,11 @@ fn gather_locals(fcx: @fn_ctxt,
               ast::ty_infer => None,
               _ => Some(fcx.to_ty(local.node.ty))
             };
-            assign(local.span, local.node.id, o_ty);
-            debug!("Local variable %s is assigned to %s",
+            assign(local.node.id, o_ty);
+            debug!("Local variable %s is assigned type %s",
                    fcx.pat_to_str(local.node.pat),
-                   fcx.inh.locals.get(local.node.id).to_str());
+                   fcx.infcx().ty_to_str(
+                       fcx.inh.locals.get(local.node.id)));
             visit::visit_local(local, e, v);
         };
 
@@ -478,10 +478,11 @@ fn gather_locals(fcx: @fn_ctxt,
             match p.node {
               ast::pat_ident(_, path, _)
                   if pat_util::pat_is_binding(fcx.ccx.tcx.def_map, p) => {
-                assign(p.span, p.id, None);
+                assign(p.id, None);
                 debug!("Pattern binding %s is assigned to %s",
                        tcx.sess.str_of(path.idents[0]),
-                       fcx.inh.locals.get(p.id).to_str());
+                       fcx.infcx().ty_to_str(
+                           fcx.inh.locals.get(p.id)));
               }
               _ => {}
             }
@@ -694,6 +695,17 @@ fn named_region(_span: span, id: ast::ident) -> Result<ty::Region, ~str> {
 impl @fn_ctxt {
     fn tag() -> ~str { fmt!("%x", ptr::addr_of(&(*self)) as uint) }
 
+    fn local_ty(span: span, nid: ast::node_id) -> ty::t {
+        match self.inh.locals.find(nid) {
+            Some(t) => t,
+            None => {
+                self.tcx().sess.span_bug(
+                    span,
+                    fmt!("No type for local variable %?", nid));
+            }
+        }
+    }
+
     fn expr_to_str(expr: @ast::expr) -> ~str {
         fmt!("expr(%?:%s)", expr.id,
              pprust::expr_to_str(expr, self.tcx().sess.intr()))
@@ -1359,10 +1371,8 @@ fn check_method_call(fcx: @fn_ctxt,
     fn check_for(fcx: @fn_ctxt, local: @ast::local,
                  element_ty: ty::t, body: ast::blk,
                  node_id: ast::node_id) -> bool {
-        let locid = lookup_local(fcx, local.span, local.node.id);
-        demand::suptype(fcx, local.span,
-                       ty::mk_var(fcx.ccx.tcx, locid),
-                       element_ty);
+        let local_ty = fcx.local_ty(local.span, local.node.id);
+        demand::suptype(fcx, local.span, local_ty, element_ty);
         let bot = check_decl_local(fcx, local);
         check_block_no_value(fcx, body);
         fcx.write_nil(node_id);
@@ -2551,15 +2561,15 @@ fn require_integral(fcx: @fn_ctxt, sp: span, t: ty::t) {
 
 fn check_decl_initializer(fcx: @fn_ctxt, nid: ast::node_id,
                           init: @ast::expr) -> bool {
-    let lty = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, init.span, nid));
-    return check_expr_coercable_to_type(fcx, init, lty);
+    let local_ty = fcx.local_ty(init.span, nid);
+    return check_expr_coercable_to_type(fcx, init, local_ty);
 }
 
 fn check_decl_local(fcx: @fn_ctxt, local: @ast::local) -> bool {
     let mut bot = false;
     let tcx = fcx.ccx.tcx;
 
-    let t = ty::mk_var(tcx, fcx.inh.locals.get(local.node.id));
+    let t = fcx.local_ty(local.span, local.node.id);
     fcx.write_ty(local.node.id, t);
 
     match local.node.init {
@@ -2819,17 +2829,6 @@ fn do_check(ccx: @crate_ctxt, sp: span, vs: ~[ast::variant],
     check_instantiable(ccx.tcx, sp, id);
 }
 
-pub fn lookup_local(fcx: @fn_ctxt, sp: span, id: ast::node_id) -> TyVid {
-    match fcx.inh.locals.find(id) {
-        Some(x) => x,
-        _ => {
-            fcx.ccx.tcx.sess.span_fatal(
-                sp,
-                ~"internal error looking up a local var")
-        }
-    }
-}
-
 fn lookup_def(fcx: @fn_ctxt, sp: span, id: ast::node_id) -> ast::def {
     lookup_def_ccx(fcx.ccx, sp, id)
 }
@@ -2841,9 +2840,8 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
     match defn {
       ast::def_arg(nid, _, _) | ast::def_local(nid, _) |
       ast::def_self(nid, _) | ast::def_binding(nid, _) => {
-        assert (fcx.inh.locals.contains_key(nid));
-        let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, nid));
-        return no_params(typ);
+          let typ = fcx.local_ty(sp, nid);
+          return no_params(typ);
       }
       ast::def_fn(_, ast::extern_fn) => {
         // extern functions are just u8 pointers
index 1a665aa756611bbe7404158d69a8baff89fa2184..e5dc91b7f179a41fbe10dab6667be10d40b629c3 100644 (file)
@@ -16,7 +16,7 @@
 
 use middle::pat_util;
 use middle::ty;
-use middle::typeck::check::{fn_ctxt, lookup_local, self_info};
+use middle::typeck::check::{fn_ctxt, self_info};
 use middle::typeck::infer::{force_all, resolve_all, resolve_region};
 use middle::typeck::infer::{resolve_type};
 use middle::typeck::infer;
@@ -216,8 +216,7 @@ fn visit_pat(p: @ast::pat, wbcx: wb_ctxt, v: wb_vt) {
 }
 fn visit_local(l: @ast::local, wbcx: wb_ctxt, v: wb_vt) {
     if !wbcx.success { return; }
-    let var_id = lookup_local(wbcx.fcx, l.span, l.node.id);
-    let var_ty = ty::mk_var(wbcx.fcx.tcx(), var_id);
+    let var_ty = wbcx.fcx.local_ty(l.span, l.node.id);
     match resolve_type(wbcx.fcx.infcx(), var_ty, resolve_all | force_all) {
         Ok(lty) => {
             debug!("Type for local %s (id %d) resolved to %s",
index 84fe51b65ec518c8db031890c5ff31ec37bf9c2f..9c319bdc733aea0d35c35e0bb4603a1d5e4b464c 100644 (file)
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ______________________________________________________________________
-// Type assignment
-//
-// True if rvalues of type `a` can be assigned to lvalues of type `b`.
-// This may cause borrowing to the region scope enclosing `a_node_id`.
-//
-// The strategy here is somewhat non-obvious.  The problem is
-// that the constraint we wish to contend with is not a subtyping
-// constraint.  Currently, for variables, we only track what it
-// must be a subtype of, not what types it must be assignable to
-// (or from).  Possibly, we should track that, but I leave that
-// refactoring for another day.
-//
-// Instead, we look at each variable involved and try to extract
-// *some* sort of bound.  Typically, the type a is the argument
-// supplied to a call; it typically has a *lower bound* (which
-// comes from having been assigned a value).  What we'd actually
-// *like* here is an upper-bound, but we generally don't have
-// one.  The type b is the expected type and it typically has a
-// lower-bound too, which is good.
-//
-// The way we deal with the fact that we often don't have the
-// bounds we need is to be a bit careful.  We try to get *some*
-// bound from each side, preferring the upper from a and the
-// lower from b.  If we fail to get a bound from both sides, then
-// we just fall back to requiring that a <: b.
-//
-// Assuming we have a bound from both sides, we will then examine
-// these bounds and see if they have the form (@M_a T_a, &rb.M_b T_b)
-// (resp. ~M_a T_a, ~[M_a T_a], etc).  If they do not, we fall back to
-// subtyping.
-//
-// If they *do*, then we know that the two types could never be
-// subtypes of one another.  We will then construct a type @const T_b
-// and ensure that type a is a subtype of that.  This allows for the
-// possibility of assigning from a type like (say) @~[mut T1] to a type
-// &~[T2] where T1 <: T2.  This might seem surprising, since the `@`
-// points at mutable memory but the `&` points at immutable memory.
-// This would in fact be unsound, except for the borrowck, which comes
-// later and guarantees that such mutability conversions are safe.
-// See borrowck for more details.  Next we require that the region for
-// the enclosing scope be a superregion of the region r.
-//
-// You might wonder why we don't make the type &e.const T_a where e is
-// the enclosing region and check that &e.const T_a <: B.  The reason
-// is that the type of A is (generally) just a *lower-bound*, so this
-// would be imposing that lower-bound also as the upper-bound on type
-// A.  But this upper-bound might be stricter than what is truly
-// needed.
+/*!
+
+# Type Coercion
+
+Under certain circumstances we will coerce from one type to another,
+for example by auto-borrowing.  This occurs in situations where the
+compiler has a firm 'expected type' that was supplied from the user,
+and where the actual type is similar to that expected type in purpose
+but not in representation (so actual subtyping is inappropriate).
+
+## Reborrowing
+
+Note that if we are expecting a borrowed pointer, we will *reborrow*
+even if the argument provided was already a borrowed pointer.  This is
+useful for freezing mut/const things (that is, when the expected is &T
+but you have &const T or &mut T) and also for avoiding the linearity
+of mut things (when the expected is &mut T and you have &mut T).  See
+the various `src/test/run-pass/coerce-reborrow-*.rs` tests for
+examples of where this is useful.
+
+## Subtle note
+
+When deciding what type coercions to consider, we do not attempt to
+resolve any type variables we may encounter.  This is because `b`
+represents the expected type "as the user wrote it", meaning that if
+the user defined a generic function like
+
+   fn foo<A>(a: A, b: A) { ... }
+
+and then we wrote `foo(&1, @2)`, we will not auto-borrow
+either argument.  In older code we went to some lengths to
+resolve the `b` variable, which could mean that we'd
+auto-borrow later arguments but not earlier ones, which
+seems very confusing.
+
+## Subtler note
+
+However, right now, if the user manually specifies the
+values for the type variables, as so:
+
+   foo::<&int>(@1, @2)
+
+then we *will* auto-borrow, because we can't distinguish this from a
+function that declared `&int`.  This is inconsistent but it's easiest
+at the moment. The right thing to do, I think, is to consider the
+*unsubstituted* type when deciding whether to auto-borrow, but the
+*substituted* type when considering the bounds and so forth. But most
+of our methods don't give access to the unsubstituted type, and
+rightly so because they'd be error-prone.  So maybe the thing to do is
+to actually determine the kind of coercions that should occur
+separately and pass them in.  Or maybe it's ok as is.  Anyway, it's
+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 core::prelude::*;
 
-use middle::ty::TyVar;
+use middle::ty::{TyVar, AutoPtr, AutoBorrowVec, AutoBorrowFn};
+use middle::ty::{AutoAdjustment, AutoRef};
+use middle::ty::{vstore_slice, vstore_box, vstore_uniq, vstore_fixed};
+use middle::ty::{FnMeta, FnTyBase, mt};
 use middle::ty;
-use middle::typeck::infer::{ares, cres};
+use middle::typeck::infer::{CoerceResult, resolve_type};
 use middle::typeck::infer::combine::CombineFields;
 use middle::typeck::infer::sub::Sub;
 use middle::typeck::infer::to_str::InferStr;
+use middle::typeck::infer::resolve::try_resolve_tvar_shallow;
 use util::common::{indent, indenter};
 
 use core::option;
 use syntax::ast::{m_const, m_imm, m_mutbl};
 use syntax::ast;
 
-fn to_ares<T>(+c: cres<T>) -> ares {
-    match c {
-        Ok(_) => Ok(None),
-        Err(ref e) => Err((*e))
-    }
-}
-
 // Note: Coerce is not actually a combiner, in that it does not
 // conform to the same interface, though it performs a similar
 // function.
 pub enum Coerce = CombineFields;
 
 impl Coerce {
-    fn tys(&self, a: ty::t, b: ty::t) -> ares {
+    fn tys(&self, a: ty::t, b: ty::t) -> CoerceResult {
         debug!("Coerce.tys(%s => %s)",
                a.inf_str(self.infcx),
                b.inf_str(self.infcx));
         let _indent = indenter();
-        let r = match (&ty::get(a).sty, &ty::get(b).sty) {
-            (&ty::ty_bot, _) => {
-                Ok(None)
+
+        // Examine the supertype and consider auto-borrowing.
+        //
+        // Note: does not attempt to resolve type variables we encounter.
+        // See above for details.
+        match ty::get(b).sty {
+            ty::ty_rptr(_, mt_b) => {
+                return do self.unpack_actual_value(a) |sty_a| {
+                    self.coerce_borrowed_pointer(a, sty_a, b, mt_b)
+                };
             }
 
-            (&ty::ty_infer(TyVar(a_id)), &ty::ty_infer(TyVar(b_id))) => {
-                let nde_a = self.infcx.get(a_id);
-                let nde_b = self.infcx.get(b_id);
-                let a_bounds = nde_a.possible_types;
-                let b_bounds = nde_b.possible_types;
+            ty::ty_estr(vstore_slice(_)) => {
+                return do self.unpack_actual_value(a) |sty_a| {
+                    self.coerce_borrowed_string(a, sty_a, b)
+                };
+            }
 
-                let a_bnd = option::or(a_bounds.ub, a_bounds.lb);
-                let b_bnd = option::or(b_bounds.lb, b_bounds.ub);
-                self.coerce_tys_or_sub(a, b, a_bnd, b_bnd)
+            ty::ty_evec(mt_b, vstore_slice(_)) => {
+                return do self.unpack_actual_value(a) |sty_a| {
+                    self.coerce_borrowed_vector(a, sty_a, b, mt_b)
+                };
             }
 
-            (&ty::ty_infer(TyVar(a_id)), _) => {
-                let nde_a = self.infcx.get(a_id);
-                let a_bounds = nde_a.possible_types;
+            ty::ty_fn(ref b_f) if b_f.meta.proto == ast::ProtoBorrowed => {
+                return do self.unpack_actual_value(a) |sty_a| {
+                    self.coerce_borrowed_fn(a, sty_a, b)
+                };
+            }
 
-                let a_bnd = option::or(a_bounds.ub, a_bounds.lb);
-                self.coerce_tys_or_sub(a, b, a_bnd, Some(b))
+            ty::ty_ptr(_) => {
+                return do self.unpack_actual_value(a) |sty_a| {
+                    self.coerce_unsafe_ptr(a, sty_a, b)
+                };
             }
 
-            (_, &ty::ty_infer(TyVar(b_id))) => {
-                let nde_b = self.infcx.get(b_id);
-                let b_bounds = nde_b.possible_types;
+            _ => {}
+        }
 
-                let b_bnd = option::or(b_bounds.lb, b_bounds.ub);
-                self.coerce_tys_or_sub(a, b, Some(a), b_bnd)
+        do self.unpack_actual_value(a) |sty_a| {
+            match *sty_a {
+                ty::ty_fn(ref a_f) if a_f.meta.proto == ast::ProtoBare => {
+                    // Bare functions are coercable to any closure type.
+                    //
+                    // FIXME(#3320) this should go away and be
+                    // replaced with proper inference, got a patch
+                    // underway - ndm
+                    self.coerce_from_bare_fn(a, a_f, b)
+                }
+                _ => {
+                    // Otherwise, just use subtyping rules.
+                    self.subtype(a, b)
+                }
             }
+        }
+    }
+
+    fn subtype(&self, a: ty::t, b: ty::t) -> CoerceResult {
+        match Sub(**self).tys(a, b) {
+            Ok(_) => Ok(None),         // No coercion required.
+            Err(ref e) => Err(*e)
+        }
+    }
 
-            (_, _) => {
-                self.coerce_tys_or_sub(a, b, Some(a), Some(b))
+    fn unpack_actual_value(&self,
+                           a: ty::t,
+                           f: &fn(&ty::sty) -> CoerceResult) -> CoerceResult
+    {
+        match resolve_type(self.infcx, a, try_resolve_tvar_shallow) {
+            Ok(t) => {
+                f(&ty::get(t).sty)
             }
-        };
+            Err(e) => {
+                self.infcx.tcx.sess.span_bug(
+                    self.span,
+                    fmt!("Failed to resolve even without \
+                          any force options: %?", e));
+            }
+        }
+    }
+
+    fn coerce_borrowed_pointer(&self,
+                               a: ty::t,
+                               sty_a: &ty::sty,
+                               b: ty::t,
+                               mt_b: ty::mt) -> CoerceResult
+    {
+        debug!("coerce_borrowed_pointer(a=%s, sty_a=%?, b=%s, mt_b=%?)",
+               a.inf_str(self.infcx), sty_a,
+               b.inf_str(self.infcx), mt_b);
 
-        debug!("Coerce.tys end");
+        // If we have a parameter of type `&M T_a` and the value
+        // provided is `expr`, we will be adding an implicit borrow,
+        // meaning that we convert `f(expr)` to `f(&M *expr)`.  Therefore,
+        // to type check, we will construct the type that `&M*expr` would
+        // yield.
+
+        let sub = Sub(**self);
+        let r_borrow = self.infcx.next_region_var_nb(self.span);
+
+        let inner_ty = match *sty_a {
+            ty::ty_box(mt_a) => mt_a.ty,
+            ty::ty_uniq(mt_a) => mt_a.ty,
+            ty::ty_rptr(r_a, mt_a) => {
+                // Ensure that the pointer we are borrowing from lives
+                // at least as long as the borrowed result.
+                //
+                // FIXME(#3148)---in principle this dependency should
+                // be done more generally
+                if_ok!(sub.contraregions(r_a, r_borrow));
+                mt_a.ty
+            }
+            _ => {
+                return self.subtype(a, b);
+            }
+        };
 
-        move r
+        let a_borrowed = ty::mk_rptr(self.infcx.tcx,
+                                     r_borrow,
+                                     mt {ty: inner_ty, mutbl: mt_b.mutbl});
+        if_ok!(sub.tys(a_borrowed, b));
+        Ok(Some(@AutoAdjustment {
+            autoderefs: 1,
+            autoref: Some(AutoRef {
+                kind: AutoPtr,
+                region: r_borrow,
+                mutbl: mt_b.mutbl
+            })
+        }))
     }
-}
 
-impl Coerce {
-    fn coerce_tys_or_sub(
-        &self,
-        +a: ty::t,
-        +b: ty::t,
-        +a_bnd: Option<ty::t>,
-        +b_bnd: Option<ty::t>) -> ares
+    fn coerce_borrowed_string(&self,
+                              a: ty::t,
+                              sty_a: &ty::sty,
+                              b: ty::t) -> CoerceResult
     {
-        debug!("Coerce.coerce_tys_or_sub(%s => %s, %s => %s)",
-               a.inf_str(self.infcx), b.inf_str(self.infcx),
-               a_bnd.inf_str(self.infcx), b_bnd.inf_str(self.infcx));
-        let _r = indenter();
-
-        fn is_borrowable(v: ty::vstore) -> bool {
-            match v {
-              ty::vstore_fixed(_) | ty::vstore_uniq | ty::vstore_box => true,
-              ty::vstore_slice(_) => false
+        debug!("coerce_borrowed_string(a=%s, sty_a=%?, b=%s)",
+               a.inf_str(self.infcx), sty_a,
+               b.inf_str(self.infcx));
+
+        match *sty_a {
+            ty::ty_estr(vstore_box) |
+            ty::ty_estr(vstore_uniq) => {}
+            _ => {
+                return self.subtype(a, b);
             }
-        }
+        };
+
+        let r_a = self.infcx.next_region_var_nb(self.span);
+        let a_borrowed = ty::mk_estr(self.infcx.tcx, vstore_slice(r_a));
+        if_ok!(self.subtype(a_borrowed, b));
+        Ok(Some(@AutoAdjustment {
+            autoderefs: 0,
+            autoref: Some(AutoRef {
+                kind: AutoBorrowVec,
+                region: r_a,
+                mutbl: m_imm
+            })
+        }))
+    }
 
-        fn borrowable_protos(a_p: ast::Proto, b_p: ast::Proto) -> bool {
-            match (a_p, b_p) {
-                (ast::ProtoBox, ast::ProtoBorrowed) => true,
-                (ast::ProtoUniq, ast::ProtoBorrowed) => true,
-                _ => false
+    fn coerce_borrowed_vector(&self,
+                              a: ty::t,
+                              sty_a: &ty::sty,
+                              b: ty::t,
+                              mt_b: ty::mt) -> CoerceResult
+    {
+        debug!("coerce_borrowed_vector(a=%s, sty_a=%?, b=%s)",
+               a.inf_str(self.infcx), sty_a,
+               b.inf_str(self.infcx));
+
+        let sub = Sub(**self);
+        let r_borrow = self.infcx.next_region_var_nb(self.span);
+        let ty_inner = match *sty_a {
+            ty::ty_evec(mt, vstore_box) => mt.ty,
+            ty::ty_evec(mt, vstore_uniq) => mt.ty,
+            ty::ty_evec(mt, vstore_fixed(_)) => mt.ty,
+            ty::ty_evec(mt, vstore_slice(r_a)) => {
+                // Ensure that the pointer we are borrowing from lives
+                // at least as long as the borrowed result.
+                //
+                // FIXME(#3148)---in principle this dependency should
+                // be done more generally
+                if_ok!(sub.contraregions(r_a, r_borrow));
+                mt.ty
             }
-        }
+            _ => {
+                return self.subtype(a, b);
+            }
+        };
 
-        match (a_bnd, b_bnd) {
-            (Some(a_bnd), Some(b_bnd)) => {
-                match (&ty::get(a_bnd).sty, &ty::get(b_bnd).sty) {
-                    // check for a case where a non-region pointer (@, ~) is
-                    // being coerceed to a region pointer:
-                    (&ty::ty_box(_), &ty::ty_rptr(r_b, mt_b)) => {
-                        let nr_b = ty::mk_box(self.infcx.tcx,
-                                              ty::mt {ty: mt_b.ty,
-                                                      mutbl: m_const});
-                        self.try_coerce(1, ty::AutoPtr,
-                                        a, nr_b,
-                                        mt_b.mutbl, r_b)
-                    }
-                    (&ty::ty_uniq(_), &ty::ty_rptr(r_b, mt_b)) => {
-                        let nr_b = ty::mk_uniq(self.infcx.tcx,
-                                               ty::mt {ty: mt_b.ty,
-                                                       mutbl: m_const});
-                        self.try_coerce(1, ty::AutoPtr,
-                                        a, nr_b,
-                                        mt_b.mutbl, r_b)
-                    }
-                    (&ty::ty_estr(vs_a),
-                     &ty::ty_estr(ty::vstore_slice(r_b)))
-                    if is_borrowable(vs_a) => {
-                        let nr_b = ty::mk_estr(self.infcx.tcx, vs_a);
-                        self.try_coerce(0, ty::AutoBorrowVec,
-                                        a, nr_b,
-                                        m_imm, r_b)
-                    }
-
-                    (&ty::ty_evec(_, vs_a),
-                     &ty::ty_evec(mt_b, ty::vstore_slice(r_b)))
-                    if is_borrowable(vs_a) => {
-                        let nr_b = ty::mk_evec(self.infcx.tcx,
-                                               ty::mt {ty: mt_b.ty,
-                                                       mutbl: m_const},
-                                               vs_a);
-                        self.try_coerce(0, ty::AutoBorrowVec,
-                                        a, nr_b,
-                                        mt_b.mutbl, r_b)
-                    }
-
-                    (&ty::ty_fn(ref a_f), &ty::ty_fn(ref b_f))
-                    if borrowable_protos(a_f.meta.proto, b_f.meta.proto) => {
-                        let nr_b = ty::mk_fn(self.infcx.tcx, ty::FnTyBase {
-                            meta: ty::FnMeta {proto: a_f.meta.proto,
-                                              ..b_f.meta},
-                            sig: copy b_f.sig
-                        });
-                        self.try_coerce(0, ty::AutoBorrowFn,
-                                        a, nr_b, m_imm, b_f.meta.region)
-                    }
-
-                    (&ty::ty_fn(ref a_f), &ty::ty_fn(ref b_f))
-                    if a_f.meta.proto == ast::ProtoBare => {
-                        let b1_f = ty::FnTyBase {
-                            meta: ty::FnMeta {proto: ast::ProtoBare,
-                                              ..b_f.meta},
-                            sig: copy b_f.sig
-                        };
-                        // Eventually we will need to add some sort of
-                        // adjustment here so that trans can add an
-                        // extra NULL env pointer:
-                        to_ares(Sub(**self).fns(a_f, &b1_f))
-                    }
-
-                    // check for &T being coerced to *T:
-                    (&ty::ty_rptr(_, ref a_t), &ty::ty_ptr(ref b_t)) => {
-                        to_ares(Sub(**self).mts(*a_t, *b_t))
-                    }
-
-                    // otherwise, coercement follows normal subtype rules:
-                    _ => {
-                        to_ares(Sub(**self).tys(a, b))
-                    }
-                }
+        let a_borrowed = ty::mk_evec(self.infcx.tcx,
+                                     mt {ty: ty_inner, mutbl: mt_b.mutbl},
+                                     vstore_slice(r_borrow));
+        if_ok!(sub.tys(a_borrowed, b));
+        Ok(Some(@AutoAdjustment {
+            autoderefs: 0,
+            autoref: Some(AutoRef {
+                kind: AutoBorrowVec,
+                region: r_borrow,
+                mutbl: mt_b.mutbl
+            })
+        }))
+    }
+
+    fn coerce_borrowed_fn(&self,
+                          a: ty::t,
+                          sty_a: &ty::sty,
+                          b: ty::t) -> CoerceResult
+    {
+        debug!("coerce_borrowed_fn(a=%s, sty_a=%?, b=%s)",
+               a.inf_str(self.infcx), sty_a,
+               b.inf_str(self.infcx));
+
+        let fn_ty = match *sty_a {
+            ty::ty_fn(ref f) if f.meta.proto == ast::ProtoBox => {f}
+            ty::ty_fn(ref f) if f.meta.proto == ast::ProtoUniq => {f}
+            ty::ty_fn(ref f) if f.meta.proto == ast::ProtoBare => {
+                return self.coerce_from_bare_fn(a, f, b);
             }
             _ => {
-                // if insufficient bounds were available, just follow
-                // normal subtype rules:
-                to_ares(Sub(**self).tys(a, b))
+                return self.subtype(a, b);
             }
+        };
+
+        let r_borrow = self.infcx.next_region_var_nb(self.span);
+        let meta = FnMeta {proto: ast::ProtoBorrowed,
+                           region: r_borrow,
+                           ..fn_ty.meta};
+        let a_borrowed = ty::mk_fn(self.infcx.tcx,
+                                   FnTyBase {meta: meta,
+                                             sig: copy fn_ty.sig});
+
+        if_ok!(self.subtype(a_borrowed, b));
+        Ok(Some(@AutoAdjustment {
+            autoderefs: 0,
+            autoref: Some(AutoRef {
+                kind: AutoBorrowFn,
+                region: r_borrow,
+                mutbl: m_imm
+            })
+        }))
+    }
+
+    fn coerce_from_bare_fn(&self,
+                           a: ty::t,
+                           fn_ty_a: &ty::FnTy,
+                           b: ty::t) -> CoerceResult
+    {
+        do self.unpack_actual_value(b) |sty_b| {
+            self.coerce_from_bare_fn_post_unpack(a, fn_ty_a, b, sty_b)
         }
     }
 
-    /// Given an coercement from a type like `@a` to `&r_b/m nr_b`,
-    /// this function checks that `a <: nr_b`.  In that case, the
-    /// coercement is permitted, so it constructs a fresh region
-    /// variable `r_a >= r_b` and returns a corresponding coercement
-    /// record.  See the discussion at the top of this file for more
-    /// details.
-    fn try_coerce(&self,
-                  autoderefs: uint,
-                  kind: ty::AutoRefKind,
-                  a: ty::t,
-                  nr_b: ty::t,
-                  m: ast::mutability,
-                  r_b: ty::Region) -> ares
+    fn coerce_from_bare_fn_post_unpack(&self,
+                                       a: ty::t,
+                                       fn_ty_a: &ty::FnTy,
+                                       b: ty::t,
+                                       sty_b: &ty::sty) -> CoerceResult
     {
-        debug!("try_coerce(a=%s, nr_b=%s, m=%?, r_b=%s)",
-               a.inf_str(self.infcx),
-               nr_b.inf_str(self.infcx),
-               m,
-               r_b.inf_str(self.infcx));
-
-        do indent {
-            let sub = Sub(**self);
-            do sub.tys(a, nr_b).chain |_t| {
-                let r_a = self.infcx.next_region_var_nb(self.span);
-                do sub.contraregions(r_a, r_b).chain |_r| {
-                    Ok(Some(@ty::AutoAdjustment {
-                        autoderefs: autoderefs,
-                        autoref: Some(ty::AutoRef {
-                            kind: kind,
-                            region: r_a,
-                            mutbl: m
-                        })
-                    }))
-                }
+        debug!("coerce_from_bare_fn(a=%s, b=%s)",
+               a.inf_str(self.infcx), b.inf_str(self.infcx));
+
+        let fn_ty_b = match *sty_b {
+            ty::ty_fn(ref f) if f.meta.proto != ast::ProtoBare => {f}
+            _ => {
+                return self.subtype(a, b);
             }
-        }
+        };
+
+            // for now, bare fn and closures have the same
+            // representation
+        let a_adapted = ty::mk_fn(self.infcx.tcx,
+                                  FnTyBase {meta: copy fn_ty_b.meta,
+                                            sig: copy fn_ty_a.sig});
+        self.subtype(a_adapted, b)
     }
-}
 
+    fn coerce_unsafe_ptr(&self,
+                         a: ty::t,
+                         sty_a: &ty::sty,
+                         b: ty::t) -> CoerceResult
+    {
+        debug!("coerce_unsafe_ptr(a=%s, sty_a=%?, b=%s)",
+               a.inf_str(self.infcx), sty_a,
+               b.inf_str(self.infcx));
+
+        let mt_a = match *sty_a {
+            ty::ty_rptr(_, mt) => mt,
+            _ => {
+                return self.subtype(a, b);
+            }
+        };
+
+        // borrowed pointers and unsafe pointers have the same
+        // representation, so just check that the types which they
+        // point at are compatible:
+        let a_unsafe = ty::mk_ptr(self.infcx.tcx, mt_a);
+        self.subtype(a_unsafe, b)
+    }
+}
index 8ec7e68176a56c2fcec18611888af6164654d8a6..cac5fa5feb1c1a6412b06d51a25d580d42c32137 100644 (file)
@@ -317,12 +317,11 @@ fn bar() {
 export cyclic_ty, unresolved_ty, region_var_bound_by_region_var;
 export Bound, Bounds;
 export ures;
-export ares;
+export CoerceResult;
 export infer_ctxt;
 export fixup_err;
 export IntVarValue, IntType, UintType;
 
-mod coercion;
 #[legacy_exports]
 mod combine;
 #[legacy_exports]
@@ -341,6 +340,7 @@ fn bar() {
 mod to_str;
 #[legacy_exports]
 mod unify;
+mod coercion;
 
 type Bound<T> = Option<T>;
 type Bounds<T> = {lb: Bound<T>, ub: Bound<T>};
@@ -348,7 +348,7 @@ fn bar() {
 type cres<T> = Result<T,ty::type_err>; // "combine result"
 type ures = cres<()>; // "unify result"
 type fres<T> = Result<T, fixup_err>; // "fixup result"
-type ares = cres<Option<@ty::AutoAdjustment>>; // "assignment result"
+type CoerceResult = cres<Option<@ty::AutoAdjustment>>;
 
 struct InferCtxt {
     tcx: ty::ctxt,
@@ -457,7 +457,8 @@ fn mk_eqty(cx: @InferCtxt, a_is_expected: bool, span: span,
 }
 
 fn mk_coercety(cx: @InferCtxt, a_is_expected: bool, span: span,
-               a: ty::t, b: ty::t) -> ares {
+               a: ty::t, b: ty::t) -> CoerceResult
+{
     debug!("mk_coercety(%s -> %s)", a.inf_str(cx), b.inf_str(cx));
     do indent {
         do cx.commit {
index 01f4b86b48858a55c04103986f0b4055ff3c7ec7..b25c4db8a90b767b546403256f6a2292f88584ea 100644 (file)
@@ -78,6 +78,7 @@
 
 const not_regions: uint         = !(force_rvar | resolve_rvar);
 
+const try_resolve_tvar_shallow: uint = 0;
 const resolve_and_force_all_but_regions: uint =
     (resolve_all | force_all) & not_regions;
 
index 839d4137ba923f21a2c16ad04febf9030a02763f..19cdfe784d2b03a2078c6c224c321e66f7277db6 100644 (file)
@@ -16,9 +16,9 @@
 fn main() {
     let buggy_map :HashMap<uint, &uint> =
       HashMap::<uint, &uint>();
-    buggy_map.insert(42, ~1); //~ ERROR illegal borrow
-    
+    buggy_map.insert(42, &*~1); //~ ERROR illegal borrow
+
     // but it is ok if we use a temporary
     let tmp = ~2;
-    buggy_map.insert(43, tmp);
+    buggy_map.insert(43, &*tmp);
 }
diff --git a/src/test/compile-fail/coerce-bad-variance.rs b/src/test/compile-fail/coerce-bad-variance.rs
new file mode 100644 (file)
index 0000000..c4cdbcb
--- /dev/null
@@ -0,0 +1,17 @@
+fn mutate(x: &mut @const int) {
+    *x = @3;
+}
+
+fn give_away1(y: @mut @mut int) {
+    mutate(y); //~ ERROR values differ in mutability
+}
+
+fn give_away2(y: @mut @const int) {
+    mutate(y);
+}
+
+fn give_away3(y: @mut @int) {
+    mutate(y); //~ ERROR values differ in mutability
+}
+
+fn main() {}
\ No newline at end of file
index 83938293d7548cfd08d1efe6a49f6541aff25d76..356a64498219ab9a5c347e9571dd54c927caa15a 100644 (file)
@@ -10,6 +10,5 @@
 
 fn main () {
     let mut _p: & int = & 4;
-    _p = ~3; //~ ERROR illegal borrow: borrowed value does not live long enough
-    //~^ NOTE ...but borrowed value is only valid for the statement
+    _p = &*~3; //~ ERROR illegal borrow
 }
index c7c6aec9f1df83f87ce97d92f581fc1edd4a3206..69f07e3e77492bac15bea532ee44dbde83cd7e40 100644 (file)
@@ -20,11 +20,12 @@ fn repeater<A:Copy>(v: @A) -> repeat<A> {
 }
 
 fn main() {
-    // Here, an error results as the type of y is inferred to
-    // repeater<&lt/3> where lt is the block.
-    let y = {
-        let x: &blk/int = &3; //~ ERROR cannot infer an appropriate lifetime
+    // Error results because the type of is inferred to be
+    // repeat<&blk/int> where blk is the lifetime of the block below.
+
+    let y = { //~ ERROR reference is not valid
+        let x: &blk/int = &3;
         repeater(@x)
     };
-    assert 3 == *(y.get());
+    assert 3 == *(y.get()); //~ ERROR reference is not valid
 }
\ No newline at end of file
index 1f59e9a8128cc2b7226c4816c7d7e3407b740e80..f9992429733450371a41cee900a79929a0d05e52 100644 (file)
@@ -25,8 +25,7 @@ fn nested(x: &x/int) {  // (1)
             //~^ ERROR cannot infer an appropriate lifetime
 
             return z(y, x, x);
-            //~^ ERROR mismatched types: expected `&x/int` but found `&y/int`
-            //~^^ ERROR mismatched types: expected `&y/int` but found `&x/int`
+            //~^ ERROR cannot infer an appropriate lifetime
         }
     ) |foo| {
 
diff --git a/src/test/run-pass/coerce-reborrow-imm-ptr-arg.rs b/src/test/run-pass/coerce-reborrow-imm-ptr-arg.rs
new file mode 100644 (file)
index 0000000..3c9748f
--- /dev/null
@@ -0,0 +1,17 @@
+pure fn negate(x: &int) -> int {
+    -*x
+}
+
+fn negate_mut(y: &mut int) -> int {
+    negate(y)
+}
+
+fn negate_imm(y: &int) -> int {
+    negate(y)
+}
+
+fn negate_const(y: &const int) -> int {
+    negate(y)
+}
+
+fn main() {}
diff --git a/src/test/run-pass/coerce-reborrow-imm-ptr-rcvr.rs b/src/test/run-pass/coerce-reborrow-imm-ptr-rcvr.rs
new file mode 100644 (file)
index 0000000..0d8f406
--- /dev/null
@@ -0,0 +1,16 @@
+struct SpeechMaker {
+    speeches: uint
+}
+
+impl SpeechMaker {
+    pure fn how_many(&self) -> uint { self.speeches }
+}
+
+fn foo(speaker: &const SpeechMaker) -> uint {
+    speaker.how_many() + 33
+}
+
+fn main() {
+    let mut lincoln = SpeechMaker {speeches: 22};
+    assert foo(&const lincoln) == 55;
+}
diff --git a/src/test/run-pass/coerce-reborrow-imm-vec-arg.rs b/src/test/run-pass/coerce-reborrow-imm-vec-arg.rs
new file mode 100644 (file)
index 0000000..54a6b35
--- /dev/null
@@ -0,0 +1,19 @@
+pure fn sum(x: &[int]) -> int {
+    let mut sum = 0;
+    for x.each |y| { sum += *y; }
+    return sum;
+}
+
+fn sum_mut(y: &[mut int]) -> int {
+    sum(y)
+}
+
+fn sum_imm(y: &[int]) -> int {
+    sum(y)
+}
+
+fn sum_const(y: &[const int]) -> int {
+    sum(y)
+}
+
+fn main() {}
\ No newline at end of file
diff --git a/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs b/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs
new file mode 100644 (file)
index 0000000..24fb5cb
--- /dev/null
@@ -0,0 +1,18 @@
+fn foo(v: &[const uint]) -> ~[uint] {
+    v.to_vec()
+}
+
+fn bar(v: &[mut uint]) -> ~[uint] {
+    v.to_vec()
+}
+
+fn bip(v: &[uint]) -> ~[uint] {
+    v.to_vec()
+}
+
+fn main() {
+    let mut the_vec = ~[1, 2, 3, 100];
+    assert the_vec == foo(the_vec);
+    assert the_vec == bar(the_vec);
+    assert the_vec == bip(the_vec);
+}
diff --git a/src/test/run-pass/coerce-reborrow-mut-ptr-arg.rs b/src/test/run-pass/coerce-reborrow-mut-ptr-arg.rs
new file mode 100644 (file)
index 0000000..4579907
--- /dev/null
@@ -0,0 +1,22 @@
+struct SpeechMaker {
+    speeches: uint
+}
+
+fn talk(x: &mut SpeechMaker) {
+    x.speeches += 1;
+}
+
+fn give_a_few_speeches(speaker: &mut SpeechMaker) {
+
+    // Here speaker is reborrowed for each call, so we don't get errors
+    // about speaker being moved.
+
+    talk(speaker);
+    talk(speaker);
+    talk(speaker);
+}
+
+fn main() {
+    let mut lincoln = SpeechMaker {speeches: 22};
+    give_a_few_speeches(&mut lincoln);
+}
diff --git a/src/test/run-pass/coerce-reborrow-mut-ptr-rcvr.rs b/src/test/run-pass/coerce-reborrow-mut-ptr-rcvr.rs
new file mode 100644 (file)
index 0000000..c915c01
--- /dev/null
@@ -0,0 +1,24 @@
+struct SpeechMaker {
+    speeches: uint
+}
+
+impl SpeechMaker {
+    fn talk(&mut self) {
+        self.speeches += 1;
+    }
+}
+
+fn give_a_few_speeches(speaker: &mut SpeechMaker) {
+
+    // Here speaker is reborrowed for each call, so we don't get errors
+    // about speaker being moved.
+
+    speaker.talk();
+    speaker.talk();
+    speaker.talk();
+}
+
+fn main() {
+    let mut lincoln = SpeechMaker {speeches: 22};
+    give_a_few_speeches(&mut lincoln);
+}
diff --git a/src/test/run-pass/coerce-reborrow-mut-vec-arg.rs b/src/test/run-pass/coerce-reborrow-mut-vec-arg.rs
new file mode 100644 (file)
index 0000000..0cce52e
--- /dev/null
@@ -0,0 +1,15 @@
+trait Reverser {
+    fn reverse(&self);
+}
+
+fn bar(v: &[mut uint]) {
+    vec::reverse(v);
+    vec::reverse(v);
+    vec::reverse(v);
+}
+
+fn main() {
+    let mut the_vec = ~[1, 2, 3, 100];
+    bar(the_vec);
+    assert the_vec == ~[100, 3, 2, 1];
+}
diff --git a/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs b/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs
new file mode 100644 (file)
index 0000000..9fb748f
--- /dev/null
@@ -0,0 +1,21 @@
+trait Reverser {
+    fn reverse(&self);
+}
+
+impl &[mut uint] : Reverser {
+    fn reverse(&self) {
+        vec::reverse(*self);
+    }
+}
+
+fn bar(v: &[mut uint]) {
+    v.reverse();
+    v.reverse();
+    v.reverse();
+}
+
+fn main() {
+    let mut the_vec = ~[1, 2, 3, 100];
+    bar(the_vec);
+    assert the_vec == ~[100, 3, 2, 1];
+}
index 04932676f3d63074f5e3db53a42473dbe4b204b1..8a7ebb8d129e00b75019eafb98d9b7801d828ab4 100644 (file)
@@ -17,5 +17,5 @@
 fn main() {
     let buggy_map :HashMap<uint, &uint> = HashMap::<uint, &uint>();
     let x = ~1;
-    buggy_map.insert(42, x);
+    buggy_map.insert(42, &*x);
 }
index 2978585674524053669b9b95fd393e01ab2de5fd..453d556b13c994d0a2b468af5918327a9296e88e 100644 (file)
@@ -14,15 +14,7 @@ fn f() {
     io::println(b);
 }
 
-fn g() {
-    let c = ~"world";
-    let d: &str;
-    d = c;
-    io::println(d);
-}
-
 fn main() {
     f();
-    g();
 }