about summary refs log tree commit diff
path: root/src/librustdoc
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2015-04-13 16:23:32 -0700
committerAlex Crichton <alex@alexcrichton.com>2015-04-16 13:28:15 -0700
commit71c1b5b704ca3955e5ca22d77a0d59b55c9af4f1 (patch)
treeb233e253ba43b1fc0077464a2bba0ebf50162639 /src/librustdoc
parent8fb31f75c95c52cfef40c6ffe2f1452c959ca5e4 (diff)
downloadrust-71c1b5b704ca3955e5ca22d77a0d59b55c9af4f1.tar.gz
rust-71c1b5b704ca3955e5ca22d77a0d59b55c9af4f1.zip
rustdoc: Inline methods inhereted through Deref
Whenever a type implements Deref, rustdoc will now add a section to the "methods
available" sections for "Methods from Deref<Target=Foo>", listing all the
inherent methods of the type `Foo`.

Closes #19190
Diffstat (limited to 'src/librustdoc')
-rw-r--r--src/librustdoc/clean/inline.rs49
-rw-r--r--src/librustdoc/clean/mod.rs84
-rw-r--r--src/librustdoc/core.rs9
-rw-r--r--src/librustdoc/html/render.rs133
-rw-r--r--src/librustdoc/html/static/main.css8
-rw-r--r--src/librustdoc/test.rs3
6 files changed, 220 insertions, 66 deletions
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index f14437b71b4..4fc86cf181b 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -218,15 +218,17 @@ fn build_type(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::ItemEn
     })
 }
 
