auto merge of #10003 : alexcrichton/rust/issue-fixes, r=brson

Commits have all the fun details.
This commit is contained in:
bors 2013-10-22 01:31:24 -07:00
commit c6337f2099
7 changed files with 235 additions and 64 deletions

View File

@ -21,9 +21,9 @@ use middle::privacy;
use middle::resolve;
use std::hashmap::HashSet;
use syntax::ast::*;
use syntax::ast;
use syntax::ast_map;
use syntax::ast_util::{def_id_of_def, is_local};
use syntax::ast_util::{def_id_of_def, is_local, local_def};
use syntax::attr;
use syntax::parse::token;
use syntax::visit::Visitor;
@ -31,26 +31,26 @@ use syntax::visit;
// Returns true if the given set of attributes contains the `#[inline]`
// attribute.
fn attributes_specify_inlining(attrs: &[Attribute]) -> bool {
fn attributes_specify_inlining(attrs: &[ast::Attribute]) -> bool {
attr::contains_name(attrs, "inline")
}
// Returns true if the given set of generics implies that the item it's
// associated with must be inlined.
fn generics_require_inlining(generics: &Generics) -> bool {
fn generics_require_inlining(generics: &ast::Generics) -> bool {
!generics.ty_params.is_empty()
}
// Returns true if the given item must be inlined because it may be
// monomorphized or it was marked with `#[inline]`. This will only return
// true for functions.
fn item_might_be_inlined(item: @item) -> bool {
fn item_might_be_inlined(item: @ast::item) -> bool {
if attributes_specify_inlining(item.attrs) {
return true
}
match item.node {
item_fn(_, _, _, ref generics, _) => {
ast::item_fn(_, _, _, ref generics, _) => {
generics_require_inlining(generics)
}
_ => false,
@ -59,17 +59,17 @@ fn item_might_be_inlined(item: @item) -> bool {
// Returns true if the given type method must be inlined because it may be
// monomorphized or it was marked with `#[inline]`.
fn ty_method_might_be_inlined(ty_method: &TypeMethod) -> bool {
fn ty_method_might_be_inlined(ty_method: &ast::TypeMethod) -> bool {
attributes_specify_inlining(ty_method.attrs) ||
generics_require_inlining(&ty_method.generics)
}
// Returns true if the given trait method must be inlined because it may be
// monomorphized or it was marked with `#[inline]`.
fn trait_method_might_be_inlined(trait_method: &trait_method) -> bool {
fn trait_method_might_be_inlined(trait_method: &ast::trait_method) -> bool {
match *trait_method {
required(ref ty_method) => ty_method_might_be_inlined(ty_method),
provided(_) => true
ast::required(ref ty_method) => ty_method_might_be_inlined(ty_method),
ast::provided(_) => true
}
}
@ -81,27 +81,27 @@ struct ReachableContext {
// methods they've been resolved to.
method_map: typeck::method_map,
// The set of items which must be exported in the linkage sense.
reachable_symbols: @mut HashSet<NodeId>,
reachable_symbols: @mut HashSet<ast::NodeId>,
// A worklist of item IDs. Each item ID in this worklist will be inlined
// and will be scanned for further references.
worklist: @mut ~[NodeId],
worklist: @mut ~[ast::NodeId],
// Known reexports of modules
exp_map2: resolve::ExportMap2,
}
struct MarkSymbolVisitor {
worklist: @mut ~[NodeId],
worklist: @mut ~[ast::NodeId],
method_map: typeck::method_map,
tcx: ty::ctxt,
reachable_symbols: @mut HashSet<NodeId>,
reachable_symbols: @mut HashSet<ast::NodeId>,
}
impl Visitor<()> for MarkSymbolVisitor {
fn visit_expr(&mut self, expr:@Expr, _:()) {
fn visit_expr(&mut self, expr:@ast::Expr, _:()) {
match expr.node {
ExprPath(_) => {
ast::ExprPath(_) => {
let def = match self.tcx.def_map.find(&expr.id) {
Some(&def) => def,
None => {
@ -118,7 +118,7 @@ impl Visitor<()> for MarkSymbolVisitor {
}
self.reachable_symbols.insert(def_id.node);
}
ExprMethodCall(*) => {
ast::ExprMethodCall(*) => {
match self.method_map.find(&expr.id) {
Some(&typeck::method_map_entry {
origin: typeck::method_static(def_id),
@ -162,9 +162,9 @@ impl ReachableContext {
// Returns true if the given def ID represents a local item that is
// eligible for inlining and false otherwise.
fn def_id_represents_local_inlined_item(tcx: ty::ctxt, def_id: DefId)
fn def_id_represents_local_inlined_item(tcx: ty::ctxt, def_id: ast::DefId)
-> bool {
if def_id.crate != LOCAL_CRATE {
if def_id.crate != ast::LOCAL_CRATE {
return false
}
@ -172,14 +172,14 @@ impl ReachableContext {
match tcx.items.find(&node_id) {
Some(&ast_map::node_item(item, _)) => {
match item.node {
item_fn(*) => item_might_be_inlined(item),
ast::item_fn(*) => item_might_be_inlined(item),
_ => false,
}
}
Some(&ast_map::node_trait_method(trait_method, _, _)) => {
match *trait_method {
required(_) => false,
provided(_) => true,
ast::required(_) => false,
ast::provided(_) => true,
}
}
Some(&ast_map::node_method(method, impl_did, _)) => {
@ -189,11 +189,11 @@ impl ReachableContext {
} else {
// Check the impl. If the generics on the self type of the
// impl require inlining, this method does too.
assert!(impl_did.crate == LOCAL_CRATE);
assert!(impl_did.crate == ast::LOCAL_CRATE);
match tcx.items.find(&impl_did.node) {
Some(&ast_map::node_item(item, _)) => {
match item.node {
item_impl(ref generics, _, _, _) => {
ast::item_impl(ref generics, _, _, _) => {
generics_require_inlining(generics)
}
_ => false
@ -231,7 +231,7 @@ impl ReachableContext {
}
}
fn propagate_mod(&self, id: NodeId) {
fn propagate_mod(&self, id: ast::NodeId) {
match self.exp_map2.find(&id) {
Some(l) => {
for reexport in l.iter() {
@ -262,7 +262,7 @@ impl ReachableContext {
match self.tcx.items.find(&search_item) {
Some(&ast_map::node_item(item, _)) => {
match item.node {
item_fn(_, _, _, _, ref search_block) => {
ast::item_fn(_, _, _, _, ref search_block) => {
visit::walk_block(&mut visitor, search_block, ())
}
// Our recursion into modules involves looking up their
@ -270,13 +270,50 @@ impl ReachableContext {
// exports. Privacy will put them in the worklist, but
// we won't find them in the ast_map, so this is where
// we deal with publicly re-exported items instead.
item_mod(*) => { self.propagate_mod(item.id); }
ast::item_mod(*) => self.propagate_mod(item.id),
// Implementations of exported structs/enums need to get
// added to the worklist (as all their methods should be
// accessible)
ast::item_struct(*) | ast::item_enum(*) => {
let def = local_def(item.id);
let impls = match self.tcx.inherent_impls.find(&def) {
Some(&impls) => impls,
None => continue
};
for imp in impls.iter() {
if is_local(imp.did) {
self.worklist.push(imp.did.node);
}
}
}
// Propagate through this impl
ast::item_impl(_, _, _, ref methods) => {
for method in methods.iter() {
self.worklist.push(method.id);
}
}
// Default methods of exported traits need to all be
// accessible.
ast::item_trait(_, _, ref methods) => {
for method in methods.iter() {
match *method {
ast::required(*) => {}
ast::provided(ref method) => {
self.worklist.push(method.id);
}
}
}
}
// These are normal, nothing reachable about these
// inherently and their children are already in the
// worklist
item_struct(*) | item_impl(*) | item_static(*) |
item_enum(*) | item_ty(*) | item_trait(*) |
item_foreign_mod(*) => {}
ast::item_static(*) | ast::item_ty(*) |
ast::item_foreign_mod(*) => {}
_ => {
self.tcx.sess.span_bug(item.span,
"found non-function item \
@ -286,10 +323,10 @@ impl ReachableContext {
}
Some(&ast_map::node_trait_method(trait_method, _, _)) => {
match *trait_method {
required(*) => {
ast::required(*) => {
// Keep going, nothing to get exported
}
provided(ref method) => {
ast::provided(ref method) => {
visit::walk_block(&mut visitor, &method.body, ())
}
}
@ -310,7 +347,7 @@ impl ReachableContext {
worklist: {}",
desc))
}
None if search_item == CRATE_NODE_ID => {
None if search_item == ast::CRATE_NODE_ID => {
self.propagate_mod(search_item);
}
None => {
@ -329,7 +366,7 @@ impl ReachableContext {
// reachability, which might result in a compile time loss.
fn mark_destructors_reachable(&self) {
for (_, destructor_def_id) in self.tcx.destructor_for_type.iter() {
if destructor_def_id.crate == LOCAL_CRATE {
if destructor_def_id.crate == ast::LOCAL_CRATE {
self.reachable_symbols.insert(destructor_def_id.node);
}
}
@ -340,7 +377,7 @@ pub fn find_reachable(tcx: ty::ctxt,
method_map: typeck::method_map,
exp_map2: resolve::ExportMap2,
exported_items: &privacy::ExportedItems)
-> @mut HashSet<NodeId> {
-> @mut HashSet<ast::NodeId> {
// XXX(pcwalton): We only need to mark symbols that are exported. But this
// is more complicated than just looking at whether the symbol is `pub`,
// because it might be the target of a `pub use` somewhere. For now, I

View File

@ -149,10 +149,9 @@ pub struct Cache {
/// This map contains information about all known traits of this crate.
/// Implementations of a crate should inherit the documentation of the
/// parent trait if no extra documentation is specified, and this map is
/// keyed on trait id with a value of a 'method name => documentation'
/// mapping.
traits: HashMap<ast::NodeId, HashMap<~str, ~str>>,
/// parent trait if no extra documentation is specified, and default methods
/// should show up in documentation about trait implementations.
traits: HashMap<ast::NodeId, clean::Trait>,
/// When rendering traits, it's often useful to be able to list all
/// implementors of the trait, and this mapping is exactly, that: a mapping
@ -488,18 +487,7 @@ impl DocFolder for Cache {
// trait
match item.inner {
clean::TraitItem(ref t) => {
let mut dox = HashMap::new();
for meth in t.methods.iter() {
let it = meth.item();
match it.doc_value() {
None => {}
Some(s) => {
dox.insert(it.name.get_ref().to_owned(),
s.to_owned());
}
}
}
self.traits.insert(item.id, dox);
self.traits.insert(item.id, t.clone());
}
_ => {}
}
@ -1480,18 +1468,25 @@ fn render_impl(w: &mut io::Writer, i: &clean::Impl, dox: &Option<~str>) {
}
None => {}
}
write!(w, "<div class='methods'>");
for meth in i.methods.iter() {
fn docmeth(w: &mut io::Writer, item: &clean::Item) -> bool {
write!(w, "<h4 id='method.{}' class='method'><code>",
*meth.name.get_ref());
render_method(w, meth, false);
*item.name.get_ref());
render_method(w, item, false);
write!(w, "</code></h4>\n");
match meth.doc_value() {
match item.doc_value() {
Some(s) => {
write!(w, "<div class='docblock'>{}</div>", Markdown(s));
continue
true
}
None => {}
None => false
}
}
write!(w, "<div class='methods'>");
for meth in i.methods.iter() {
if docmeth(w, meth) {
continue
}
// No documentation? Attempt to slurp in the trait's documentation
@ -1501,13 +1496,19 @@ fn render_impl(w: &mut io::Writer, i: &clean::Impl, dox: &Option<~str>) {
};
do local_data::get(cache_key) |cache| {
do cache.unwrap().read |cache| {
let name = meth.name.get_ref().as_slice();
match cache.traits.find(&trait_id) {
Some(m) => {
match m.find_equiv(&name) {
Some(s) => {
write!(w, "<div class='docblock'>{}</div>",
Markdown(s.as_slice()));
Some(t) => {
let name = meth.name.clone();
match t.methods.iter().find(|t| t.item().name == name) {
Some(method) => {
match method.item().doc_value() {
Some(s) => {
write!(w,
"<div class='docblock'>{}</div>",
Markdown(s));
}
None => {}
}
}
None => {}
}
@ -1517,6 +1518,32 @@ fn render_impl(w: &mut io::Writer, i: &clean::Impl, dox: &Option<~str>) {
}
}
}
// If we've implemented a trait, then also emit documentation for all
// default methods which weren't overridden in the implementation block.
match trait_id {
None => {}
Some(id) => {
do local_data::get(cache_key) |cache| {
do cache.unwrap().read |cache| {
match cache.traits.find(&id) {
Some(t) => {
for method in t.methods.iter() {
let n = method.item().name.clone();
match i.methods.iter().find(|m| m.name == n) {
Some(*) => continue,
None => {}
}
docmeth(w, method.item());
}
}
None => {}
}
}
}
}
}
write!(w, "</div>");
}

View File

@ -97,6 +97,13 @@ nav.sub {
margin-bottom: 10px;
}
.block h2 { margin-top: 0; }
.block a {
display: inline-block;
width: 100%;
text-overflow: ellipsis;
overflow: hidden;
line-height: 15px;
}
.content {
background: #f3f3f3;

View File

@ -0,0 +1,28 @@
// Copyright 2013 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.
// xfail-fast windows doesn't like extern mod
// aux-build:issue-9906.rs
pub use other::FooBar;
pub use other::foo;
mod other {
pub struct FooBar{value: int}
impl FooBar{
pub fn new(val: int) -> FooBar {
FooBar{value: val}
}
}
pub fn foo(){
1+1;
}
}

View File

@ -0,0 +1,32 @@
// Copyright 2013 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 use internal::core::{Trait, Struct};
mod internal {
pub mod core {
pub struct Struct;
impl Struct {
pub fn init() -> Struct {
Struct
}
}
pub trait Trait {
fn test(&self) {
private();
}
}
impl Trait for Struct {}
fn private() { }
}
}

View File

@ -0,0 +1,19 @@
// Copyright 2013 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.
// xfail-fast windows doesn't like extern mod
// aux-build:issue-9906.rs
extern mod testmod(name = "issue-9906");
fn main() {
testmod::foo();
testmod::FooBar::new(1);
}

View File

@ -0,0 +1,21 @@
// Copyright 2013 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.
// xfail-fast windows doesn't like extern mod
// aux-build:issue-9968.rs
extern mod lib(name = "issue-9968");
use lib::{Trait, Struct};
fn main()
{
Struct::init().test();
}