about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-06-14 22:47:55 +0000
committerbors <bors@rust-lang.org>2015-06-14 22:47:55 +0000
commit4f3c19f547d62c3c2824979ea453a6558d6c873e (patch)
treeea603605134d307557bc7665cd20cb940d1aa225 /src
parentb26eeffacb80c122e0559ada5584fdce7183561b (diff)
parent718268398e312b02775e946af31d77fe35fb5550 (diff)
downloadrust-4f3c19f547d62c3c2824979ea453a6558d6c873e.tar.gz
rust-4f3c19f547d62c3c2824979ea453a6558d6c873e.zip
Auto merge of #26110 - nrc:save-api-3, r=brson
r? @huonw 
Diffstat (limited to 'src')
-rw-r--r--src/librustc_trans/save/dump_csv.rs353
-rw-r--r--src/librustc_trans/save/mod.rs183
-rw-r--r--src/librustc_trans/save/recorder.rs4
3 files changed, 332 insertions, 208 deletions
diff --git a/src/librustc_trans/save/dump_csv.rs b/src/librustc_trans/save/dump_csv.rs
index 36901ff0967..cbc40af4b52 100644
--- a/src/librustc_trans/save/dump_csv.rs
+++ b/src/librustc_trans/save/dump_csv.rs
@@ -54,6 +54,15 @@ use super::recorder::{Recorder, FmtStrs};
 
 use util::ppaux;
 
+macro_rules! down_cast_data {
+    ($id:ident, $kind:ident, $this:ident, $sp:expr) => {
+        let $id = if let super::Data::$kind(data) = $id {
+            data
+        } else {
+            $this.sess.span_bug($sp, &format!("unexpected data kind: {:?}", $id));
+        };
+    };
+}
 
 pub struct DumpCsvVisitor<'l, 'tcx: 'l> {
     save_ctxt: SaveContext<'l, 'tcx>,
@@ -249,7 +258,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
         match def {
             def::DefMod(_) |
             def::DefForeignMod(_) => Some(recorder::ModRef),
-            def::DefStruct(_) => Some(recorder::StructRef),
+            def::DefStruct(_) => Some(recorder::TypeRef),
             def::DefTy(..) |
             def::DefAssociatedTy(..) |
             def::DefTrait(_) => Some(recorder::TypeRef),
@@ -419,48 +428,31 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
                                     id);
     }
 
