about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/rustc/middle/mem_categorization.rs8
-rw-r--r--src/rustc/middle/trans/base.rs12
-rw-r--r--src/rustc/middle/typeck/check/method.rs150
-rw-r--r--src/test/compile-fail/auto-ref-borrowck-failure.rs21
-rw-r--r--src/test/compile-fail/class-cast-to-trait.rs4
-rw-r--r--src/test/compile-fail/map-types.rs4
-rw-r--r--src/test/compile-fail/regions-bounds.rs4
-rw-r--r--src/test/compile-fail/regions-infer-paramd-method.rs2
-rw-r--r--src/test/compile-fail/regions-trait-2.rs2
-rw-r--r--src/test/compile-fail/regions-trait-3.rs4
-rw-r--r--src/test/compile-fail/trait-cast.rs2
-rw-r--r--src/test/run-pass/auto-ref.rs19
12 files changed, 170 insertions, 62 deletions
diff --git a/src/rustc/middle/mem_categorization.rs b/src/rustc/middle/mem_categorization.rs
index cf9ee1bc190..b509880ab5f 100644
--- a/src/rustc/middle/mem_categorization.rs
+++ b/src/rustc/middle/mem_categorization.rs
@@ -236,7 +236,8 @@ struct mem_categorization_ctxt {
 
 impl &mem_categorization_ctxt {
     fn cat_borrow_of_expr(expr: @ast::expr) -> cmt {
-        // a borrowed expression must be either an @, ~, or a @vec, ~vec
+        // Any expression can be borrowed (to account for auto-ref on method
+        // receivers), but @, ~, @vec, and ~vec are handled specially.
         let expr_ty = ty::expr_ty(self.tcx, expr);
         match ty::get(expr_ty).struct {
           ty::ty_evec(*) | ty::ty_estr(*) => {
@@ -255,10 +256,7 @@ impl &mem_categorization_ctxt {
           */
 
           _ => {
-            self.tcx.sess.span_bug(
-                expr.span,
-                fmt!{"Borrowing of non-derefable type `%s`",
-                     ty_to_str(self.tcx, expr_ty)});
+            self.cat_rvalue(expr, expr_ty)
           }
         }
     }
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index 83bdb941f46..2734fa85ae6 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -3056,9 +3056,15 @@ fn adapt_borrowed_value(lv: lval_result,
       }
 
       _ => {
-        bcx.tcx().sess.span_bug(
-            e.span, fmt!{"cannot borrow a value of type %s",
-                         ppaux::ty_to_str(bcx.tcx(), e_ty)});
+        // Just take a reference. This is basically like trans_addr_of.
+        let mut {bcx, val, kind} = trans_temp_lval(bcx, e);
+        let is_immediate = ty::type_is_immediate(e_ty);
+        if (kind == lv_temporary && is_immediate) || kind == lv_owned_imm {
+            val = do_spill(bcx, val, e_ty);
+        }
+        return {lv: {bcx: bcx, val: val, kind: lv_temporary},
+                ty: ty::mk_rptr(bcx.tcx(), ty::re_static,
+                                {ty: e_ty, mutbl: ast::m_imm})};
       }
     }
 }
diff --git a/src/rustc/middle/typeck/check/method.rs b/src/rustc/middle/typeck/check/method.rs
index 3bb0e566dc6..6e45762eca6 100644
--- a/src/rustc/middle/typeck/check/method.rs
+++ b/src/rustc/middle/typeck/check/method.rs
@@ -11,13 +11,21 @@ import syntax::ast_map::node_id_to_str;
 import syntax::ast_util::{dummy_sp, new_def_hash};
 import dvec::{DVec, dvec};
 
+enum method_lookup_mode {
+    subtyping_mode,
+    assignability_mode,
+    immutable_reference_mode,
+    mutable_reference_mode
+}
+
 type candidate = {
-    self_ty: ty::t,          // type of a in a.b()
-    self_substs: ty::substs, // values for any tvars def'd on the class
-    rcvr_ty: ty::t,          // type of receiver in the method def
-    n_tps_m: uint,           // number of tvars defined on the method
-    fty: ty::t,              // type of the method
-    entry: method_map_entry
+    self_ty: ty::t,             // type of a in a.b()
+    self_substs: ty::substs,    // values for any tvars def'd on the class
+    rcvr_ty: ty::t,             // type of receiver in the method def
+    n_tps_m: uint,              // number of tvars defined on the method
+    fty: ty::t,                 // type of the method
+    entry: method_map_entry,
+    mode: method_lookup_mode    // the mode we used
 };
 
 fn transform_self_type_for_method
@@ -141,16 +149,33 @@ class lookup {
             // it.
             if self.candidates.len() > 0u { break; }
 
-            // Look for inherent methods.
+            // Look for inherent and extension methods, using subtyping.
             self.add_inherent_and_extension_candidates
-                (optional_inherent_methods, false);
+                (optional_inherent_methods, subtyping_mode);
 
             // if we found anything, stop before trying borrows
             if self.candidates.len() > 0u { break; }
 
-            // Again, look for inherent methods.
+            // Again, look for inherent and extension methods, this time using
+            // assignability.
+            self.add_inherent_and_extension_candidates
+                (optional_inherent_methods, assignability_mode);
+
+            // If we found anything, stop before trying auto-ref.
+            if self.candidates.len() > 0u { break; }
+
+            // Now look for inherent and extension methods, this time using an
+            // immutable reference.
             self.add_inherent_and_extension_candidates
-                (optional_inherent_methods, true);
+                (optional_inherent_methods, immutable_reference_mode);
+
+            // if we found anything, stop before attempting auto-deref.
+            if self.candidates.len() > 0u { break; }
+
+            // Now look for inherent and extension methods, this time using a
+            // mutable reference.
+            self.add_inherent_and_extension_candidates
+                (optional_inherent_methods, mutable_reference_mode);
 
             // if we found anything, stop before attempting auto-deref.
             if self.candidates.len() > 0u { break; }
@@ -362,9 +387,8 @@ class lookup {
     }
 
     // Returns true if any were added and false otherwise.
-    fn add_candidates_from_impl(im: @resolve3::Impl,
-                                use_assignability: bool) -> bool {
-
+    fn add_candidates_from_impl(im: @resolve3::Impl, mode: method_lookup_mode)
+                             -> bool {
         let mut added_any = false;
 
         // Check whether this impl has a method with the right name.
@@ -382,15 +406,33 @@ class lookup {
                 self.tcx(), impl_substs.self_r,
                 impl_ty, m.self_type);
 
-            // Depending on our argument, we find potential
-            // matches either by checking subtypability or
-            // type assignability. Collect the matches.
-            let matches = if use_assignability {
-                self.fcx.can_mk_assignty(self.self_expr, self.borrow_lb,
-                                         self.self_ty, impl_ty)
-            } else {
-                self.fcx.can_mk_subty(self.self_ty, impl_ty)
-            };
+            // Depending on our argument, we find potential matches by
+            // checking subtypability, type assignability, or reference
+            // subtypability. Collect the matches.
+            let matches;
+            match mode {
+                subtyping_mode => 
+                    matches = self.fcx.can_mk_subty(self.self_ty, impl_ty),
+                assignability_mode =>
+                    matches = self.fcx.can_mk_assignty(self.self_expr,
+                                                       self.borrow_lb,
+                                                       self.self_ty,
+                                                       impl_ty),
+                immutable_reference_mode => {
+                    let region = self.fcx.infcx.next_region_var_with_scope_lb
+                        (self.self_expr.id);
+                    let tm = { ty: self.self_ty, mutbl: ast::m_imm };
+                    let ref_ty = ty::mk_rptr(self.tcx(), region, tm);
+                    matches = self.fcx.can_mk_subty(ref_ty, impl_ty);
+                }
+                mutable_reference_mode => {
+                    let region = self.fcx.infcx.next_region_var_with_scope_lb
+                        (self.self_expr.id);
+                    let tm = { ty: self.self_ty, mutbl: ast::m_mutbl };
+                    let ref_ty = ty::mk_rptr(self.tcx(), region, tm);
+                    matches = self.fcx.can_mk_subty(ref_ty, impl_ty);
+                }
+            }
             debug!{"matches = %?", matches};
             match matches {
               result::err(_) => { /* keep looking */ }
@@ -404,7 +446,8 @@ class lookup {
                          n_tps_m: m.n_tps,
                          fty: fty,
                          entry: {derefs: self.derefs,
-                                 origin: method_static(m.did)}});
+                                 origin: method_static(m.did)},
+                         mode: mode});
                     self.candidate_impls.insert(im.did, ());
                     added_any = true;
                 }
@@ -431,12 +474,13 @@ class lookup {
              rcvr_ty: self.self_ty,
              n_tps_m: (*m.tps).len(),
              fty: fty,
-             entry: {derefs: self.derefs, origin: origin}});
+             entry: {derefs: self.derefs, origin: origin},
+             mode: subtyping_mode});
     }
 
     fn add_inherent_and_extension_candidates(optional_inherent_methods:
                                                 option<@DVec<@Impl>>,
-                                             use_assignability: bool) {
+                                             mode: method_lookup_mode) {
 
         // Add inherent methods.
         match optional_inherent_methods {
@@ -451,8 +495,7 @@ class lookup {
                         adding candidates from impl: %s",
                         node_id_to_str(self.tcx().items,
                                        implementation.did.node)};
-                self.add_candidates_from_impl(implementation,
-                                              use_assignability);
+                self.add_candidates_from_impl(implementation, mode);
             }
           }
         }
