summary refs log tree commit diff
path: root/src/rustc
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2012-04-11 13:10:35 -0700
committerNiko Matsakis <niko@alum.mit.edu>2012-04-11 17:21:53 -0700
commit3e6943d8201215e60b74df7d3be8f48a52b3c2b7 (patch)
treea21b74a717a8865fe75ee683a2b871f8e201714b /src/rustc
parentc1c60c023ec3b9b5bb85aa68d00667c4ab61ee00 (diff)
downloadrust-3e6943d8201215e60b74df7d3be8f48a52b3c2b7.tar.gz
rust-3e6943d8201215e60b74df7d3be8f48a52b3c2b7.zip
refactor fixup_self
Diffstat (limited to 'src/rustc')
-rw-r--r--src/rustc/middle/typeck.rs147
1 files changed, 88 insertions, 59 deletions
diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs
index add63e357e2..a6fd7ca6082 100644
--- a/src/rustc/middle/typeck.rs
+++ b/src/rustc/middle/typeck.rs
@@ -934,10 +934,7 @@ fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method,
         });
         let mut if_fty = ty::mk_fn(tcx, if_m.fty);
         if_fty = ty::substitute_type_params(tcx, substs, if_fty);
-        if ty::type_has_vars(if_fty) {
-            if_fty = fixup_self_in_method_ty(tcx, if_fty, substs,
-                                             self_full(self_ty, impl_tps));
-        }
+        if_fty = fixup_self_full(tcx, if_fty, substs, self_ty, impl_tps);
         require_same_types(
             tcx, sp, impl_fty, if_fty,
             {|| "method `" + if_m.ident +
@@ -946,61 +943,84 @@ fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method,
     }
 }
 
-enum self_subst { self_param(ty::t, @fn_ctxt, span), self_full(ty::t, uint) }
+// Mangles an iface method ty to make its self type conform to the self type
+// of a specific impl or bounded type parameter. This is rather involved
+// because the type parameters of ifaces and impls are not required to line up
+// (an impl can have less or more parameters than the iface it implements), so
+// some mangling of the substituted types is required.
+fn fixup_self_full(cx: ty::ctxt, mty: ty::t, m_substs: [ty::t],
+                   selfty: ty::t, impl_n_tps: uint) -> ty::t {
+
+    if !ty::type_has_vars(mty) { ret mty; }
+
+    ty::fold_ty(cx, mty) {|t|
+        alt ty::get(t).struct {
+          ty::ty_self(tps) if vec::len(tps) == 0u {
+            selfty
+          }
+          ty::ty_self(tps) {
+            // Move the substs into the type param system of the
+            // context.
+            let mut substs = vec::map(tps) {|t|
+                let f = fixup_self_full(cx, t, m_substs, selfty, impl_n_tps);
+                ty::substitute_type_params(cx, m_substs, f)
+            };
+
+            // Add extra substs for impl type parameters.
+            while vec::len(substs) < impl_n_tps {
+                substs += [ty::mk_param(cx, vec::len(substs),
+                                        {crate: 0, node: 0})];
+            }
+
+            // And for method type parameters.
+            let method_n_tps =
+                (vec::len(m_substs) - vec::len(tps)) as int;
+            if method_n_tps > 0 {
+                substs += vec::tailn(m_substs, vec::len(m_substs)
+                                     - (method_n_tps as uint));
+            }
+
+            // And then instantiate the self type using all those.
+            ty::substitute_type_params(cx, substs, selfty)
+          }
+          _ {
+              t
+          }
+        }
+    }
+}
 
 // Mangles an iface method ty to make its self type conform to the self type
 // of a specific impl or bounded type parameter. This is rather involved
 // because the type parameters of ifaces and impls are not required to line up
 // (an impl can have less or more parameters than the iface it implements), so
 // some mangling of the substituted types is required.
