rustdoc: Fix ICE with cross-crate default impls

This adds a special code path for impls which are listed as default impls to
ensure that they're loaded correctly.
This commit is contained in:
Alex Crichton 2015-03-12 19:15:52 -07:00
parent c9b03c24ec
commit 4e25765aa2
11 changed files with 130 additions and 14 deletions

View File

@ -411,3 +411,8 @@ pub fn is_defaulted_trait(cstore: &cstore::CStore, trait_def_id: ast::DefId) ->
let cdata = cstore.get_crate_data(trait_def_id.krate);
decoder::is_defaulted_trait(&*cdata, trait_def_id.node)
}
pub fn is_default_impl(cstore: &cstore::CStore, impl_did: ast::DefId) -> bool {
let cdata = cstore.get_crate_data(impl_did.krate);
decoder::is_default_impl(&*cdata, impl_did.node)
}

View File

@ -1537,13 +1537,18 @@ pub fn is_associated_type(cdata: Cmd, id: ast::NodeId) -> bool {
}
}
pub fn is_defaulted_trait<'tcx>(cdata: Cmd, trait_id: ast::NodeId) -> bool {
pub fn is_defaulted_trait(cdata: Cmd, trait_id: ast::NodeId) -> bool {
let trait_doc = lookup_item(trait_id, cdata.data());
assert!(item_family(trait_doc) == Family::Trait);
let defaulted_doc = reader::get_doc(trait_doc, tag_defaulted_trait);
reader::doc_as_u8(defaulted_doc) != 0
}
pub fn is_default_impl(cdata: Cmd, impl_id: ast::NodeId) -> bool {
let impl_doc = lookup_item(impl_id, cdata.data());
item_family(impl_doc) == Family::DefaultImpl
}
pub fn get_imported_filemaps(metadata: &[u8]) -> Vec<codemap::FileMap> {
let crate_doc = rbml::Doc::new(metadata);
let cm_doc = reader::get_doc(crate_doc, tag_codemap);

View File

@ -259,26 +259,43 @@ fn build_impls(cx: &DocContext, tcx: &ty::ctxt,
impls.into_iter().filter_map(|a| a).collect()
}
fn build_impl(cx: &DocContext, tcx: &ty::ctxt,
fn build_impl(cx: &DocContext,
tcx: &ty::ctxt,
did: ast::DefId) -> Option<clean::Item> {
if !cx.inlined.borrow_mut().as_mut().unwrap().insert(did) {
return None
}
let attrs = load_attrs(cx, tcx, did);
let associated_trait = csearch::get_impl_trait(tcx, did);
// If this is an impl for a #[doc(hidden)] trait, be sure to not inline it.
match associated_trait {
Some(ref t) => {
let trait_attrs = load_attrs(cx, tcx, t.def_id);
if trait_attrs.iter().any(|a| is_doc_hidden(a)) {
return None
}
if let Some(ref t) = associated_trait {
// 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
}
None => {}
}
let attrs = load_attrs(cx, tcx, did);
let ty = ty::lookup_item_type(tcx, did);
// If this is a defaulted impl, then bail out early here
if csearch::is_default_impl(&tcx.sess.cstore, did) {
return Some(clean::Item {
inner: clean::DefaultImplItem(clean::DefaultImpl {
// FIXME: this should be decoded
unsafety: ast::Unsafety::Normal,
trait_: match associated_trait.as_ref().unwrap().clean(cx) {
clean::TraitBound(polyt, _) => polyt.trait_,
clean::RegionBound(..) => unreachable!(),
},
}),
source: clean::Span::empty(),
name: None,
attrs: attrs,
visibility: Some(ast::Inherited),
stability: stability::lookup(tcx, did).clean(cx),
def_id: did,
});
}
let predicates = ty::lookup_predicates(tcx, did);
let trait_items = csearch::get_impl_items(&tcx.sess.cstore, did)
.iter()
@ -330,8 +347,10 @@ fn build_impl(cx: &DocContext, tcx: &ty::ctxt,
}
}).collect();
let polarity = csearch::get_impl_polarity(tcx, did);
let ty = ty::lookup_item_type(tcx, did);
return Some(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 {

View File

@ -337,6 +337,7 @@ pub enum ItemEnum {
MacroItem(Macro),
PrimitiveItem(PrimitiveType),
AssociatedTypeItem(Vec<TyParamBound>, Option<Type>),
DefaultImplItem(DefaultImpl),
}
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
@ -367,6 +368,7 @@ impl Clean<Item> for doctree::Module {
items.extend(self.traits.iter().map(|x| x.clean(cx)));
items.extend(self.impls.iter().map(|x| x.clean(cx)));
items.extend(self.macros.iter().map(|x| x.clean(cx)));
items.extend(self.def_traits.iter().map(|x| x.clean(cx)));
// determine if we should display the inner contents or
// the outer `mod` item for the source code.
@ -2079,6 +2081,7 @@ impl Clean<ImplPolarity> for ast::ImplPolarity {
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct Impl {
pub unsafety: ast::Unsafety,
pub generics: Generics,
pub trait_: Option<Type>,
pub for_: Type,
@ -2101,6 +2104,7 @@ impl Clean<Item> for doctree::Impl {
visibility: self.vis.clean(cx),
stability: self.stab.clean(cx),
inner: ImplItem(Impl {
unsafety: self.unsafety,
generics: self.generics.clean(cx),
trait_: self.trait_.clean(cx),
for_: self.for_.clean(cx),
@ -2112,6 +2116,29 @@ impl Clean<Item> for doctree::Impl {
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct DefaultImpl {
pub unsafety: ast::Unsafety,
pub trait_: Type,
}
impl Clean<Item> for doctree::DefaultImpl {
fn clean(&self, cx: &DocContext) -> Item {
Item {
name: None,
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
def_id: ast_util::local_def(self.id),
visibility: Some(ast::Public),
stability: None,
inner: DefaultImplItem(DefaultImpl {
unsafety: self.unsafety,
trait_: self.trait_.clean(cx),
}),
}
}
}
impl Clean<Item> for doctree::ExternCrate {
fn clean(&self, cx: &DocContext) -> Item {
Item {

View File

@ -202,6 +202,8 @@ pub struct DefaultImpl {
pub unsafety: ast::Unsafety,
pub trait_: ast::TraitRef,
pub id: ast::NodeId,
pub attrs: Vec<ast::Attribute>,
pub whence: Span,
}
pub struct Macro {

View File

@ -64,6 +64,7 @@ impl ItemType {
clean::MacroItem(..) => ItemType::Macro,
clean::PrimitiveItem(..) => ItemType::Primitive,
clean::AssociatedTypeItem(..) => ItemType::AssociatedType,
clean::DefaultImplItem(..) => ItemType::Impl,
}
}

View File

@ -176,7 +176,7 @@ impl<'a> fold::DocFolder for Stripper<'a> {
return None;
}
}
clean::ImplItem(..) => {}
clean::DefaultImplItem(..) | clean::ImplItem(..) => {}
// tymethods/macros have no control over privacy
clean::MacroItem(..) | clean::TyMethodItem(..) => {}

View File

@ -362,7 +362,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
let i = DefaultImpl {
unsafety: unsafety,
trait_: trait_ref.clone(),
id: item.id
id: item.id,
attrs: item.attrs.clone(),
whence: item.span,
};
om.def_traits.push(i);
}

View File

@ -0,0 +1,5 @@
-include ../tools.mk
all: foo.rs bar.rs
$(RUSTC) foo.rs --crate-type lib
$(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc bar.rs -L $(TMPDIR)

View File

@ -0,0 +1,17 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
extern crate foo;
pub use foo::bar;
pub fn wut<T: bar::Bar>() {
}

View File

@ -0,0 +1,33 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub mod bar {
use std::marker;
pub trait Bar: marker::MarkerTrait + 'static {}
impl Bar for .. {}
pub trait Foo {
fn foo(&self) {}
}
impl Foo {
pub fn test<T: Bar>(&self) {}
}
pub struct TypeId;
impl TypeId {
pub fn of<T: Bar + ?Sized>() -> TypeId {
panic!()
}
}
}