]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc/middle/typeck/check/method.rs
librustc: Permit by-value-self methods to be invoked on objects
[rust.git] / src / librustc / middle / typeck / check / method.rs
index 864de344db2cdd12ccdd42ef0db2c24a6824fbcb..c3b2756bdbff2f7f165af2718ec6a1fe293a7452 100644 (file)
@@ -93,6 +93,7 @@ trait `ToStr` imported, and I call `to_str()` on a value of type `T`,
 use middle::typeck::{MethodStatic, MethodObject};
 use middle::typeck::{param_index};
 use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
+use middle::typeck::TypeAndSubsts;
 use util::common::indenter;
 use util::ppaux;
 use util::ppaux::Repr;
@@ -270,21 +271,23 @@ fn construct_transformed_self_ty_for_object(
             tcx.sess.span_bug(span, "static method for object type receiver");
         }
         ast::SelfValue => {
-            ty::mk_err() // error reported in `enforce_object_limitations()`
+            let tr = ty::mk_trait(tcx, trait_def_id, obj_substs,
+                                  ty::empty_builtin_bounds());
+            ty::mk_uniq(tcx, tr)
         }
         ast::SelfRegion(..) | ast::SelfUniq => {
             let transformed_self_ty = *method_ty.fty.sig.inputs.get(0);
             match ty::get(transformed_self_ty).sty {
                 ty::ty_rptr(r, mt) => { // must be SelfRegion
                     let r = r.subst(tcx, rcvr_substs); // handle Early-Bound lifetime
-                    ty::mk_trait(tcx, trait_def_id, obj_substs,
-                                 RegionTraitStore(r, mt.mutbl),
-                                 ty::empty_builtin_bounds())
+                    let tr = ty::mk_trait(tcx, trait_def_id, obj_substs,
+                                          ty::empty_builtin_bounds());
+                    ty::mk_rptr(tcx, r, ty::mt{ ty: tr, mutbl: mt.mutbl })
                 }
                 ty::ty_uniq(_) => { // must be SelfUniq
-                    ty::mk_trait(tcx, trait_def_id, obj_substs,
-                                 UniqTraitStore,
-                                 ty::empty_builtin_bounds())
+                    let tr = ty::mk_trait(tcx, trait_def_id, obj_substs,
+                                          ty::empty_builtin_bounds());
+                    ty::mk_uniq(tcx, tr)
                 }
                 _ => {
                     tcx.sess.span_bug(span,
@@ -433,10 +436,13 @@ fn push_inherent_candidates(&mut self, self_ty: ty::t) {
         let span = self.self_expr.map_or(self.span, |e| e.span);
         check::autoderef(self.fcx, span, self_ty, None, PreferMutLvalue, |self_ty, _| {
             match get(self_ty).sty {
-                ty_trait(box TyTrait { def_id, ref substs, .. }) => {
-                    self.push_inherent_candidates_from_object(def_id, substs);
-                    self.push_inherent_impl_candidates_for_type(def_id);
-                }
+                ty_uniq(ty) | ty_rptr(_, mt {ty, ..}) => match get(ty).sty{
+                    ty_trait(box TyTrait { def_id, ref substs, .. }) => {
+                        self.push_inherent_candidates_from_object(def_id, substs);
+                        self.push_inherent_impl_candidates_for_type(def_id);
+                    }
+                    _ => {}
+                },
                 ty_enum(did, _) | ty_struct(did, _) => {
                     if self.check_traits == CheckTraitsAndInherentMethods {
                         self.push_inherent_impl_candidates_for_type(did);
@@ -685,7 +691,7 @@ fn push_candidates_from_impl(&mut self,
         // variables for each parameter:
         let span = self.self_expr.map_or(self.span, |e| e.span);
         let vcx = self.fcx.vtable_context();
-        let ty::ty_param_substs_and_ty {
+        let TypeAndSubsts {
             substs: impl_substs,
             ty: impl_ty
         } = impl_self_ty(&vcx, span, impl_did);
@@ -774,6 +780,7 @@ fn consider_reborrow(&self,
                 let (extra_derefs, auto) = match ty::get(self_mt.ty).sty {
                     ty::ty_vec(_, None) => (0, ty::AutoBorrowVec(region, self_mt.mutbl)),
                     ty::ty_str => (0, ty::AutoBorrowVec(region, self_mt.mutbl)),
+                    ty::ty_trait(..) => (0, ty::AutoBorrowObj(region, self_mt.mutbl)),
                     _ => (1, ty::AutoPtr(region, self_mt.mutbl)),
                 };
                 (ty::mk_rptr(tcx, region, self_mt),
@@ -781,18 +788,6 @@ fn consider_reborrow(&self,
                      autoderefs: autoderefs + extra_derefs,
                      autoref: Some(auto)})
             }
-
-            ty::ty_trait(box ty::TyTrait {
-                def_id, ref substs, store: ty::RegionTraitStore(_, mutbl), bounds
-            }) => {
-                let region =
-                    self.infcx().next_region_var(infer::Autoref(self.span));
-                (ty::mk_trait(tcx, def_id, substs.clone(),
-                              ty::RegionTraitStore(region, mutbl), bounds),
-                 ty::AutoDerefRef {
-                     autoderefs: autoderefs,
-                     autoref: Some(ty::AutoBorrowObj(region, mutbl))})
-            }
             _ => {
                 (self_ty,
                  ty::AutoDerefRef {
@@ -862,6 +857,26 @@ fn auto_slice_str(&self, autoderefs: uint) -> Option<MethodCallee> {
             })
     }
 
+    // Coerce Box/&Trait instances to &Trait.
+    fn auto_slice_trait(&self, ty: ty::t, autoderefs: uint) -> Option<MethodCallee> {
+        match ty::get(ty).sty {
+            ty_trait(box ty::TyTrait {
+                    def_id: trt_did,
+                    substs: ref trt_substs,
+                    bounds: b,
+                    .. }) => {
+                let tcx = self.tcx();
+                self.search_for_some_kind_of_autorefd_method(
+                    AutoBorrowObj, autoderefs, [MutImmutable, MutMutable],
+                    |m, r| {
+                        let tr = ty::mk_trait(tcx, trt_did, trt_substs.clone(), b);
+                        ty::mk_rptr(tcx, r, ty::mt{ ty: tr, mutbl: m })
+                    })
+            }
+            _ => fail!("Expected ty_trait in auto_slice_trait")
+        }
+    }
+
     fn search_for_autosliced_method(&self,
                                     self_ty: ty::t,
                                     autoderefs: uint)
@@ -871,38 +886,23 @@ fn search_for_autosliced_method(&self,
          * `~[]` to `&[]`.
          */
 
-        let tcx = self.tcx();
-        debug!("search_for_autosliced_method {}", ppaux::ty_to_str(tcx, self_ty));
+        debug!("search_for_autosliced_method {}", ppaux::ty_to_str(self.tcx(), self_ty));
 
         let sty = ty::get(self_ty).sty.clone();
         match sty {
             ty_rptr(_, mt) => match ty::get(mt.ty).sty {
                 ty_vec(mt, None) => self.auto_slice_vec(mt, autoderefs),
+                ty_trait(..) => self.auto_slice_trait(mt.ty, autoderefs),
                 _ => None
             },
             ty_uniq(t) => match ty::get(t).sty {
                 ty_vec(mt, None) => self.auto_slice_vec(mt, autoderefs),
                 ty_str => self.auto_slice_str(autoderefs),
+                ty_trait(..) => self.auto_slice_trait(t, autoderefs),
                 _ => None
             },
             ty_vec(mt, Some(_)) => self.auto_slice_vec(mt, autoderefs),
 
-            ty_trait(box ty::TyTrait {
-                    def_id: trt_did,
-                    substs: trt_substs,
-                    bounds: b,
-                    ..
-                }) => {
-                // Coerce Box/&Trait instances to &Trait.
-
-                self.search_for_some_kind_of_autorefd_method(
-                    AutoBorrowObj, autoderefs, [MutImmutable, MutMutable],
-                    |m, r| {
-                        ty::mk_trait(tcx, trt_did, trt_substs.clone(),
-                                     RegionTraitStore(r, m), b)
-                    })
-            }
-
             ty_closure(..) => {
                 // This case should probably be handled similarly to
                 // Trait instances.
@@ -1227,14 +1227,7 @@ fn enforce_object_limitations(&self, candidate: &Candidate) {
                      through an object");
             }
 
-            ast::SelfValue => { // reason (a) above
-                self.tcx().sess.span_err(
-                    self.span,
-                    "cannot call a method with a by-value receiver \
-                     through an object");
-            }
-
-            ast::SelfRegion(..) | ast::SelfUniq => {}
+            ast::SelfValue | ast::SelfRegion(..) | ast::SelfUniq => {}
         }
 
         // reason (a) above
@@ -1304,7 +1297,26 @@ fn is_relevant(&self, rcvr_ty: ty::t, candidate: &Candidate) -> bool {
             }
 
             SelfValue => {
-                rcvr_matches_ty(self.fcx, rcvr_ty, candidate)
+                debug!("(is relevant?) explicit self is by-value");
+                match ty::get(rcvr_ty).sty {
+                    ty::ty_uniq(typ) => {
+                        match ty::get(typ).sty {
+                            ty::ty_trait(box ty::TyTrait {
+                                def_id: self_did,
+                                ..
+                            }) => {
+                                rcvr_matches_object(self_did, candidate) ||
+                                    rcvr_matches_ty(self.fcx,
+                                                    rcvr_ty,
+                                                    candidate)
+                            }
+                            _ => {
+                                rcvr_matches_ty(self.fcx, rcvr_ty, candidate)
+                            }
+                        }
+                    }
+                    _ => rcvr_matches_ty(self.fcx, rcvr_ty, candidate)
+                }
             }
 
             SelfRegion(_, m) => {
@@ -1313,17 +1325,15 @@ fn is_relevant(&self, rcvr_ty: ty::t, candidate: &Candidate) -> bool {
                     ty::ty_rptr(_, mt) => {
                         match ty::get(mt.ty).sty {
                             ty::ty_vec(_, None) | ty::ty_str => false,
+                            ty::ty_trait(box ty::TyTrait { def_id: self_did, .. }) => {
+                                mutability_matches(mt.mutbl, m) &&
+                                rcvr_matches_object(self_did, candidate)
+                            }
                             _ => mutability_matches(mt.mutbl, m) &&
                                  rcvr_matches_ty(self.fcx, mt.ty, candidate),
                         }
                     }
 
-                    ty::ty_trait(box ty::TyTrait {
-                        def_id: self_did, store: RegionTraitStore(_, self_m), ..
-                    }) => {
-                        mutability_matches(self_m, m) &&
-                        rcvr_matches_object(self_did, candidate)
-                    }
 
                     _ => false
                 }
@@ -1335,16 +1345,13 @@ fn is_relevant(&self, rcvr_ty: ty::t, candidate: &Candidate) -> bool {
                     ty::ty_uniq(typ) => {
                         match ty::get(typ).sty {
                             ty::ty_vec(_, None) | ty::ty_str => false,
+                            ty::ty_trait(box ty::TyTrait { def_id: self_did, .. }) => {
+                                rcvr_matches_object(self_did, candidate)
+                            }
                             _ => rcvr_matches_ty(self.fcx, typ, candidate),
                         }
                     }
 
-                    ty::ty_trait(box ty::TyTrait {
-                        def_id: self_did, store: UniqTraitStore, ..
-                    }) => {
-                        rcvr_matches_object(self_did, candidate)
-                    }
-
                     _ => false
                 }
             }