about summary refs log tree commit diff
path: root/src/comp
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2012-03-01 19:37:52 -0800
committerNiko Matsakis <niko@alum.mit.edu>2012-03-02 06:47:25 -0800
commit6473a87cec100682764f4d926541fc7eb455b00c (patch)
tree695fd8037c9ee0b1f932ad4864ed867b05270d55 /src/comp
parentdef72bda47977b3bc36143eba9692bff12a8303c (diff)
restructure to better support method inlining
Diffstat (limited to 'src/comp')
-rw-r--r--src/comp/metadata/astencode.rs150
-rw-r--r--src/comp/metadata/astencode_gen.rs86
-rw-r--r--src/comp/metadata/csearch.rs2
-rw-r--r--src/comp/metadata/decoder.rs2
-rw-r--r--src/comp/metadata/encoder.rs2
-rw-r--r--src/comp/middle/ast_map.rs19
-rw-r--r--src/comp/middle/inline.rs29
-rw-r--r--src/comp/middle/trans/base.rs125
-rw-r--r--src/comp/middle/trans/impl.rs9
-rw-r--r--src/comp/syntax/ast.rs8
-rw-r--r--src/comp/syntax/ast_util.rs23
-rw-r--r--src/comp/syntax/fold.rs1
12 files changed, 269 insertions, 187 deletions
diff --git a/src/comp/metadata/astencode.rs b/src/comp/metadata/astencode.rs
index c24c80cf74b..bd1309c7c86 100644
--- a/src/comp/metadata/astencode.rs
+++ b/src/comp/metadata/astencode.rs
@@ -2,6 +2,7 @@ import syntax::ast;
 import syntax::fold;
 import syntax::visit;
 import syntax::ast_util;
+import syntax::ast_util::inlined_item_methods;
 import syntax::codemap::span;
 import std::map::map;
 import std::smallintmap::map;
@@ -31,8 +32,6 @@ import syntax::print::pprust;
 
 export encode_inlined_item;
 export decode_inlined_item;
-export encode_inlined_method;
-export decode_inlined_method;
 
 type decode_ctxt = @{
     cdata: cstore::crate_metadata,
@@ -53,123 +52,49 @@ iface tr {
 // ______________________________________________________________________
 // Top-level methods.
 
-// The type inline_fn should be a type that can represent both methods
-// and top-level items. As it happens, the type ast::method is perfect
-// for this purpose, but I use this typedef just to keep clear when
-// the thing may not, in fact, be an actual method in the AST but
-// rather some sort of function.
-enum inline_fn = @ast::method;
-
 fn encode_inlined_item(ecx: @e::encode_ctxt,
                        ebml_w: ebml::writer,
                        path: ast_map::path,
-                       item: @ast::item) {
-    let ifn = inline_fn(alt item.node {
-      ast::item_fn(decl, tps, body) {
-          @{ident: item.ident,
-            attrs: item.attrs,
-            tps: tps,
-            decl: decl,
-            body: body,
-            id: item.id,
-            span: item.span}
-      }
-
-      _ {
-          ecx.ccx.sess.span_bug(item.span, "Cannot inline non-function")
-      }
-    });
-
-    encode_inlined_fn(ecx, ebml_w, path, ifn);
-}
-
-fn decode_inlined_item(cdata: cstore::crate_metadata,
-                       tcx: ty::ctxt,
-                       maps: maps,
-                       path: ast_map::path,
-                       par_doc: ebml::doc) -> option<@ast::item> {
-    let oifn = decode_inlined_fn(cdata, tcx, maps, path, par_doc);
-    option::map(oifn) {|ifn|
-        let item = @{ident: ifn.ident,
-                     attrs: ifn.attrs,
-                     id: ifn.id,
-                     node: ast::item_fn(ifn.decl, ifn.tps, ifn.body),
-                     span: ifn.span};
-        ast_map::map_decoded_item(tcx.items, path, item);
-        item
-    }
-}
-
-fn encode_inlined_method(ecx: @e::encode_ctxt,
-                         ebml_w: ebml::writer,
-                         path: ast_map::path,
-                         mthd: @ast::method) {
-    encode_inlined_fn(ecx, ebml_w, path, inline_fn(mthd))
-}
-
-fn decode_inlined_method(cdata: cstore::crate_metadata,
-                         tcx: ty::ctxt,
-                         maps: maps,
-                         path: ast_map::path,
-                         par_doc: ebml::doc) -> option<@ast::method> {
-    let oifn = decode_inlined_fn(cdata, tcx, maps, path, par_doc);
-    option::map(oifn) {|ifn|
-        ast_map::map_decoded_method(tcx.items, path, *ifn);
-        *ifn
-    }
-}
-
-fn encode_inlined_fn(ecx: @e::encode_ctxt,
-                     ebml_w: ebml::writer,
-                     path: ast_map::path,
-                     ifn: inline_fn) {
-
+                       ii: ast::inlined_item) {
     #debug["> Encoding inlined item: %s::%s (%u)",
-           ast_map::path_to_str(path),
-           ifn.ident,
+           ast_map::path_to_str(path), ii.ident(),
            ebml_w.writer.tell()];
 
-    let id_range = compute_id_range(ifn);
+    let id_range = compute_id_range(ii);
     ebml_w.wr_tag(c::tag_ast as uint) {||
         encode_id_range(ebml_w, id_range);
-        encode_ast(ebml_w, ifn);
-        encode_side_tables_for_ifn(ecx, ebml_w, ifn);
+        encode_ast(ebml_w, ii);
+        encode_side_tables_for_ii(ecx, ebml_w, ii);
     }
 
     #debug["< Encoded inlined fn: %s::%s (%u)",
-           ast_map::path_to_str(path),
-           ifn.ident,
+           ast_map::path_to_str(path), ii.ident(),
            ebml_w.writer.tell()];
 }
 