@@ -479,8 +522,7 @@ class lookup {
                                 candidates) adding impl %s",
                                 self.def_id_to_str
                                 (implementation.did)};
-                        self.add_candidates_from_impl
-                            (implementation, use_assignability);
+                        self.add_candidates_from_impl(implementation, mode);
                     }
                   }
                 }
@@ -505,19 +547,41 @@ class lookup {
                self.fcx.infcx.ty_to_str(cand.fty),
                cand.entry};
 
-        // Make the actual receiver type (cand.self_ty) assignable to the
-        // required receiver type (cand.rcvr_ty).  If this method is not
-        // from an impl, this'll basically be a no-nop.
-        match self.fcx.mk_assignty(self.self_expr, self.borrow_lb,
-                                   cand.self_ty, cand.rcvr_ty) {
-          result::ok(_) => (),
-          result::err(_) => {
-            self.tcx().sess.span_bug(
-                self.expr.span,
-                fmt!{"%s was assignable to %s but now is not?",
-                     self.fcx.infcx.ty_to_str(cand.self_ty),
-                     self.fcx.infcx.ty_to_str(cand.rcvr_ty)});
-          }
+        match cand.mode {
+            subtyping_mode | assignability_mode => {
+                // Make the actual receiver type (cand.self_ty) assignable to
+                // the required receiver type (cand.rcvr_ty).  If this method
+                // is not from an impl, this'll basically be a no-nop.
+                match self.fcx.mk_assignty(self.self_expr, self.borrow_lb,
+                                           cand.self_ty, cand.rcvr_ty) {
+                  result::ok(_) => (),
+                  result::err(_) => {
+                    self.tcx().sess.span_bug(
+                        self.expr.span,
+                        fmt!{"%s was assignable to %s but now is not?",
+                             self.fcx.infcx.ty_to_str(cand.self_ty),
+                             self.fcx.infcx.ty_to_str(cand.rcvr_ty)});
+                  }
+                }
+            }
+            immutable_reference_mode => {
+                // Borrow as an immutable reference.
+                let region_var = self.fcx.infcx.next_region_var_with_scope_lb
+                    (self.self_expr.id);
+                self.fcx.infcx.borrowings.push({expr_id: self.self_expr.id,
+                                                span: self.self_expr.span,
+                                                scope: region_var,
+                                                mutbl: ast::m_imm});
+            }
+            mutable_reference_mode => {
+                // Borrow as a mutable reference.
+                let region_var = self.fcx.infcx.next_region_var_with_scope_lb
+                    (self.self_expr.id);
+                self.fcx.infcx.borrowings.push({expr_id: self.self_expr.id,
+                                                span: self.self_expr.span,
+                                                scope: region_var,
+                                                mutbl: ast::m_mutbl});
+            }
         }
 
         // Construct the full set of type parameters for the method,
@@ -546,7 +610,7 @@ class lookup {
         let all_substs = {tps: vec::append(cand.self_substs.tps, m_substs)
                           with cand.self_substs};
 
-         self.fcx.write_ty_substs(self.node_id, cand.fty, all_substs);
+        self.fcx.write_ty_substs(self.node_id, cand.fty, all_substs);
 
         return cand.entry;
     }
diff --git a/src/test/compile-fail/auto-ref-borrowck-failure.rs b/src/test/compile-fail/auto-ref-borrowck-failure.rs
new file mode 100644
index 00000000000..316f3797196
--- /dev/null
+++ b/src/test/compile-fail/auto-ref-borrowck-failure.rs
@@ -0,0 +1,21 @@
+// Tests that auto-ref can't create mutable aliases to immutable memory.
+
+struct Foo {
+    x: int;
+}
+
+trait Stuff {
+    fn printme();
+}
+
+impl &mut Foo : Stuff {
+    fn printme() {
+        io::println(fmt!("%d", self.x));
+    }
+}
+
+fn main() {
+    let x = Foo { x: 3 };
+    x.printme();    //~ ERROR illegal borrow
+}
+
diff --git a/src/test/compile-fail/class-cast-to-trait.rs b/src/test/compile-fail/class-cast-to-trait.rs
index 159e881ee8a..eba939d76e7 100644
--- a/src/test/compile-fail/class-cast-to-trait.rs
+++ b/src/test/compile-fail/class-cast-to-trait.rs
@@ -1,4 +1,4 @@
-// error-pattern: attempted access of field `eat` on type `noisy`
+// error-pattern: attempted access of field `eat` on type `@noisy`
 trait noisy {
   fn speak();
 }
@@ -39,4 +39,4 @@ class cat : noisy {
 fn main() {
   let nyan : noisy  = cat(0u, 2, "nyan") as noisy;
   nyan.eat();
-}
\ No newline at end of file
+}
diff --git a/src/test/compile-fail/map-types.rs b/src/test/compile-fail/map-types.rs
index 0a506367341..5131bd81c7c 100644
--- a/src/test/compile-fail/map-types.rs
+++ b/src/test/compile-fail/map-types.rs
@@ -6,7 +6,7 @@ import std::map::map;
 // Test that trait types printed in error msgs include the type arguments.
 
 fn main() {
-    let x: map<~str,~str> = map::str_hash::<~str>() as map::<~str,~str>;
+    let x: map<~str,~str> = map::str_hash::<~str>() as @map::<~str,~str>;
     let y: map<uint,~str> = x;
-    //~^ ERROR mismatched types: expected `std::map::map<uint,~str>`
+    //~^ ERROR mismatched types: expected `@std::map::map<uint,~str>`
 }
diff --git a/src/test/compile-fail/regions-bounds.rs b/src/test/compile-fail/regions-bounds.rs
index e795c5b8686..28c3b1c4463 100644
--- a/src/test/compile-fail/regions-bounds.rs
+++ b/src/test/compile-fail/regions-bounds.rs
@@ -11,7 +11,7 @@ fn a_fn1(e: an_enum/&a) -> an_enum/&b {
 }
 
 fn a_fn2(e: a_trait/&a) -> a_trait/&b {
-    return e; //~ ERROR mismatched types: expected `a_trait/&b` but found `a_trait/&a`
+    return e; //~ ERROR mismatched types: expected `@a_trait/&b` but found `@a_trait/&a`
 }
 
 fn a_fn3(e: a_class/&a) -> a_class/&b {
@@ -24,4 +24,4 @@ fn a_fn4(e: int/&a) -> int/&b {
     return e;
 }
 
-fn main() { }
\ No newline at end of file
+fn main() { }
diff --git a/src/test/compile-fail/regions-infer-paramd-method.rs b/src/test/compile-fail/regions-infer-paramd-method.rs
index 73b834c2624..61389763955 100644
--- a/src/test/compile-fail/regions-infer-paramd-method.rs
+++ b/src/test/compile-fail/regions-infer-paramd-method.rs
@@ -15,7 +15,7 @@ trait set_foo_foo {
 
 impl with_foo: set_foo_foo {
     fn set_foo(f: foo) {
-        self.f = f; //~ ERROR mismatched types: expected `foo/&self` but found `foo/&`
+        self.f = f; //~ ERROR mismatched types: expected `@foo/&self` but found `@foo/&`
     }
 }
 
diff --git a/src/test/compile-fail/regions-trait-2.rs b/src/test/compile-fail/regions-trait-2.rs
index a34a903e3ba..661f64ec651 100644
--- a/src/test/compile-fail/regions-trait-2.rs
+++ b/src/test/compile-fail/regions-trait-2.rs
@@ -13,7 +13,7 @@ impl has_ctxt: get_ctxt {
 fn make_gc() -> get_ctxt  {
     let ctxt = { v: 22u };
     let hc = { c: &ctxt };
-    return hc as get_ctxt; //~ ERROR mismatched types: expected `get_ctxt/&`
+    return hc as get_ctxt; //~ ERROR mismatched types: expected `@get_ctxt/&`
 }
 
 fn main() {
diff --git a/src/test/compile-fail/regions-trait-3.rs b/src/test/compile-fail/regions-trait-3.rs
index a0be6c90177..b3a0d0fcf62 100644
--- a/src/test/compile-fail/regions-trait-3.rs
+++ b/src/test/compile-fail/regions-trait-3.rs
@@ -3,11 +3,11 @@ trait get_ctxt {
 }
 
 fn make_gc1(gc: get_ctxt/&a) -> get_ctxt/&b  {
-    return gc; //~ ERROR mismatched types: expected `get_ctxt/&b` but found `get_ctxt/&a`
+    return gc; //~ ERROR mismatched types: expected `@get_ctxt/&b` but found `@get_ctxt/&a`
 }
 
 fn make_gc2(gc: get_ctxt/&a) -> get_ctxt/&b  {
-    return gc as get_ctxt; //~ ERROR mismatched types: expected `get_ctxt/&b` but found `get_ctxt/&a`
+    return gc as get_ctxt; //~ ERROR mismatched types: expected `@get_ctxt/&b` but found `@get_ctxt/&a`
 }
 
 fn main() {
diff --git a/src/test/compile-fail/trait-cast.rs b/src/test/compile-fail/trait-cast.rs
index 736634c13e8..9e15a31d95a 100644
--- a/src/test/compile-fail/trait-cast.rs
+++ b/src/test/compile-fail/trait-cast.rs
@@ -2,7 +2,7 @@ trait foo<T> { }
 
 fn bar(x: foo<uint>) -> foo<int> {
     return (x as foo::<int>);
-    //~^ ERROR mismatched types: expected `foo<int>` but found `foo<uint>`
+    //~^ ERROR mismatched types: expected `@foo<int>` but found `@foo<uint>`
 }
 
 fn main() {}
diff --git a/src/test/run-pass/auto-ref.rs b/src/test/run-pass/auto-ref.rs
new file mode 100644
index 00000000000..e5d4d106b53
--- /dev/null
+++ b/src/test/run-pass/auto-ref.rs
@@ -0,0 +1,19 @@
+struct Foo {
+    x: int;
+}
+
+trait Stuff {
+    fn printme();
+}
+
+impl &Foo : Stuff {
+    fn printme() {
+        io::println(fmt!("%d", self.x));
+    }
+}
+
+fn main() {
+    let x = Foo { x: 3 };
+    x.printme();
+}
+