-    fn process_trait_ref(&mut self,
-                         trait_ref: &ast::TraitRef) {
-        match self.lookup_type_ref(trait_ref.ref_id) {
-            Some(id) => {
-                let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span);
-                self.fmt.ref_str(recorder::TypeRef,
-                                 trait_ref.path.span,
-                                 sub_span,
-                                 id,
-                                 self.cur_scope);
-                visit::walk_path(self, &trait_ref.path);
-            },
-            None => ()
+    fn process_trait_ref(&mut self, trait_ref: &ast::TraitRef) {
+        let trait_ref_data = self.save_ctxt.get_trait_ref_data(trait_ref, self.cur_scope);
+        if let Some(trait_ref_data) = trait_ref_data {
+            self.fmt.ref_str(recorder::TypeRef,
+                             trait_ref.path.span,
+                             Some(trait_ref_data.span),
+                             trait_ref_data.ref_id,
+                             trait_ref_data.scope);
+            visit::walk_path(self, &trait_ref.path);
         }
     }
 
     fn process_struct_field_def(&mut self,
                                 field: &ast::StructField,
-                                qualname: &str,
-                                scope_id: NodeId) {
-        match field.node.kind {
-            ast::NamedField(ident, _) => {
-                let name = get_ident(ident);
-                let qualname = format!("{}::{}", qualname, name);
-                let typ =
-                    ppaux::ty_to_string(
-                        &self.analysis.ty_cx,
-                        *self.analysis.ty_cx.node_types().get(&field.node.id).unwrap());
-                match self.span.sub_span_before_token(field.span, token::Colon) {
-                    Some(sub_span) => self.fmt.field_str(field.span,
-                                                         Some(sub_span),
-                                                         field.node.id,
-                                                         &name,
-                                                         &qualname,
-                                                         &typ,
-                                                         scope_id),
-                    None => self.sess.span_bug(field.span,
-                                               &format!("Could not find sub-span for field {}",
-                                                       qualname)),
-                }
-            },
-            _ => (),
+                                parent_id: NodeId) {
+        let field_data = self.save_ctxt.get_field_data(field, parent_id);
+        if let Some(field_data) = field_data {
+            down_cast_data!(field_data, VariableData, self, field.span);
+            self.fmt.field_str(field.span,
+                               Some(field_data.span),
+                               field_data.id,
+                               &field_data.name,
+                               &field_data.qualname,
+                               &field_data.type_value,
+                               field_data.scope);
         }
     }
 
@@ -497,19 +489,16 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
                   ty_params: &ast::Generics,
                   body: &ast::Block) {
         let fn_data = self.save_ctxt.get_item_data(item);
-        if let super::Data::FunctionData(fn_data) = fn_data {
-            self.fmt.fn_str(item.span,
-                            Some(fn_data.span),
-                            fn_data.id,
-                            &fn_data.qualname,
-                            fn_data.scope);
+        down_cast_data!(fn_data, FunctionData, self, item.span);
+        self.fmt.fn_str(item.span,
+                        Some(fn_data.span),
+                        fn_data.id,
+                        &fn_data.qualname,
+                        fn_data.scope);
 
 
-            self.process_formals(&decl.inputs, &fn_data.qualname);
-            self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id);
-        } else {
-            self.sess.span_bug(item.span, "expected FunctionData");
-        }
+        self.process_formals(&decl.inputs, &fn_data.qualname);
+        self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id);
 
         for arg in &decl.inputs {
             self.visit_ty(&arg.ty);
@@ -528,18 +517,15 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
                                     expr: &ast::Expr)
     {
         let var_data = self.save_ctxt.get_item_data(item);
-        if let super::Data::VariableData(var_data) = var_data {
-            self.fmt.static_str(item.span,
-                                Some(var_data.span),
-                                var_data.id,
-                                &var_data.name,
-                                &var_data.qualname,
-                                &var_data.value,
-                                &var_data.type_value,
-                                var_data.scope);
-        } else {
-            self.sess.span_bug(item.span, "expected VariableData");
-        }
+        down_cast_data!(var_data, VariableData, self, item.span);
+        self.fmt.static_str(item.span,
+                            Some(var_data.span),
+                            var_data.id,
+                            &var_data.name,
+                            &var_data.qualname,
+                            &var_data.value,
+                            &var_data.type_value,
+                            var_data.scope);
 
         self.visit_ty(&typ);
         self.visit_expr(expr);
@@ -593,8 +579,8 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
 
         // fields
         for field in &def.fields {
-            self.process_struct_field_def(field, &qualname, item.id);
-            self.visit_ty(&*field.node.ty);
+            self.process_struct_field_def(field, item.id);
+            self.visit_ty(&field.node.ty);
         }
 
         self.process_generic_params(ty_params, item.span, &qualname, item.id);
@@ -605,59 +591,57 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
                     enum_definition: &ast::EnumDef,
                     ty_params: &ast::Generics) {
         let enum_data = self.save_ctxt.get_item_data(item);
-        if let super::Data::EnumData(enum_data) = enum_data {
-            self.fmt.enum_str(item.span,
-                              Some(enum_data.span),
-                              enum_data.id,
-                              &enum_data.qualname,
-                              self.cur_scope,
-                              &enum_data.value);
-            for variant in &enum_definition.variants {
-                let name = &get_ident(variant.node.name);
-                let mut qualname = enum_data.qualname.clone();
-                qualname.push_str("::");
-                qualname.push_str(name);
-                let val = self.span.snippet(variant.span);
-                match variant.node.kind {
-                    ast::TupleVariantKind(ref args) => {
-                        // first ident in span is the variant's name
-                        self.fmt.tuple_variant_str(variant.span,
-                                                   self.span.span_for_first_ident(variant.span),
-                                                   variant.node.id,
-                                                   name,
-                                                   &qualname,
-                                                   &enum_data.qualname,
-                                                   &val,
-                                                   item.id);
-                        for arg in args {
-                            self.visit_ty(&*arg.ty);
-                        }
+        down_cast_data!(enum_data, EnumData, self, item.span);
+        self.fmt.enum_str(item.span,
+                          Some(enum_data.span),
+                          enum_data.id,
+                          &enum_data.qualname,
+                          enum_data.scope,
+                          &enum_data.value);
+
+        for variant in &enum_definition.variants {
+            let name = &get_ident(variant.node.name);
+            let mut qualname = enum_data.qualname.clone();
+            qualname.push_str("::");
+            qualname.push_str(name);
+            let val = self.span.snippet(variant.span);
+            match variant.node.kind {
+                ast::TupleVariantKind(ref args) => {
+                    // first ident in span is the variant's name
+                    self.fmt.tuple_variant_str(variant.span,
+                                               self.span.span_for_first_ident(variant.span),
+                                               variant.node.id,
+                                               name,
+                                               &qualname,
+                                               &enum_data.qualname,
+                                               &val,
+                                               enum_data.id);
+                    for arg in args {
+                        self.visit_ty(&*arg.ty);
                     }
-                    ast::StructVariantKind(ref struct_def) => {
-                        let ctor_id = match struct_def.ctor_id {
-                            Some(node_id) => node_id,
-                            None => -1,
-                        };
-                        self.fmt.struct_variant_str(variant.span,
-                                                    self.span.span_for_first_ident(variant.span),
-                                                    variant.node.id,
-                                                    ctor_id,
-                                                    &qualname,
-                                                    &enum_data.qualname,
-                                                    &val,
-                                                    item.id);
-
-                        for field in &struct_def.fields {
-                            self.process_struct_field_def(field, &qualname, variant.node.id);
-                            self.visit_ty(&*field.node.ty);
-                        }
+                }
+                ast::StructVariantKind(ref struct_def) => {
+                    let ctor_id = match struct_def.ctor_id {
+                        Some(node_id) => node_id,
+                        None => -1,
+                    };
+                    self.fmt.struct_variant_str(variant.span,
+                                                self.span.span_for_first_ident(variant.span),
+                                                variant.node.id,
+                                                ctor_id,
+                                                &qualname,
+                                                &enum_data.qualname,
+                                                &val,
+                                                enum_data.id);
+
+                    for field in &struct_def.fields {
+                        self.process_struct_field_def(field, variant.node.id);
+                        self.visit_ty(&*field.node.ty);
                     }
                 }
             }
-            self.process_generic_params(ty_params, item.span, &enum_data.qualname, item.id);
-        } else {
-            self.sess.span_bug(item.span, "expected EnumData");
         }
+        self.process_generic_params(ty_params, item.span, &enum_data.qualname, enum_data.id);
     }
 
     fn process_impl(&mut self,
@@ -666,45 +650,36 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
                     trait_ref: &Option<ast::TraitRef>,
                     typ: &ast::Ty,
                     impl_items: &[P<ast::ImplItem>]) {
-        let trait_id = trait_ref.as_ref().and_then(|tr| self.lookup_type_ref(tr.ref_id));
-        match typ.node {
-            // Common case impl for a struct or something basic.
-            ast::TyPath(None, ref path) => {
-                let sub_span = self.span.sub_span_for_type_name(path.span);
-                let self_id = self.lookup_type_ref(typ.id).map(|id| {
-                    self.fmt.ref_str(recorder::TypeRef,
-                                     path.span,
-                                     sub_span,
-                                     id,
-                                     self.cur_scope);
-                    id
-                });
-                self.fmt.impl_str(path.span,
-                                  sub_span,
-                                  item.id,
-                                  self_id,
-                                  trait_id,
-                                  self.cur_scope);
-            },
-            _ => {
-                // Less useful case, impl for a compound type.
-                self.visit_ty(&*typ);
-
-                let sub_span = self.span.sub_span_for_type_name(typ.span);
-                self.fmt.impl_str(typ.span,
-                                  sub_span,
-                                  item.id,
-                                  None,
-                                  trait_id,
-                                  self.cur_scope);
+        let impl_data = self.save_ctxt.get_item_data(item);
+        down_cast_data!(impl_data, ImplData, self, item.span);
+        match impl_data.self_ref {
+            Some(ref self_ref) => {
+                self.fmt.ref_str(recorder::TypeRef,
+                                 item.span,
+                                 Some(self_ref.span),
+                                 self_ref.ref_id,
+                                 self_ref.scope);
+            }
+            None => {
+                self.visit_ty(&typ);
             }
         }
-
-        match *trait_ref {
-            Some(ref trait_ref) => self.process_trait_ref(trait_ref),
-            None => (),
+        if let Some(ref trait_ref_data) = impl_data.trait_ref {
+            self.fmt.ref_str(recorder::TypeRef,
+                             item.span,
+                             Some(trait_ref_data.span),
+                             trait_ref_data.ref_id,
+                             trait_ref_data.scope);
+            visit::walk_path(self, &trait_ref.as_ref().unwrap().path);
         }
 
+        self.fmt.impl_str(item.span,
+                          Some(impl_data.span),
+                          impl_data.id,
+                          impl_data.self_ref.map(|data| data.ref_id),
+                          impl_data.trait_ref.map(|data| data.ref_id),
+                          impl_data.scope);
+
         self.process_generic_params(type_parameters, item.span, "", item.id);
         for impl_item in impl_items {
             self.visit_impl_item(impl_item);
@@ -765,16 +740,13 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
     fn process_mod(&mut self,
                    item: &ast::Item) {  // The module in question, represented as an item.
         let mod_data = self.save_ctxt.get_item_data(item);
-        if let super::Data::ModData(mod_data) = mod_data {
-            self.fmt.mod_str(item.span,
-                             Some(mod_data.span),
-                             mod_data.id,
-                             &mod_data.qualname,
-                             mod_data.scope,
-                             &mod_data.filename);
-        } else {
-            self.sess.span_bug(item.span, "expected ModData");
-        }
+        down_cast_data!(mod_data, ModData, self, item.span);
+        self.fmt.mod_str(item.span,
+                         Some(mod_data.span),
+                         mod_data.id,
+                         &mod_data.qualname,
+                         mod_data.scope,
+                         &mod_data.filename);
     }
 
     fn process_path(&mut self,
@@ -804,7 +776,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
                                                     sub_span,
                                                     def.def_id(),
                                                     self.cur_scope),
-            def::DefStruct(def_id) => self.fmt.ref_str(recorder::StructRef,
+            def::DefStruct(def_id) => self.fmt.ref_str(recorder::TypeRef,
                                                        span,
                                                        sub_span,
                                                        def_id,
@@ -901,44 +873,33 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
 
         self.write_sub_paths_truncated(path, false);
 
-        let ty = &ty::expr_ty_adjusted(&self.analysis.ty_cx, ex).sty;
-        let struct_def = match *ty {
-            ty::TyStruct(def_id, _) => {
-                let sub_span = self.span.span_for_last_ident(path.span);
-                self.fmt.ref_str(recorder::StructRef,
-                                 path.span,
-                                 sub_span,
-                                 def_id,
-                                 self.cur_scope);
-                Some(def_id)
-            }
-            _ => None
-        };
-
-        for field in fields {
-            match struct_def {
-                Some(struct_def) => {
-                    let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, struct_def);
-                    for f in &fields {
-                        if generated_code(field.ident.span) {
-                            continue;
-                        }
-                        if f.name == field.ident.node.name {
-                            // We don't really need a sub-span here, but no harm done
-                            let sub_span = self.span.span_for_last_ident(field.ident.span);
-                            self.fmt.ref_str(recorder::VarRef,
-                                             field.ident.span,
-                                             sub_span,
-                                             f.id,
-                                             self.cur_scope);
-                        }
-                    }
+        if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) {
+            down_cast_data!(struct_lit_data, TypeRefData, self, ex.span);
+            self.fmt.ref_str(recorder::TypeRef,
+                             ex.span,
+                             Some(struct_lit_data.span),
+                             struct_lit_data.ref_id,
+                             struct_lit_data.scope);
+            let struct_def = struct_lit_data.ref_id;
+
+            for field in fields {
+                if generated_code(field.ident.span) {
+                    continue;
                 }
-                None => {}
-            }
 
-            self.visit_expr(&*field.expr)
+                let field_data = self.save_ctxt.get_field_ref_data(field,
+                                                                   struct_def,
+                                                                   self.cur_scope);
+                self.fmt.ref_str(recorder::VarRef,
+                                 field.ident.span,
+                                 Some(field_data.span),
+                                 field_data.ref_id,
+                                 field_data.scope);
+
+                self.visit_expr(&field.expr)
+            }
         }
+
         visit::walk_expr_opt(self, base)
     }
 
@@ -1174,7 +1135,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> {
                 self.process_impl(item,
                                   ty_params,
                                   trait_ref,
-                                  &**typ,
+                                  &typ,
                                   impl_items)
             }
             ast::ItemTrait(_, ref generics, ref trait_refs, ref methods) =>
@@ -1296,15 +1257,13 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> {
 
                 self.visit_expr(&sub_ex);
 
-                let field_data = self.save_ctxt.get_expr_data(ex);
-                if let super::Data::VariableRefData(field_data) = field_data {
+                if let Some(field_data) = self.save_ctxt.get_expr_data(ex) {
+                    down_cast_data!(field_data, VariableRefData, self, ex.span);
                     self.fmt.ref_str(recorder::VarRef,
                                      ex.span,
                                      Some(field_data.span),
                                      field_data.ref_id,
                                      field_data.scope);
-                } else {
-                    self.sess.span_bug(ex.span, "expected VariableRefData");
                 }
             },
             ast::ExprTupField(ref sub_ex, idx) => {
diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs
index 096ee7ad7b3..380d6b0ee65 100644
--- a/src/librustc_trans/save/mod.rs
+++ b/src/librustc_trans/save/mod.rs
@@ -10,6 +10,7 @@
 
 use session::Session;
 use middle::ty;
+use middle::def;
 
 use std::env;
 use std::fs::{self, File};
@@ -23,9 +24,11 @@ use syntax::parse::token::{self, get_ident, keywords};
 use syntax::visit::{self, Visitor};
 use syntax::print::pprust::ty_to_string;
 
+use util::ppaux;
 
 use self::span_utils::SpanUtils;
 
+
 mod span_utils;
 mod recorder;
 
@@ -44,22 +47,28 @@ pub struct CrateData {
 
 /// Data for any entity in the Rust language. The actual data contained varied
 /// with the kind of entity being queried. See the nested structs for details.
+#[derive(Debug)]
 pub enum Data {
     /// Data for all kinds of functions and methods.
     FunctionData(FunctionData),
-    /// Data for local and global variables (consts and statics).
+    /// Data for local and global variables (consts and statics), and fields.
     VariableData(VariableData),
     /// Data for modules.
     ModData(ModData),
     /// Data for Enums.
     EnumData(EnumData),
+    /// Data for impls.
+    ImplData(ImplData),
 
     /// Data for the use of some variable (e.g., the use of a local variable, which
     /// will refere to that variables declaration).
     VariableRefData(VariableRefData),
+    /// Data for a reference to a type or trait.
+    TypeRefData(TypeRefData),
 }
 
 /// Data for all kinds of functions and methods.
+#[derive(Debug)]
 pub struct FunctionData {
     pub id: NodeId,
     pub name: String,
@@ -70,6 +79,7 @@ pub struct FunctionData {
 }
 
 /// Data for local and global variables (consts and statics).
+#[derive(Debug)]
 pub struct VariableData {
     pub id: NodeId,
     pub name: String,
@@ -81,6 +91,7 @@ pub struct VariableData {
 }
 
 /// Data for modules.
+#[derive(Debug)]
 pub struct ModData {
     pub id: NodeId,
     pub name: String,
@@ -91,15 +102,30 @@ pub struct ModData {
 }
 
 /// Data for enum declarations.
+#[derive(Debug)]
 pub struct EnumData {
     pub id: NodeId,
     pub value: String,
     pub qualname: String,
     pub span: Span,
+    pub scope: NodeId,
+}
+
+#[derive(Debug)]
+pub struct ImplData {
+    pub id: NodeId,
+    pub span: Span,
+    pub scope: NodeId,
+    // FIXME: I'm not really sure inline data is the best way to do this. Seems
+    // OK in this case, but generalising leads to returning chunks of AST, which
+    // feels wrong.
+    pub trait_ref: Option<TypeRefData>,
+    pub self_ref: Option<TypeRefData>,
 }
 
 /// Data for the use of some item (e.g., the use of a local variable, which
 /// will refere to that variables declaration (by ref_id)).
+#[derive(Debug)]
 pub struct VariableRefData {
     pub name: String,
     pub span: Span,
@@ -107,6 +133,14 @@ pub struct VariableRefData {
     pub ref_id: DefId,
 }
 
+/// Data for a reference to a type or trait.
+#[derive(Debug)]
+pub struct TypeRefData {
+    pub span: Span,
+    pub scope: NodeId,
+    pub ref_id: DefId,
+}
+
 
 impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
     pub fn new(sess: &'l Session,
@@ -209,8 +243,42 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     value: val,
                     span: sub_span.unwrap(),
                     qualname: enum_name,
+                    scope: self.analysis.ty_cx.map.get_parent(item.id),
                 })
             },
+            ast::ItemImpl(_, _, _, ref trait_ref, ref typ, _) => {
+                let mut type_data = None;
+                let sub_span;
+
+                let parent = self.analysis.ty_cx.map.get_parent(item.id);
+
+                match typ.node {
+                    // Common case impl for a struct or something basic.
+                    ast::TyPath(None, ref path) => {
+                        sub_span = self.span_utils.sub_span_for_type_name(path.span);
+                        type_data = self.lookup_ref_id(typ.id).map(|id| TypeRefData {
+                            span: sub_span.unwrap(),
+                            scope: parent,
+                            ref_id: id,
+                        });
+                    },
+                    _ => {
+                        // Less useful case, impl for a compound type.
+                        sub_span = self.span_utils.sub_span_for_type_name(typ.span);
+                    }
+                }
+
+                let trait_data =
+                    trait_ref.as_ref().and_then(|tr| self.get_trait_ref_data(tr, parent));
+
+                Data::ImplData(ImplData {
+                    id: item.id,
+                    span: sub_span.unwrap(),
+                    scope: parent,
+                    trait_ref: trait_data,
+                    self_ref: type_data,
+                })
+            }
             _ => {
                 // FIXME
                 unimplemented!();
@@ -218,7 +286,50 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
         }
     }
 
-    pub fn get_expr_data(&self, expr: &ast::Expr) -> Data {
+    // FIXME: we ought to be able to get the parent id ourselves, but we can't
+    // for now.
+    pub fn get_field_data(&self, field: &ast::StructField, parent: NodeId) -> Option<Data> {
+        match field.node.kind {
+            ast::NamedField(ident, _) => {
+                let name = get_ident(ident);
+                let qualname = format!("::{}::{}",
+                                       self.analysis.ty_cx.map.path_to_string(parent),
+                                       name);
+                let typ = ppaux::ty_to_string(&self.analysis.ty_cx,
+                                              *self.analysis.ty_cx.node_types()
+                                                  .get(&field.node.id).unwrap());
+                let sub_span = self.span_utils.sub_span_before_token(field.span, token::Colon);
+                Some(Data::VariableData(VariableData {
+                    id: field.node.id,
+                    name: get_ident(ident).to_string(),
+                    qualname: qualname,
+                    span: sub_span.unwrap(),
+                    scope: parent,
+                    value: "".to_owned(),
+                    type_value: typ,
+                }))
+            },
+            _ => None,
+        }
+    }
+
+    // FIXME: we ought to be able to get the parent id ourselves, but we can't
+    // for now.
+    pub fn get_trait_ref_data(&self,
+                              trait_ref: &ast::TraitRef,
+                              parent: NodeId)
+                              -> Option<TypeRefData> {
+        self.lookup_ref_id(trait_ref.ref_id).map(|def_id| {
+            let sub_span = self.span_utils.sub_span_for_type_name(trait_ref.path.span);
+            TypeRefData {
+                span: sub_span.unwrap(),
+                scope: parent,
+                ref_id: def_id,
+            }
+        })
+    }
+
+    pub fn get_expr_data(&self, expr: &ast::Expr) -> Option<Data> {
         match expr.node {
             ast::ExprField(ref sub_ex, ident) => {
                 let ty = &ty::expr_ty_adjusted(&self.analysis.ty_cx, &sub_ex).sty;
@@ -228,12 +339,12 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                         for f in &fields {
                             if f.name == ident.node.name {
                                 let sub_span = self.span_utils.span_for_last_ident(expr.span);
-                                return Data::VariableRefData(VariableRefData {
+                                return Some(Data::VariableRefData(VariableRefData {
                                     name: get_ident(ident.node).to_string(),
                                     span: sub_span.unwrap(),
                                     scope: self.analysis.ty_cx.map.get_parent(expr.id),
                                     ref_id: f.id,
-                                });
+                                }));
                             }
                         }
 
@@ -242,8 +353,29 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                                                     &get_ident(ident.node),
                                                     ty))
                     }
-                    _ => self.sess.span_bug(expr.span,
-                                            &format!("Expected struct type, found {:?}", ty)),
+                    _ => {
+                        debug!("Expected struct type, found {:?}", ty);
+                        None
+                    }
+                }
+            }
+            ast::ExprStruct(ref path, _, _) => {
+                let ty = &ty::expr_ty_adjusted(&self.analysis.ty_cx, expr).sty;
+                match *ty {
+                    ty::TyStruct(def_id, _) => {
+                        let sub_span = self.span_utils.span_for_last_ident(path.span);
+                        Some(Data::TypeRefData(TypeRefData {
+                            span: sub_span.unwrap(),
+                            scope: self.analysis.ty_cx.map.get_parent(expr.id),
+                            ref_id: def_id,
+                        }))
+                    }
+                    _ => {
+                        // FIXME ty could legitimately be a TyEnum, but then we will fail
+                        // later if we try to look up the fields.
+                        debug!("expected TyStruct, found {:?}", ty);
+                        None
+                    }
                 }
             }
             _ => {
@@ -253,10 +385,47 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
         }
     }
 
+    pub fn get_field_ref_data(&self,
+                              field_ref: &ast::Field,
+                              struct_id: DefId,
+                              parent: NodeId)
+                              -> VariableRefData {
+        let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, struct_id);
+        let field_name = get_ident(field_ref.ident.node).to_string();
+        for f in &fields {
+            if f.name == field_ref.ident.node.name {
+                // We don't really need a sub-span here, but no harm done
+                let sub_span = self.span_utils.span_for_last_ident(field_ref.ident.span);
+                return VariableRefData {
+                    name: field_name,
+                    span: sub_span.unwrap(),
+                    scope: parent,
+                    ref_id: f.id,
+                };
+            }
+        }
+
+        self.sess.span_bug(field_ref.span,
+                           &format!("Couldn't find field {}", field_name));
+    }
+
     pub fn get_data_for_id(&self, _id: &NodeId) -> Data {
         // FIXME
         unimplemented!();
     }
+
+    fn lookup_ref_id(&self, ref_id: NodeId) -> Option<DefId> {
+        if !self.analysis.ty_cx.def_map.borrow().contains_key(&ref_id) {
+            self.sess.bug(&format!("def_map has no key for {} in lookup_type_ref",
+                                  ref_id));
+        }
+        let def = self.analysis.ty_cx.def_map.borrow().get(&ref_id).unwrap().full_def();
+        match def {
+            def::DefPrimTy(_) => None,
+            _ => Some(def.def_id()),
+        }
+    }
+
 }
 
 // An AST visitor for collecting paths from patterns.
@@ -284,7 +453,7 @@ impl<'v> Visitor<'v> for PathCollector {
                 self.collected_paths.push((p.id,
                                            path.clone(),
                                            ast::MutMutable,
-                                           recorder::StructRef));
+                                           recorder::TypeRef));
             }
             ast::PatEnum(ref path, _) |
             ast::PatQPath(_, ref path) => {
diff --git a/src/librustc_trans/save/recorder.rs b/src/librustc_trans/save/recorder.rs
index c7759f4266b..c53fa22a2c1 100644
--- a/src/librustc_trans/save/recorder.rs
+++ b/src/librustc_trans/save/recorder.rs
@@ -89,7 +89,6 @@ pub enum Row {
     ModRef,
     VarRef,
     TypeRef,
-    StructRef,
     FnRef,
 }
 
@@ -150,9 +149,6 @@ impl<'a> FmtStrs<'a> {
             TypeRef => ("type_ref",
                         vec!("refid","refidcrate","qualname","scopeid"),
                         true, true),
-            StructRef => ("struct_ref",
-                          vec!("refid","refidcrate","qualname","scopeid"),
-                          true, true),
             FnRef => ("fn_ref", vec!("refid","refidcrate","qualname","scopeid"), true, true)
         }
     }