-// Decodes the inlined function and associated side tables.  Does
-// *not* insert the function into the ast_map, since the correct way
-// to do this depends on whether this is an inlined item or method;
-// therefore, you ought to be invoking decode_inlined_item() or
-// decode_inlined_method() and not this helper function.
-fn decode_inlined_fn(cdata: cstore::crate_metadata,
-                     tcx: ty::ctxt,
-                     maps: maps,
-                     path: ast_map::path,
-                     par_doc: ebml::doc) -> option<inline_fn> {
+fn decode_inlined_item(cdata: cstore::crate_metadata,
+                       tcx: ty::ctxt,
+                       maps: maps,
+                       path: ast_map::path,
+                       par_doc: ebml::doc) -> option<ast::inlined_item> {
     let dcx = @{cdata: cdata, tcx: tcx, maps: maps};
     alt par_doc.opt_child(c::tag_ast) {
       none { none }
       some(ast_doc) {
-        #debug["> Decoding inlined fn: %s", ast_map::path_to_str(path)];
+        #debug["> Decoding inlined fn: %s::?", ast_map::path_to_str(path)];
         let from_id_range = decode_id_range(ast_doc);
         let to_id_range = reserve_id_range(dcx.tcx.sess, from_id_range);
         let xcx = @{dcx: dcx,
                     from_id_range: from_id_range,
                     to_id_range: to_id_range};
-        let raw_ifn = decode_ast(ast_doc);
-        let ifn = renumber_ast(xcx, raw_ifn);
-        #debug["Fn named: %s", ifn.ident];
+        let raw_ii = decode_ast(ast_doc);
+        let ii = renumber_ast(xcx, raw_ii);
+        ast_map::map_decoded_item(dcx.tcx.items, path, ii);
+        #debug["Fn named: %s", ii.ident()];
         decode_side_tables(xcx, ast_doc);
         #debug["< Decoded inlined fn: %s::%s",
-               ast_map::path_to_str(path),
-               ifn.ident];
-        some(ifn)
+               ast_map::path_to_str(path), ii.ident()];
+        some(ii)
       }
     }
 }
@@ -183,7 +108,7 @@ fn empty(range: id_range) -> bool {
     range.min >= range.max
 }
 