-fn build_impls(cx: &DocContext, tcx: &ty::ctxt,
-               did: ast::DefId) -> Vec<clean::Item> {
+pub fn build_impls(cx: &DocContext, tcx: &ty::ctxt,
+                   did: ast::DefId) -> Vec<clean::Item> {
     ty::populate_implementations_for_type_if_necessary(tcx, did);
     let mut impls = Vec::new();
 
     match tcx.inherent_impls.borrow().get(&did) {
         None => {}
         Some(i) => {
-            impls.extend(i.iter().map(|&did| { build_impl(cx, tcx, did) }));
+            for &did in i.iter() {
+                build_impl(cx, tcx, did, &mut impls);
+            }
         }
     }
 
@@ -247,9 +249,9 @@ fn build_impls(cx: &DocContext, tcx: &ty::ctxt,
 
         fn populate_impls(cx: &DocContext, tcx: &ty::ctxt,
                           def: decoder::DefLike,
-                          impls: &mut Vec<Option<clean::Item>>) {
+                          impls: &mut Vec<clean::Item>) {
             match def {
-                decoder::DlImpl(did) => impls.push(build_impl(cx, tcx, did)),
+                decoder::DlImpl(did) => build_impl(cx, tcx, did, impls),
                 decoder::DlDef(def::DefMod(did)) => {
                     csearch::each_child_of_item(&tcx.sess.cstore,
                                                 did,
@@ -262,14 +264,15 @@ fn build_impls(cx: &DocContext, tcx: &ty::ctxt,
         }
     }
 
-    impls.into_iter().filter_map(|a| a).collect()
+    return impls;
 }
 
-fn build_impl(cx: &DocContext,
-              tcx: &ty::ctxt,
-              did: ast::DefId) -> Option<clean::Item> {
+pub fn build_impl(cx: &DocContext,
+                  tcx: &ty::ctxt,
+                  did: ast::DefId,
+                  ret: &mut Vec<clean::Item>) {
     if !cx.inlined.borrow_mut().as_mut().unwrap().insert(did) {
-        return None
+        return
     }
 
     let attrs = load_attrs(cx, tcx, did);
@@ -278,13 +281,13 @@ fn build_impl(cx: &DocContext,
         // If this is an impl for a #[doc(hidden)] trait, be sure to not inline
         let trait_attrs = load_attrs(cx, tcx, t.def_id);
         if trait_attrs.iter().any(|a| is_doc_hidden(a)) {
-            return None
+            return
         }
     }
 
     // If this is a defaulted impl, then bail out early here
     if csearch::is_default_impl(&tcx.sess.cstore, did) {
-        return Some(clean::Item {
+        return ret.push(clean::Item {
             inner: clean::DefaultImplItem(clean::DefaultImpl {
                 // FIXME: this should be decoded
                 unsafety: ast::Unsafety::Normal,
@@ -352,19 +355,25 @@ fn build_impl(cx: &DocContext,
                 })
             }
         }
-    }).collect();
+    }).collect::<Vec<_>>();
     let polarity = csearch::get_impl_polarity(tcx, did);
     let ty = ty::lookup_item_type(tcx, did);
-    return Some(clean::Item {
+    let trait_ = associated_trait.clean(cx).map(|bound| {
+        match bound {
+            clean::TraitBound(polyt, _) => polyt.trait_,
+            clean::RegionBound(..) => unreachable!(),
+        }
+    });
+    if let Some(clean::ResolvedPath { did, .. }) = trait_ {
+        if Some(did) == cx.deref_trait_did.get() {
+            super::build_deref_target_impls(cx, &trait_items, ret);
+        }
+    }
+    ret.push(clean::Item {
         inner: clean::ImplItem(clean::Impl {
             unsafety: ast::Unsafety::Normal, // FIXME: this should be decoded
             derived: clean::detect_derived(&attrs),
-            trait_: associated_trait.clean(cx).map(|bound| {
-                match bound {
-                    clean::TraitBound(polyt, _) => polyt.trait_,
-                    clean::RegionBound(..) => unreachable!(),
-                }
-            }),
+            trait_: trait_,
             for_: ty.ty.clean(cx),
             generics: (&ty.generics, &predicates, subst::TypeSpace).clean(cx),
             items: trait_items,
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 263a93a9d67..f7fbb67e08a 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -128,6 +128,10 @@ impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
     fn clean(&self, cx: &DocContext) -> Crate {
         use rustc::session::config::Input;
 
+        if let Some(t) = cx.tcx_opt() {
+            cx.deref_trait_did.set(t.lang_items.deref_trait());
+        }
+
         let mut externs = Vec::new();
         cx.sess().cstore.iter_crate_data(|n, meta| {
             externs.push((n, meta.clean(cx)));
@@ -321,7 +325,7 @@ impl Item {
                     attr::Unstable => "unstable".to_string(),
                     attr::Stable => String::new(),
                 };
-                if s.deprecated_since.len() > 0 {
+                if !s.deprecated_since.is_empty() {
                     base.push_str(" deprecated");
                 }
                 base
@@ -387,7 +391,7 @@ impl Clean<Item> for doctree::Module {
         items.extend(self.statics.iter().map(|x| x.clean(cx)));
         items.extend(self.constants.iter().map(|x| x.clean(cx)));
         items.extend(self.traits.iter().map(|x| x.clean(cx)));
-        items.extend(self.impls.iter().map(|x| x.clean(cx)));
+        items.extend(self.impls.iter().flat_map(|x| x.clean(cx).into_iter()));
         items.extend(self.macros.iter().map(|x| x.clean(cx)));
         items.extend(self.def_traits.iter().map(|x| x.clean(cx)));
 
@@ -2186,9 +2190,21 @@ fn detect_derived<M: AttrMetaMethods>(attrs: &[M]) -> bool {
     attr::contains_name(attrs, "automatically_derived")
 }
 
-impl Clean<Item> for doctree::Impl {
-    fn clean(&self, cx: &DocContext) -> Item {
-        Item {
+impl Clean<Vec<Item>> for doctree::Impl {
+    fn clean(&self, cx: &DocContext) -> Vec<Item> {
+        let mut ret = Vec::new();
+        let trait_ = self.trait_.clean(cx);
+        let items = self.items.clean(cx);
+
+        // If this impl block is an implementation of the Deref trait, then we
+        // need to try inlining the target's inherent impl blocks as well.
+        if let Some(ResolvedPath { did, .. }) = trait_ {
+            if Some(did) == cx.deref_trait_did.get() {
+                build_deref_target_impls(cx, &items, &mut ret);
+            }
+        }
+
+        ret.push(Item {
             name: None,
             attrs: self.attrs.clean(cx),
             source: self.whence.clean(cx),
@@ -2198,12 +2214,66 @@ impl Clean<Item> for doctree::Impl {
             inner: ImplItem(Impl {
                 unsafety: self.unsafety,
                 generics: self.generics.clean(cx),
-                trait_: self.trait_.clean(cx),
+                trait_: trait_,
                 for_: self.for_.clean(cx),
-                items: self.items.clean(cx),
+                items: items,
                 derived: detect_derived(&self.attrs),
                 polarity: Some(self.polarity.clean(cx)),
             }),
+        });
+        return ret;
+    }
+}
+
+fn build_deref_target_impls(cx: &DocContext,
+                            items: &[Item],
+                            ret: &mut Vec<Item>) {
+    let tcx = match cx.tcx_opt() {
+        Some(t) => t,
+        None => return,
+    };
+
+    for item in items {
+        let target = match item.inner {
+            TypedefItem(ref t) => &t.type_,
+            _ => continue,
+        };
+        let primitive = match *target {
+            ResolvedPath { did, .. } if ast_util::is_local(did) => continue,
+            ResolvedPath { did, .. } => {
+                ret.extend(inline::build_impls(cx, tcx, did));
+                continue
+            }
+            _ => match target.primitive_type() {
+                Some(prim) => prim,
+                None => continue,
+            }
+        };
+        let did = match primitive {
+            Isize => tcx.lang_items.isize_impl(),
+            I8 => tcx.lang_items.i8_impl(),
+            I16 => tcx.lang_items.i16_impl(),
+            I32 => tcx.lang_items.i32_impl(),
+            I64 => tcx.lang_items.i64_impl(),
+            Usize => tcx.lang_items.usize_impl(),
+            U8 => tcx.lang_items.u8_impl(),
+            U16 => tcx.lang_items.u16_impl(),
+            U32 => tcx.lang_items.u32_impl(),
+            U64 => tcx.lang_items.u64_impl(),
+            F32 => tcx.lang_items.f32_impl(),
+            F64 => tcx.lang_items.f64_impl(),
+            Char => tcx.lang_items.char_impl(),
+            Bool => None,
+            Str => tcx.lang_items.str_impl(),
+            Slice => tcx.lang_items.slice_impl(),
+            Array => tcx.lang_items.slice_impl(),
+            PrimitiveTuple => None,
+            PrimitiveRawPointer => tcx.lang_items.const_ptr_impl(),
+        };
+        if let Some(did) = did {
+            if !ast_util::is_local(did) {
+                inline::build_impl(cx, tcx, did, ret);
+            }
         }
     }
 }
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index a637ba9f297..1b74123c4ad 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -20,7 +20,7 @@ use rustc_resolve as resolve;
 
 use syntax::{ast, ast_map, codemap, diagnostic};
 
-use std::cell::RefCell;
+use std::cell::{RefCell, Cell};
 use std::collections::{HashMap, HashSet};
 
 use visit_ast::RustdocVisitor;
@@ -48,6 +48,7 @@ pub struct DocContext<'tcx> {
     pub external_typarams: RefCell<Option<HashMap<ast::DefId, String>>>,
     pub inlined: RefCell<Option<HashSet<ast::DefId>>>,
     pub populated_crate_impls: RefCell<HashSet<ast::CrateNum>>,
+    pub deref_trait_did: Cell<Option<ast::DefId>>,
 }
 
 impl<'tcx> DocContext<'tcx> {
@@ -77,6 +78,7 @@ pub struct CrateAnalysis {
     pub external_paths: ExternalPaths,
     pub external_typarams: RefCell<Option<HashMap<ast::DefId, String>>>,
     pub inlined: RefCell<Option<HashSet<ast::DefId>>>,
+    pub deref_trait_did: Option<ast::DefId>,
 }
 
 pub type Externs = HashMap<String, Vec<String>>;
@@ -147,15 +149,17 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
         external_paths: RefCell::new(Some(HashMap::new())),
         inlined: RefCell::new(Some(HashSet::new())),
         populated_crate_impls: RefCell::new(HashSet::new()),
+        deref_trait_did: Cell::new(None),
     };
     debug!("crate: {:?}", ctxt.krate);
 
-    let analysis = CrateAnalysis {
+    let mut analysis = CrateAnalysis {
         exported_items: exported_items,
         public_items: public_items,
         external_paths: RefCell::new(None),
         external_typarams: RefCell::new(None),
         inlined: RefCell::new(None),
+        deref_trait_did: None,
     };
 
     let krate = {
@@ -170,5 +174,6 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
     *analysis.external_typarams.borrow_mut() = map;
     let map = ctxt.inlined.borrow_mut().take();
     *analysis.inlined.borrow_mut() = map;
+    analysis.deref_trait_did = ctxt.deref_trait_did.get();
     (krate, analysis)
 }
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index e3df0fc9ba6..f87a86eb3a6 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -209,6 +209,7 @@ pub struct Cache {
     privmod: bool,
     remove_priv: bool,
     public_items: NodeSet,
+    deref_trait_did: Option<ast::DefId>,
 
     // In rare case where a structure is defined in one module but implemented
     // in another, if the implementing module is parsed before defining module,
@@ -396,6 +397,7 @@ pub fn run(mut krate: clean::Crate,
         public_items: public_items,
         orphan_methods: Vec::new(),
         traits: mem::replace(&mut krate.external_traits, HashMap::new()),
+        deref_trait_did: analysis.as_ref().and_then(|a| a.deref_trait_did),
         typarams: analysis.as_ref().map(|a| {
             a.external_typarams.borrow_mut().take().unwrap()
         }).unwrap_or(HashMap::new()),
@@ -403,8 +405,6 @@ pub fn run(mut krate: clean::Crate,
             a.inlined.borrow_mut().take().unwrap()
         }).unwrap_or(HashSet::new()),
     };
-    cache.stack.push(krate.name.clone());
-    krate = cache.fold_crate(krate);
 
     // Cache where all our extern crates are located
     for &(n, ref e) in &krate.externs {
@@ -427,6 +427,9 @@ pub fn run(mut krate: clean::Crate,
         cache.primitive_locations.insert(prim, ast::LOCAL_CRATE);
     }
 
+    cache.stack.push(krate.name.clone());
+    krate = cache.fold_crate(krate);
+
     // Build our search index
     let index = try!(build_index(&krate, &mut cache));
 
@@ -1069,8 +1072,11 @@ impl DocFolder for Cache {
                             }
 
                             ref t => {
-                                t.primitive_type().map(|p| {
-                                    ast_util::local_def(p.to_node_id())
+                                t.primitive_type().and_then(|t| {
+                                    self.primitive_locations.get(&t).map(|n| {
+                                        let id = t.to_node_id();
+                                        ast::DefId { krate: *n, node: id }
+                                    })
                                 })
                             }
                         };
@@ -1684,12 +1690,12 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
 
 fn short_stability(item: &clean::Item, show_reason: bool) -> Option<String> {
     item.stability.as_ref().and_then(|stab| {
-        let reason = if show_reason && stab.reason.len() > 0 {
+        let reason = if show_reason && !stab.reason.is_empty() {
             format!(": {}", stab.reason)
         } else {
             String::new()
         };
-        let text = if stab.deprecated_since.len() > 0 {
+        let text = if !stab.deprecated_since.is_empty() {
             let since = if show_reason {
                 format!(" since {}", Escape(&stab.deprecated_since))
             } else {
@@ -1865,7 +1871,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
     }
 
     // If there are methods directly on this trait object, render them here.
-    try!(render_methods(w, it));
+    try!(render_methods(w, it.def_id, MethodRender::All));
 
     let cache = cache();
     try!(write!(w, "
@@ -1995,7 +2001,7 @@ fn item_struct(w: &mut fmt::Formatter, it: &clean::Item,
             try!(write!(w, "</table>"));
         }
     }
-    render_methods(w, it)
+    render_methods(w, it.def_id, MethodRender::All)
 }
 
 fn item_enum(w: &mut fmt::Formatter, it: &clean::Item,
@@ -2094,7 +2100,7 @@ fn item_enum(w: &mut fmt::Formatter, it: &clean::Item,
         try!(write!(w, "</table>"));
 
     }
-    try!(render_methods(w, it));
+    try!(render_methods(w, it.def_id, MethodRender::All));
     Ok(())
 }
 
@@ -2183,27 +2189,61 @@ enum MethodLink {
     GotoSource(ast::DefId),
 }
 
-fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {
-    let v = match cache().impls.get(&it.def_id) {
-        Some(v) => v.clone(),
+enum MethodRender<'a> {
+    All,
+    DerefFor { trait_: &'a clean::Type, type_: &'a clean::Type },
+}
+
+fn render_methods(w: &mut fmt::Formatter,
+                  it: ast::DefId,
+                  what: MethodRender) -> fmt::Result {
+    let c = cache();
+    let v = match c.impls.get(&it) {
+        Some(v) => v,
         None => return Ok(()),
     };
-    let (non_trait, traits): (Vec<_>, _) = v.into_iter()
-        .partition(|i| i.impl_.trait_.is_none());
+    let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| {
+        i.impl_.trait_.is_none()
+    });
     if !non_trait.is_empty() {
-        try!(write!(w, "<h2 id='methods'>Methods</h2>"));
+        let render_header = match what {
+            MethodRender::All => {
+                try!(write!(w, "<h2 id='methods'>Methods</h2>"));
+                true
+            }
+            MethodRender::DerefFor { trait_, type_ } => {
+                try!(write!(w, "<h2 id='deref-methods'>Methods from \
+                                    {}&lt;Target={}&gt;</h2>", trait_, type_));
+                false
+            }
+        };
         for i in &non_trait {
-            try!(render_impl(w, i, MethodLink::Anchor));
+            try!(render_impl(w, i, MethodLink::Anchor, render_header));
         }
     }
+    if let MethodRender::DerefFor { .. } = what {
+        return Ok(())
+    }
     if !traits.is_empty() {
+        let deref_impl = traits.iter().find(|t| {
+            match *t.impl_.trait_.as_ref().unwrap() {
+                clean::ResolvedPath { did, .. } => {
+                    Some(did) == c.deref_trait_did
+                }
+                _ => false
+            }
+        });
+        if let Some(impl_) = deref_impl {
+            try!(render_deref_methods(w, impl_));
+        }
         try!(write!(w, "<h2 id='implementations'>Trait \
                           Implementations</h2>"));
-        let (derived, manual): (Vec<_>, _) = traits.into_iter()
-            .partition(|i| i.impl_.derived);
+        let (derived, manual): (Vec<_>, _) = traits.iter().partition(|i| {
+            i.impl_.derived
+        });
         for i in &manual {
             let did = i.trait_did().unwrap();
-            try!(render_impl(w, i, MethodLink::GotoSource(did)));
+            try!(render_impl(w, i, MethodLink::GotoSource(did), true));
         }
         if !derived.is_empty() {
             try!(write!(w, "<h3 id='derived_implementations'>\
@@ -2211,27 +2251,52 @@ fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {
             </h3>"));
             for i in &derived {
                 let did = i.trait_did().unwrap();
-                try!(render_impl(w, i, MethodLink::GotoSource(did)));
+                try!(render_impl(w, i, MethodLink::GotoSource(did), true));
             }
         }
     }
     Ok(())
 }
 
-fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink)
-               -> fmt::Result {
-    try!(write!(w, "<h3 class='impl'><code>impl{} ",
-                i.impl_.generics));
-    if let Some(clean::ImplPolarity::Negative) = i.impl_.polarity {
-        try!(write!(w, "!"));
-    }
-    if let Some(ref ty) = i.impl_.trait_ {
-        try!(write!(w, "{} for ", *ty));
+fn render_deref_methods(w: &mut fmt::Formatter, impl_: &Impl) -> fmt::Result {
+    let deref_type = impl_.impl_.trait_.as_ref().unwrap();
+    let target = impl_.impl_.items.iter().filter_map(|item| {
+        match item.inner {
+            clean::TypedefItem(ref t) => Some(&t.type_),
+            _ => None,
+        }
+    }).next().unwrap();
+    let what = MethodRender::DerefFor { trait_: deref_type, type_: target };
+    match *target {
+        clean::ResolvedPath { did, .. } => render_methods(w, did, what),
+        _ => {
+            if let Some(prim) = target.primitive_type() {
+                if let Some(c) = cache().primitive_locations.get(&prim) {
+                    let did = ast::DefId { krate: *c, node: prim.to_node_id() };
+                    try!(render_methods(w, did, what));
+                }
+            }
+            Ok(())
+        }
     }
-    try!(write!(w, "{}{}</code></h3>", i.impl_.for_,
-                WhereClause(&i.impl_.generics)));
-    if let Some(ref dox) = i.dox {
-        try!(write!(w, "<div class='docblock'>{}</div>", Markdown(dox)));
+}
+
+fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink,
+               render_header: bool) -> fmt::Result {
+    if render_header {
+        try!(write!(w, "<h3 class='impl'><code>impl{} ",
+                    i.impl_.generics));
+        if let Some(clean::ImplPolarity::Negative) = i.impl_.polarity {
+            try!(write!(w, "!"));
+        }
+        if let Some(ref ty) = i.impl_.trait_ {
+            try!(write!(w, "{} for ", *ty));
+        }
+        try!(write!(w, "{}{}</code></h3>", i.impl_.for_,
+                    WhereClause(&i.impl_.generics)));
+        if let Some(ref dox) = i.dox {
+            try!(write!(w, "<div class='docblock'>{}</div>", Markdown(dox)));
+        }
     }
 
     fn doctraititem(w: &mut fmt::Formatter, item: &clean::Item,
@@ -2393,7 +2458,7 @@ fn item_primitive(w: &mut fmt::Formatter,
                   it: &clean::Item,
                   _p: &clean::PrimitiveType) -> fmt::Result {
     try!(document(w, it));
-    render_methods(w, it)
+    render_methods(w, it.def_id, MethodRender::All)
 }
 
 fn get_basic_keywords() -> &'static str {
diff --git a/src/librustdoc/html/static/main.css b/src/librustdoc/html/static/main.css
index 657b2c8fef8..c94dbc15103 100644
--- a/src/librustdoc/html/static/main.css
+++ b/src/librustdoc/html/static/main.css
@@ -481,9 +481,12 @@ em.stab.unstable { background: #FFF5D6; border-color: #FFC600; }
 em.stab.deprecated { background: #F3DFFF; border-color: #7F0087; }
 em.stab {
     display: inline-block;
-    border-width: 2px;
+    border-width: 1px;
     border-style: solid;
-    padding: 5px;
+    padding: 3px;
+    margin-bottom: 5px;
+    font-size: 90%;
+    font-style: normal;
 }
 em.stab p {
     display: inline;
@@ -492,6 +495,7 @@ em.stab p {
 .module-item .stab {
     border-width: 0;
     padding: 0;
+    margin: 0;
     background: inherit !important;
 }
 
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 449f9c79d1d..bbe0a6f2675 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::cell::RefCell;
+use std::cell::{RefCell, Cell};
 use std::collections::{HashSet, HashMap};
 use std::dynamic_lib::DynamicLibrary;
 use std::env;
@@ -92,6 +92,7 @@ pub fn run(input: &str,
         external_typarams: RefCell::new(None),
         inlined: RefCell::new(None),
         populated_crate_impls: RefCell::new(HashSet::new()),
+        deref_trait_did: Cell::new(None),
     };
 
     let mut v = RustdocVisitor::new(&ctx, None);