-fn fixup_self_in_method_ty(cx: ty::ctxt, mty: ty::t, m_substs: [ty::t],
-                           self: self_subst) -> ty::t {
-    if ty::type_has_vars(mty) {
-        ty::fold_ty(cx, mty) {|t|
-            alt ty::get(t).struct {
-              ty::ty_self(tps) {
-                if vec::len(tps) > 0u {
-                    // Move the substs into the type param system of the
-                    // context.
-                    let mut substs = vec::map(tps, {|t|
-                        let f = fixup_self_in_method_ty(cx, t, m_substs,
-                                                        self);
-                        ty::substitute_type_params(cx, m_substs, f)
-                    });
-                    alt self {
-                      self_param(t, fcx, sp) {
-                        // Simply ensure that the type parameters for the self
-                        // type match the context.
-                        vec::iter2(substs, m_substs) {|s, ms|
-                            demand::simple(fcx, sp, s, ms);
-                        }
-                        t
-                      }
-                      self_full(selfty, impl_n_tps) {
-                        // Add extra substs for impl type parameters.
-                        while vec::len(substs) < impl_n_tps {
-                            substs += [ty::mk_param(cx, vec::len(substs),
-                                                    {crate: 0, node: 0})];
-                        }
-                        // And for method type parameters.
-                        let method_n_tps =
-                            (vec::len(m_substs) - vec::len(tps)) as int;
-                        if method_n_tps > 0 {
-                            substs += vec::tailn(m_substs, vec::len(m_substs)
-                                                  - (method_n_tps as uint));
-                        }
-                        // And then instantiate the self type using all those.
-                        ty::substitute_type_params(cx, substs, selfty)
-                      }
-                    }
-                } else {
-                    alt self { self_param(t, _, _) | self_full(t, _) { t } }
-                }
-              }
-              _ { t }
+fn fixup_self_param(fcx: @fn_ctxt, mty: ty::t, m_substs: [ty::t],
+                    selfty: ty::t, sp: span) -> ty::t {
+    if !ty::type_has_vars(mty) { ret mty; }
+
+    let tcx = fcx.ccx.tcx;
+    ty::fold_ty(tcx, mty) {|t|
+        alt ty::get(t).struct {
+          ty::ty_self(tps) if vec::len(tps) == 0u { selfty }
+          ty::ty_self(tps) {
+            // Move the substs into the type param system of the
+            // context.
+            let mut substs = vec::map(tps) {|t|
+                let f = fixup_self_param(fcx, t, m_substs, selfty, sp);
+                ty::substitute_type_params(tcx, m_substs, f)
+            };
+
+            // Simply ensure that the type parameters for the self
+            // type match the context.
+            vec::iter2(substs, m_substs) {|s, ms|
+                demand::simple(fcx, sp, s, ms);
             }
+            selfty
+          }
+          _ { t }
         }
-    } else { mty }
+    }
 }
 
 // Replaces all occurrences of the `self` region with `with_region`.  Note
@@ -2190,6 +2210,10 @@ fn impl_self_ty(tcx: ty::ctxt, did: ast::def_id) -> {n_tps: uint, ty: ty::t} {
     }
 }
 
+type self_subst = {selfty: ty::t,
+                   fcx: @fn_ctxt,
+                   sp: span};
+
 /*
   Takes arguments describing a method, and returns either its origin,
   or <none> if it's unbound.
@@ -2249,8 +2273,8 @@ fn lookup_method(fcx: @fn_ctxt, expr: @ast::expr, node_id: ast::node_id,
         }
         if has_self && !option::is_none(self_sub) {
             let fty = fcx.node_ty(node_id);
-            let fty = fixup_self_in_method_ty(
-                tcx, fty, substs, option::get(self_sub));
+            let fty = fixup_self_param(
+                fcx, fty, substs, option::get(self_sub), expr.span);
             fcx.write_ty(node_id, fty);
         }
         if ty::type_has_rptrs(ty::ty_fn_ret(fty)) {
@@ -2273,8 +2297,11 @@ enum method_kind {
 fn lookup_method_inner_(tcx: ty::ctxt, ms: [ty::method],
      tps: [ty::t], parent: method_kind, name: ast::ident, sp: span,
                         include_private: bool)
-    -> option<{method_ty: ty::t, n_tps: uint, substs: [ty::t],
-        origin: method_origin, self_sub: option<self_subst>}> {
+    -> option<{method_ty: ty::t,
+               n_tps: uint,
+               substs: [ty::t],
+               origin: method_origin,
+               self_sub: option<ty::t>}> {
     let mut i = 0u;
     for ms.each {|m|
        if m.ident == name {
@@ -2318,9 +2345,11 @@ fn lookup_method_inner_(tcx: ty::ctxt, ms: [ty::method],
 fn lookup_method_inner(fcx: @fn_ctxt, expr: @ast::expr,
                        name: ast::ident, ty: ty::t,
                        include_private: bool)
-    -> option<{method_ty: ty::t, n_tps: uint, substs: [ty::t],
-                  origin: method_origin,
-                  self_sub: option<self_subst>}> {
+    -> option<{method_ty: ty::t,
+               n_tps: uint,
+               substs: [ty::t],
+               origin: method_origin,
+               self_sub: option<ty::t>}> {
     let tcx = fcx.ccx.tcx;
 
     #debug["lookup_method_inner: expr=%s name=%s ty=%s",
@@ -2345,7 +2374,7 @@ fn lookup_method_inner(fcx: @fn_ctxt, expr: @ast::expr,
                               n_tps: vec::len(*m.tps),
                               substs: tps,
                               origin: method_param(iid, pos, n, bound_n),
-                              self_sub: some(self_param(ty, fcx, expr.span))
+                              self_sub: some(ty)
                              });
                   }
                   _ {}