-fn visit_ids(ifn: inline_fn, vfn: fn@(ast::node_id)) {
+fn visit_ids(item: ast::inlined_item, vfn: fn@(ast::node_id)) {
     let visitor = visit::mk_simple_visitor(@{
         visit_mod: fn@(_m: ast::_mod, _sp: span, id: ast::node_id) {
             vfn(id)
@@ -292,13 +217,13 @@ fn visit_ids(ifn: inline_fn, vfn: fn@(ast::node_id)) {
         }
     });
 
-    visit::visit_method_helper(*ifn, (), visitor);
+    item.accept((), visitor)
 }
 
-fn compute_id_range(ifn: inline_fn) -> id_range {
+fn compute_id_range(item: ast::inlined_item) -> id_range {
     let min = @mutable int::max_value;
     let max = @mutable int::min_value;
-    visit_ids(ifn) {|id|
+    visit_ids(item) {|id|
         *min = int::min(*min, id);
         *max = int::max(*max, id + 1);
     }
@@ -395,25 +320,34 @@ impl deserializer_helpers<D: serialization::deserializer> for D {
 // We also have to adjust the spans: for now we just insert a dummy span,
 // but eventually we should add entries to the local codemap as required.
 
-fn encode_ast(ebml_w: ebml::writer, ifn: inline_fn) {
+fn encode_ast(ebml_w: ebml::writer, item: ast::inlined_item) {
     ebml_w.wr_tag(c::tag_tree as uint) {||
-        astencode_gen::serialize_syntax_ast_method(ebml_w, **ifn)
+        astencode_gen::serialize_syntax_ast_inlined_item(ebml_w, item)
     }
 }
 
-fn decode_ast(par_doc: ebml::doc) -> inline_fn {
+fn decode_ast(par_doc: ebml::doc) -> ast::inlined_item {
     let chi_doc = par_doc[c::tag_tree];
     let d = serialization::mk_ebml_deserializer(chi_doc);
-    inline_fn(@astencode_gen::deserialize_syntax_ast_method(d))
+    astencode_gen::deserialize_syntax_ast_inlined_item(d)
 }
 
-fn renumber_ast(xcx: extended_decode_ctxt, ifn: inline_fn) -> inline_fn {
+fn renumber_ast(xcx: extended_decode_ctxt, ii: ast::inlined_item)
+    -> ast::inlined_item {
     let fld = fold::make_fold({
         new_id: xcx.tr_id(_),
         new_span: xcx.tr_span(_)
         with *fold::default_ast_fold()
     });
-    inline_fn(fld.fold_method(*ifn))
+
+    alt ii {
+      ast::ii_item(i) {
+        ast::ii_item(fld.fold_item(i))
+      }
+      ast::ii_method(d, m) {
+        ast::ii_method(xcx.tr_def_id(d), fld.fold_method(m))
+      }
+    }
 }
 
 // ______________________________________________________________________
@@ -664,11 +598,11 @@ impl writer for ebml::writer {
     }
 }
 
-fn encode_side_tables_for_ifn(ecx: @e::encode_ctxt,
-                              ebml_w: ebml::writer,
-                              ifn: inline_fn) {
+fn encode_side_tables_for_ii(ecx: @e::encode_ctxt,
+                             ebml_w: ebml::writer,
+                             ii: ast::inlined_item) {
     ebml_w.wr_tag(c::tag_table as uint) {||
-        visit_ids(ifn, fn@(id: ast::node_id) {
+        visit_ids(ii, fn@(id: ast::node_id) {
             // Note: this will cause a copy of ebml_w, which is bad as
             // it has mutable fields.  But I believe it's harmless since
             // we generate balanced EBML.
diff --git a/src/comp/metadata/astencode_gen.rs b/src/comp/metadata/astencode_gen.rs
index abbe7376e1b..1c413de261c 100644
--- a/src/comp/metadata/astencode_gen.rs
+++ b/src/comp/metadata/astencode_gen.rs
@@ -8748,12 +8748,84 @@ fn deserialize_syntax_ast_def_id<S: std::serialization::deserializer>(s: S) ->
    syntax::ast::def_id {
     deserialize_162(s)
 }
-fn serialize_syntax_ast_method<S: std::serialization::serializer>(s: S,
-                                                                  v:
-                                                                      syntax::ast::method) {
-    serialize_160(s, v);
+/*syntax::ast::inlined_item*/
+fn serialize_168<S: std::serialization::serializer>(s: S,
+                                                    v:
+                                                        syntax::ast::inlined_item) {
+    s.emit_enum("syntax::ast::inlined_item",
+                /*@syntax::ast::item*/
+                /*syntax::ast::def_id*//*@syntax::ast::method*/
+                {||
+                    alt v {
+                      syntax::ast::ii_item(v0) {
+                        s.emit_enum_variant("syntax::ast::ii_item", 0u, 1u,
+                                            {||
+                                                {
+                                                    s.emit_enum_variant_arg(0u,
+                                                                            {||
+                                                                                serialize_117(s,
+                                                                                              v0)
+                                                                            })
+                                                }
+                                            })
+                      }
+                      syntax::ast::ii_method(v0, v1) {
+                        s.emit_enum_variant("syntax::ast::ii_method", 1u, 2u,
+                                            {||
+                                                {
+                                                    s.emit_enum_variant_arg(0u,
+                                                                            {||
+                                                                                serialize_162(s,
+                                                                                              v0)
+                                                                            });
+                                                    s.emit_enum_variant_arg(1u,
+                                                                            {||
+                                                                                serialize_159(s,
+                                                                                              v1)
+                                                                            })
+                                                }
+                                            })
+                      }
+                    }
+                });
 }
-fn deserialize_syntax_ast_method<S: std::serialization::deserializer>(s: S) ->
-   syntax::ast::method {
-    deserialize_160(s)
+fn serialize_syntax_ast_inlined_item<S: std::serialization::serializer>(s: S,
+                                                                        v:
+                                                                            syntax::ast::inlined_item) {
+    serialize_168(s, v);
+}
+/*syntax::ast::inlined_item*/
+fn deserialize_168<S: std::serialization::deserializer>(s: S) ->
+   syntax::ast::inlined_item {
+    s.read_enum("syntax::ast::inlined_item",
+                /*@syntax::ast::item*/
+
+                /*syntax::ast::def_id*//*@syntax::ast::method*/
+                {||
+                    s.read_enum_variant({|v_id|
+                                            alt check v_id {
+                                              0u {
+                                                syntax::ast::ii_item(s.read_enum_variant_arg(0u,
+                                                                                             {||
+                                                                                                 deserialize_117(s)
+                                                                                             }))
+                                              }
+                                              1u {
+                                                syntax::ast::ii_method(s.read_enum_variant_arg(0u,
+                                                                                               {||
+                                                                                                   deserialize_162(s)
+                                                                                               }),
+                                                                       s.read_enum_variant_arg(1u,
+                                                                                               {||
+                                                                                                   deserialize_159(s)
+                                                                                               }))
+                                              }
+                                            }
+                                        })
+                })
+}
+fn deserialize_syntax_ast_inlined_item<S: std::serialization::deserializer>(s:
+                                                                                S)
+   -> syntax::ast::inlined_item {
+    deserialize_168(s)
 }
diff --git a/src/comp/metadata/csearch.rs b/src/comp/metadata/csearch.rs
index 646ba5ea751..7dbf8dde75a 100644
--- a/src/comp/metadata/csearch.rs
+++ b/src/comp/metadata/csearch.rs
@@ -79,7 +79,7 @@ fn get_item_path(tcx: ty::ctxt, def: ast::def_id) -> ast_map::path {
 // not marked for inlining, then the AST will not be present and hence none
 // will be returned.
 fn maybe_get_item_ast(tcx: ty::ctxt, maps: maps, def: ast::def_id)
-    -> option<@ast::item> {
+    -> option<ast::inlined_item> {
     let cstore = tcx.sess.cstore;
     let cdata = cstore::get_crate_data(cstore, def.crate);
     decoder::maybe_get_item_ast(cdata, tcx, maps, def.node)
diff --git a/src/comp/metadata/decoder.rs b/src/comp/metadata/decoder.rs
index 6b741189c48..196789ee58c 100644
--- a/src/comp/metadata/decoder.rs
+++ b/src/comp/metadata/decoder.rs
@@ -264,7 +264,7 @@ fn get_item_path(cdata: cmd, id: ast::node_id) -> ast_map::path {
 }
 
 fn maybe_get_item_ast(cdata: cmd, tcx: ty::ctxt, maps: maps,
-                      id: ast::node_id) -> option<@ast::item> {
+                      id: ast::node_id) -> option<ast::inlined_item> {
     let item_doc = lookup_item(id, cdata.data);
     let path = vec::init(item_path(item_doc));
     astencode::decode_inlined_item(cdata, tcx, maps, path, item_doc)
diff --git a/src/comp/metadata/encoder.rs b/src/comp/metadata/encoder.rs
index 705848b48ff..57507b8d8f9 100644
--- a/src/comp/metadata/encoder.rs
+++ b/src/comp/metadata/encoder.rs
@@ -352,7 +352,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
         encode_symbol(ecx, ebml_w, item.id);
         encode_path(ebml_w, path, ast_map::path_name(item.ident));
         if should_inline(path, item) {
-            astencode::encode_inlined_item(ecx, ebml_w, path, item);
+            astencode::encode_inlined_item(ecx, ebml_w, path, ii_item(item));
         }
         ebml_w.end_tag();
       }
diff --git a/src/comp/middle/ast_map.rs b/src/comp/middle/ast_map.rs
index b5944402bb2..673b3649191 100644
--- a/src/comp/middle/ast_map.rs
+++ b/src/comp/middle/ast_map.rs
@@ -1,6 +1,7 @@
 import std::map;
 import syntax::ast::*;
 import syntax::ast_util;
+import syntax::ast_util::inlined_item_methods;
 import syntax::{visit, codemap};
 
 enum path_elt { path_mod(str), path_name(str) }
@@ -23,7 +24,7 @@ fn path_to_str(p: path) -> str {
 enum ast_node {
     node_item(@item, @path),
     node_native_item(@native_item, @path),
-    node_method(@method, node_id, @path),
+    node_method(@method, def_id, @path),
     node_variant(variant, def_id, @path),
     node_expr(@expr),
     // Locals are numbered, because the alias analysis needs to know in which
@@ -59,7 +60,7 @@ fn map_crate(c: crate) -> map {
 
 // Used for items loaded from external crate that are being inlined into this
 // crate:
-fn map_decoded_item(map: map, path: path, i: @item) {
+fn map_decoded_item(map: map, path: path, ii: inlined_item) {
     // I believe it is ok for the local IDs of inlined items from other crates
     // to overlap with the local ids from this crate, so just generate the ids
     // starting from 0.  (In particular, I think these ids are only used in
@@ -70,16 +71,7 @@ fn map_decoded_item(map: map, path: path, i: @item) {
               mutable path: path,
               mutable local_id: 0u};
     let v = mk_ast_map_visitor();
-    v.visit_item(i, cx, v);
-}
-
-fn map_decoded_method(map: map, path: path, m: @method) {
-    // As above.
-    let cx = {map: map,
-              mutable path: path,
-              mutable local_id: 0u};
-    let v = mk_ast_map_visitor();
-    visit::visit_method_helper(m, cx, v);
+    ii.accept(cx, v);
 }
 
 fn map_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
@@ -117,7 +109,8 @@ fn map_item(i: @item, cx: ctx, v: vt) {
     cx.map.insert(i.id, node_item(i, @cx.path));
     alt i.node {
       item_impl(_, _, _, ms) {
-        for m in ms { cx.map.insert(m.id, node_method(m, i.id, @cx.path)); }
+        let implid = ast_util::local_def(i.id);
+        for m in ms { cx.map.insert(m.id, node_method(m, implid, @cx.path)); }
       }
       item_res(_, _, _, dtor_id, ctor_id) {
         cx.map.insert(ctor_id, node_res_ctor(i));
diff --git a/src/comp/middle/inline.rs b/src/comp/middle/inline.rs
index 9c05823f6ec..91d69168faf 100644
--- a/src/comp/middle/inline.rs
+++ b/src/comp/middle/inline.rs
@@ -1,6 +1,7 @@
 import std::map::hashmap;
 import syntax::ast;
 import syntax::ast_util;
+import syntax::ast_util::inlined_item_methods;
 import syntax::visit;
 import middle::typeck::method_map;
 import middle::trans::common::maps;
@@ -9,13 +10,13 @@ import metadata::csearch;
 export inline_map;
 export instantiate_inlines;
 
-type inline_map = hashmap<ast::def_id, @ast::item>;
+type inline_map = hashmap<ast::def_id, ast::inlined_item>;
 
 enum ctxt = {
     tcx: ty::ctxt,
     maps: maps,
     inline_map: inline_map,
-    mutable to_process: [@ast::item]
+    mut to_process: [ast::inlined_item]
 };
 
 fn instantiate_inlines(enabled: bool,
@@ -37,7 +38,9 @@ fn instantiate_inlines(enabled: bool,
         let to_process = [];
         to_process <-> cx.to_process;
         #debug["Recursively looking at inlined items"];
-        vec::iter(to_process, {|i| visit::visit_item(i, cx, vt)});
+        vec::iter(to_process) {|ii|
+            ii.accept(cx, vt);
+        }
     }
     ret inline_map;
 }
@@ -78,20 +81,20 @@ impl methods for ctxt {
             #debug["No AST attached to def %s",
                    ty::item_path_str(self.tcx, did)];
           }
-          some(item) { /* Found an AST, add to table: */
+          some(ii) { /* Found an AST, add to table: */
             #debug["Inlining def %s", ty::item_path_str(self.tcx, did)];
-            self.to_process += [item];
-            self.inline_map.insert(did, item);
+            self.to_process += [ii];
+            self.inline_map.insert(did, ii);
           }
         }
     }
 
-    fn maybe_enqueue_impl_method(_origin: typeck::method_origin) {
-        // alt method_origin {
-        //   method_static(did) { self.maybe_enqueue_fn(did); }
-        //   method_param(_, _, _, _) | method_iface(_, _) {
-        //     /* fallthrough */
-        //   }
-        // }
+    fn maybe_enqueue_impl_method(method_origin: typeck::method_origin) {
+        alt method_origin {
+          typeck::method_static(did) { self.maybe_enqueue_fn(did); }
+          typeck::method_param(_, _, _, _) | typeck::method_iface(_, _) {
+            /* fallthrough */
+          }
+        }
     }
 }
diff --git a/src/comp/middle/trans/base.rs b/src/comp/middle/trans/base.rs
index 479def401fb..846417fcb44 100644
--- a/src/comp/middle/trans/base.rs
+++ b/src/comp/middle/trans/base.rs
@@ -23,6 +23,7 @@ import front::attr;
 import middle::inline::inline_map;
 import back::{link, abi, upcall};
 import syntax::{ast, ast_util, codemap};
+import ast_util::inlined_item_methods;
 import ast_util::local_def;
 import syntax::visit;
 import syntax::codemap::span;
@@ -2105,8 +2106,8 @@ fn monomorphic_fn(ccx: crate_ctxt, fn_id: ast::def_id, substs: [ty::t],
         trans_enum_variant(ccx, enum_id.node, v, this_tv.disr_val,
                            (*tvs).len() == 1u, [], psubsts, lldecl);
       }
-      ast_map::node_method(mth, impl_id, _) {
-        let selfty = ty::node_id_to_type(ccx.tcx, impl_id);
+      ast_map::node_method(mth, impl_def_id, _) {
+        let selfty = ty::lookup_item_type(ccx.tcx, impl_def_id).ty;
         let selfty = ty::substitute_type_params(ccx.tcx, substs, selfty);
         trans_fn(ccx, pt, mth.decl, mth.body, lldecl,
                  impl_self(selfty), [], psubsts, fn_id.node);
@@ -2131,12 +2132,12 @@ fn lval_static_fn(bcx: block, fn_id: ast::def_id, id: ast::node_id,
         } else {
             alt ccx.inline_map.find(fn_id) {
               none { fn_id }
-              some(item) {
+              some(ii) {
                 #debug["Found inlined version of %s with id %d",
                        ty::item_path_str(tcx, fn_id),
-                       item.id];
+                       ii.id()];
                 {crate: ast::local_crate,
-                 node: item.id}
+                 node: ii.id()}
               }
             }
         }
@@ -3882,8 +3883,10 @@ fn new_fn_ctxt(ccx: crate_ctxt, path: path, llfndecl: ValueRef,
 // spaces that have been created for them (by code in the llallocas field of
 // the function's fn_ctxt).  create_llargs_for_fn_args populates the llargs
 // field of the fn_ctxt with
-fn create_llargs_for_fn_args(cx: fn_ctxt, ty_self: self_arg,
-                             args: [ast::arg], ty_params: [ast::ty_param]) {
+fn create_llargs_for_fn_args(cx: fn_ctxt,
+                             ty_self: self_arg,
+                             args: [ast::arg],
+                             tps_bounds: [ty::param_bounds]) {
     // Skip the implicit arguments 0, and 1.
     let arg_n = first_tp_arg;
     alt ty_self {
@@ -3892,11 +3895,11 @@ fn create_llargs_for_fn_args(cx: fn_ctxt, ty_self: self_arg,
       }
       no_self {}
     }
-    for tp in ty_params {
+    for bounds in tps_bounds {
         let lltydesc = llvm::LLVMGetParam(cx.llfn, arg_n as c_uint);
         let dicts = none;
         arg_n += 1u;
-        for bound in *cx.ccx.tcx.ty_param_bounds.get(tp.id) {
+        for bound in *bounds {
             alt bound {
               ty::bound_iface(_) {
                 let dict = llvm::LLVMGetParam(cx.llfn, arg_n as c_uint);
@@ -3983,7 +3986,8 @@ enum self_arg { impl_self(ty::t), no_self, }
 // returned.
 fn trans_closure(ccx: crate_ctxt, path: path, decl: ast::fn_decl,
                  body: ast::blk, llfndecl: ValueRef,
-                 ty_self: self_arg, ty_params: [ast::ty_param],
+                 ty_self: self_arg,
+                 tps_bounds: [ty::param_bounds],
                  param_substs: option<param_substs>,
                  id: ast::node_id, maybe_load_env: fn(fn_ctxt)) {
     set_uwtable(llfndecl);
@@ -3991,7 +3995,7 @@ fn trans_closure(ccx: crate_ctxt, path: path, decl: ast::fn_decl,
     // Set up arguments to the function.
     let fcx = new_fn_ctxt_w_id(ccx, path, llfndecl, id, param_substs,
                                some(body.span));
-    create_llargs_for_fn_args(fcx, ty_self, decl.inputs, ty_params);
+    create_llargs_for_fn_args(fcx, ty_self, decl.inputs, tps_bounds);
 
     // Create the first basic block in the function and keep a handle on it to
     //  pass to finish_fn later.
@@ -4023,15 +4027,20 @@ fn trans_closure(ccx: crate_ctxt, path: path, decl: ast::fn_decl,
 
 // trans_fn: creates an LLVM function corresponding to a source language
 // function.
-fn trans_fn(ccx: crate_ctxt, path: path, decl: ast::fn_decl,
-            body: ast::blk, llfndecl: ValueRef, ty_self: self_arg,
-            ty_params: [ast::ty_param], param_substs: option<param_substs>,
+fn trans_fn(ccx: crate_ctxt,
+            path: path,
+            decl: ast::fn_decl,
+            body: ast::blk,
+            llfndecl: ValueRef,
+            ty_self: self_arg,
+            tps_bounds: [ty::param_bounds],
+            param_substs: option<param_substs>,
             id: ast::node_id) {
     let do_time = ccx.sess.opts.stats;
     let start = if do_time { time::get_time() }
                 else { {sec: 0u32, usec: 0u32} };
     trans_closure(ccx, path, decl, body, llfndecl, ty_self,
-                  ty_params, param_substs, id, {|fcx|
+                  tps_bounds, param_substs, id, {|fcx|
         if ccx.sess.opts.extra_debuginfo {
             debuginfo::create_function(fcx);
         }
@@ -4043,12 +4052,12 @@ fn trans_fn(ccx: crate_ctxt, path: path, decl: ast::fn_decl,
 }
 
 fn trans_res_ctor(ccx: crate_ctxt, path: path, dtor: ast::fn_decl,
-                  ctor_id: ast::node_id, ty_params: [ast::ty_param],
+                  ctor_id: ast::node_id, tps_bounds: [ty::param_bounds],
                   param_substs: option<param_substs>, llfndecl: ValueRef) {
     // Create a function for the constructor
     let fcx = new_fn_ctxt_w_id(ccx, path, llfndecl, ctor_id,
                                param_substs, none);
-    create_llargs_for_fn_args(fcx, no_self, dtor.inputs, ty_params);
+    create_llargs_for_fn_args(fcx, no_self, dtor.inputs, tps_bounds);
     let bcx = top_scope_block(fcx, none), lltop = bcx.llbb;
     let fty = node_id_type(bcx, ctor_id);
     let arg_t = ty::ty_fn_args(fty)[0].ty;
@@ -4091,7 +4100,8 @@ fn trans_enum_variant(ccx: crate_ctxt, enum_id: ast::node_id,
     }
     let fcx = new_fn_ctxt_w_id(ccx, [], llfndecl, variant.node.id,
                                param_substs, none);
-    create_llargs_for_fn_args(fcx, no_self, fn_args, ty_params);
+    create_llargs_for_fn_args(fcx, no_self, fn_args,
+                              param_bounds(ccx, ty_params));
     let ty_param_substs = alt param_substs {
       some(substs) { substs.tys }
       none {
@@ -4248,7 +4258,8 @@ fn trans_item(ccx: crate_ctxt, item: ast::item) {
         };
         if decl.purity != ast::crust_fn  {
             trans_fn(ccx, *path + [path_name(item.ident)], decl, body,
-                     llfndecl, no_self, tps, none, item.id);
+                     llfndecl, no_self, param_bounds(ccx, tps),
+                     none, item.id);
         } else {
             native::trans_crust_fn(ccx, *path + [path_name(item.ident)],
                                    decl, body, llfndecl, item.id);
@@ -4259,13 +4270,15 @@ fn trans_item(ccx: crate_ctxt, item: ast::item) {
       }
       ast::item_res(decl, tps, body, dtor_id, ctor_id) {
         let llctor_decl = ccx.item_ids.get(ctor_id);
-        trans_res_ctor(ccx, *path, decl, ctor_id, tps, none, llctor_decl);
+        trans_res_ctor(ccx, *path, decl, ctor_id,
+                       param_bounds(ccx, tps), none, llctor_decl);
 
         // Create a function for the destructor
         alt ccx.item_ids.find(item.id) {
           some(lldtor_decl) {
             trans_fn(ccx, *path + [path_name(item.ident)], decl, body,
-                     lldtor_decl, no_self, tps, none, dtor_id);
+                     lldtor_decl, no_self, param_bounds(ccx, tps),
+                     none, dtor_id);
           }
           _ {
             ccx.sess.span_fatal(item.span, "unbound dtor in trans_item");
@@ -4309,9 +4322,34 @@ fn trans_mod(ccx: crate_ctxt, m: ast::_mod) {
     for item in m.items { trans_item(ccx, *item); }
 }
 
+fn compute_ii_method_info(ccx: crate_ctxt,
+                          impl_did: ast::def_id,
+                          m: @ast::method,
+                          f: fn(ty::t, [ty::param_bounds], ast_map::path)) {
+    let {bounds: impl_bnds, ty: impl_ty} =
+        ty::lookup_item_type(ccx.tcx, impl_did);
+    let m_bounds = *impl_bnds + param_bounds(ccx, m.tps);
+    let impl_path = ty::item_path(ccx.tcx, impl_did);
+    let m_path = impl_path + [path_name(m.ident)];
+    f(impl_ty, m_bounds, m_path);
+}
+
 fn trans_inlined_items(ccx: crate_ctxt, inline_map: inline_map) {
-    inline_map.values {|item|
-        trans_item(ccx, *item)
+    inline_map.values {|ii|
+        alt ii {
+          ast::ii_item(item) {
+            trans_item(ccx, *item)
+          }
+          ast::ii_method(impl_did, m) {
+            compute_ii_method_info(ccx, impl_did, m) {
+                |impl_ty, m_bounds, m_path|
+                let llfndecl = ccx.item_ids.get(m.id);
+                trans_fn(ccx, m_path, m.decl, m.body,
+                         llfndecl, impl_self(impl_ty), m_bounds,
+                         none, m.id);
+            }
+          }
+        }
     }
 }
 
@@ -4323,18 +4361,18 @@ fn get_pair_fn_ty(llpairty: TypeRef) -> TypeRef {
 fn register_fn(ccx: crate_ctxt, sp: span, path: path, flav: str,
                ty_params: [ast::ty_param], node_id: ast::node_id) {
     let t = ty::node_id_to_type(ccx.tcx, node_id);
-    register_fn_full(ccx, sp, path, flav, ty_params, node_id, t);
+    let bnds = param_bounds(ccx, ty_params);
+    register_fn_full(ccx, sp, path, flav, bnds, node_id, t);
 }
 
-fn param_bounds(ccx: crate_ctxt, tp: ast::ty_param) -> ty::param_bounds {
-    ccx.tcx.ty_param_bounds.get(tp.id)
+fn param_bounds(ccx: crate_ctxt, tps: [ast::ty_param]) -> [ty::param_bounds] {
+    vec::map(tps) {|tp| ccx.tcx.ty_param_bounds.get(tp.id) }
 }
 
 fn register_fn_full(ccx: crate_ctxt, sp: span, path: path, flav: str,
-                    tps: [ast::ty_param], node_id: ast::node_id,
+                    bnds: [ty::param_bounds], node_id: ast::node_id,
                     node_type: ty::t) {
-    let llfty = type_of_fn_from_ty(ccx, node_type,
-                                   vec::map(tps, {|p| param_bounds(ccx, p)}));
+    let llfty = type_of_fn_from_ty(ccx, node_type, bnds);
     register_fn_fuller(ccx, sp, path, flav, node_id, node_type,
                        lib::llvm::CCallConv, llfty);
 }
@@ -4480,8 +4518,7 @@ fn collect_native_item(ccx: crate_ctxt,
             // For intrinsics: link the function directly to the intrinsic
             // function itself.
             let fn_type = type_of_fn_from_ty(
-                ccx, node_type,
-                vec::map(tps, {|p| param_bounds(ccx, p)}));
+                ccx, node_type, param_bounds(ccx, tps));
             let ri_name = "rust_intrinsic_" + native::link_name(i);
             let llnativefn = get_extern_fn(
                 ccx.externs, ccx.llmod, ri_name,
@@ -4555,7 +4592,7 @@ fn collect_item(ccx: crate_ctxt, abi: @mutable option<ast::native_abi>,
         // -- one to identify the type, and one to find the dtor symbol.
         let t = ty::node_id_to_type(ccx.tcx, dtor_id);
         register_fn_full(ccx, i.span, my_path + [path_name("dtor")],
-                         "res_dtor", tps, i.id, t);
+                         "res_dtor", param_bounds(ccx, tps), i.id, t);
       }
       ast::item_enum(variants, tps) {
         for variant in variants {
@@ -4581,14 +4618,26 @@ fn collect_items(ccx: crate_ctxt, crate: @ast::crate) {
 
 fn collect_inlined_items(ccx: crate_ctxt, inline_map: inline::inline_map) {
     let abi = @mutable none::<ast::native_abi>;
-    inline_map.values {|item|
-        collect_item(ccx, abi, item);
+    inline_map.values {|ii|
+        alt ii {
+          ast::ii_item(item) {
+            collect_item(ccx, abi, item);
+            alt item.node {
+              ast::item_fn(_, _, _) {
+                set_always_inline(ccx.item_ids.get(item.id));
+              }
+              _ { /* fallthrough */ }
+            }
+          }
 
-        alt item.node {
-          ast::item_fn(_, _, _) {
-            set_always_inline(ccx.item_ids.get(item.id));
+          ast::ii_method(impl_did, m) {
+            compute_ii_method_info(ccx, impl_did, m) {
+                |_impl_ty, m_bounds, m_path|
+                let mthd_ty = ty::node_id_to_type(ccx.tcx, m.id);
+                register_fn_full(ccx, m.span, m_path, "impl_method",
+                                 m_bounds, m.id, mthd_ty);
+            }
           }
-          _ { /* fallthrough */ }
         }
     }
 }
diff --git a/src/comp/middle/trans/impl.rs b/src/comp/middle/trans/impl.rs
index 9dfd72cc59b..b3660e3f672 100644
--- a/src/comp/middle/trans/impl.rs
+++ b/src/comp/middle/trans/impl.rs
@@ -49,9 +49,10 @@ fn trans_impl(ccx: crate_ctxt, path: path, name: ast::ident,
     for m in methods {
         alt ccx.item_ids.find(m.id) {
           some(llfn) {
+            let m_bounds = param_bounds(ccx, tps + m.tps);
             trans_fn(ccx, sub_path + [path_name(m.ident)], m.decl, m.body,
                      llfn, impl_self(ty::node_id_to_type(ccx.tcx, id)),
-                     tps + m.tps, none, m.id);
+                     m_bounds, none, m.id);
           }
           _ {
             ccx.sess.bug("Unbound id in trans_impl");
@@ -337,13 +338,13 @@ fn trans_impl_vtable(ccx: crate_ctxt, pt: path,
                      tps: [ast::ty_param], it: @ast::item) {
     let new_pt = pt + [path_name(it.ident), path_name(int::str(it.id)),
                        path_name("wrap")];
-    let extra_tps = vec::map(tps, {|p| param_bounds(ccx, p)});
+    let extra_tps = param_bounds(ccx, tps);
     let ptrs = vec::map(*ty::iface_methods(ccx.tcx, iface_id), {|im|
         alt vec::find(ms, {|m| m.ident == im.ident}) {
           some(m) {
             let target = ccx.item_ids.get(m.id);
-            trans_impl_wrapper(ccx, new_pt + [path_name(m.ident)], extra_tps,
-                               target)
+            trans_impl_wrapper(ccx, new_pt + [path_name(m.ident)],
+                               extra_tps, target)
           }
           _ {
             ccx.sess.span_bug(it.span, "No matching method \
diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs
index edc5ade4062..eea47191eef 100644
--- a/src/comp/syntax/ast.rs
+++ b/src/comp/syntax/ast.rs
@@ -534,6 +534,14 @@ enum native_item_ {
     native_item_fn(fn_decl, [ty_param]),
 }
 
+// The data we save and restore about an inlined item or method.  This is not
+// part of the AST that we parse from a file, but it becomes part of the tree
+// that we trans.
+enum inlined_item {
+    ii_item(@item),
+    ii_method(def_id /* impl id */, @method)
+}
+
 //
 // Local Variables:
 // mode: rust
diff --git a/src/comp/syntax/ast_util.rs b/src/comp/syntax/ast_util.rs
index 5f303b8c4a8..04bd4236c9b 100644
--- a/src/comp/syntax/ast_util.rs
+++ b/src/comp/syntax/ast_util.rs
@@ -411,6 +411,29 @@ pure fn class_item_ident(ci: @class_item) -> ident {
     }
 }
 
+impl inlined_item_methods for inlined_item {
+    fn ident() -> ident {
+        alt self {
+          ii_item(i) { i.ident }
+          ii_method(_, m) { m.ident }
+        }
+    }
+
+    fn id() -> ast::node_id {
+        alt self {
+          ii_item(i) { i.id }
+          ii_method(_, m) { m.id }
+        }
+    }
+
+    fn accept<E>(e: E, v: visit::vt<E>) {
+        alt self {
+          ii_item(i) { v.visit_item(i, e, v) }
+          ii_method(_, m) { visit::visit_method_helper(m, e, v) }
+        }
+    }
+}
+
 // Local Variables:
 // mode: rust
 // fill-column: 78;
diff --git a/src/comp/syntax/fold.rs b/src/comp/syntax/fold.rs
index 94a0ff6b879..7ceae548769 100644
--- a/src/comp/syntax/fold.rs
+++ b/src/comp/syntax/fold.rs
@@ -750,7 +750,6 @@ fn make_fold(afp: ast_fold_precursor) -> ast_fold {
     ret result;
 }
 
-
 //
 // Local Variables:
 // mode: rust