提交 667fdc1c 编写于 作者: B bors

Auto merge of #52827 - GuillaumeGomez:generic-impls, r=QuietMisdreavus

rustdoc: clean up generic impls

r? @QuietMisdreavus
......@@ -9,15 +9,11 @@
// except according to those terms.
use rustc::hir;
use rustc::traits::{self, auto_trait as auto};
use rustc::ty::{self, ToPredicate, TypeFoldable};
use rustc::ty::subst::Subst;
use rustc::infer::InferOk;
use rustc::middle::cstore::CrateStore;
use rustc::traits::auto_trait as auto;
use rustc::ty::{self, TypeFoldable};
use std::fmt::Debug;
use syntax_pos::DUMMY_SP;
use core::DocAccessLevels;
use self::def_ctor::{get_def_from_def_id, get_def_from_node_id};
use super::*;
......@@ -34,186 +30,16 @@ pub fn new(cx: &'a core::DocContext<'a, 'tcx, 'rcx, 'cstore>) -> Self {
}
pub fn get_with_def_id(&self, def_id: DefId) -> Vec<Item> {
let ty = self.cx.tcx.type_of(def_id);
let def_ctor: fn(DefId) -> Def = match ty.sty {
ty::TyAdt(adt, _) => match adt.adt_kind() {
AdtKind::Struct => Def::Struct,
AdtKind::Enum => Def::Enum,
AdtKind::Union => Def::Union,
}
ty::TyInt(_) |
ty::TyUint(_) |
ty::TyFloat(_) |
ty::TyStr |
ty::TyBool |
ty::TyChar => return self.get_auto_trait_impls(def_id, &move |_: DefId| {
match ty.sty {
ty::TyInt(x) => Def::PrimTy(hir::TyInt(x)),
ty::TyUint(x) => Def::PrimTy(hir::TyUint(x)),
ty::TyFloat(x) => Def::PrimTy(hir::TyFloat(x)),
ty::TyStr => Def::PrimTy(hir::TyStr),
ty::TyBool => Def::PrimTy(hir::TyBool),
ty::TyChar => Def::PrimTy(hir::TyChar),
_ => unreachable!(),
}
}, None),
_ => {
debug!("Unexpected type {:?}", def_id);
return Vec::new()
}
};
self.get_auto_trait_impls(def_id, &def_ctor, None)
get_def_from_def_id(&self.cx, def_id, &|def_ctor| {
self.get_auto_trait_impls(def_id, &def_ctor, None)
})
}
pub fn get_with_node_id(&self, id: ast::NodeId, name: String) -> Vec<Item> {
let item = &self.cx.tcx.hir.expect_item(id).node;
let did = self.cx.tcx.hir.local_def_id(id);
let def_ctor = match *item {
hir::ItemKind::Struct(_, _) => Def::Struct,
hir::ItemKind::Union(_, _) => Def::Union,
hir::ItemKind::Enum(_, _) => Def::Enum,
_ => panic!("Unexpected type {:?} {:?}", item, id),
};
self.get_auto_trait_impls(did, &def_ctor, Some(name))
}
fn get_real_ty<F>(&self,
def_id: DefId,
def_ctor: &F,
real_name: &Option<Ident>,
generics: &ty::Generics,
) -> hir::Ty
where F: Fn(DefId) -> Def {
let path = get_path_for_type(self.cx.tcx, def_id, def_ctor);
let mut segments = path.segments.into_vec();
let last = segments.pop().unwrap();
segments.push(hir::PathSegment::new(
real_name.unwrap_or(last.ident),
self.generics_to_path_params(generics.clone()),
false,
));
let new_path = hir::Path {
span: path.span,
def: path.def,
segments: HirVec::from_vec(segments),
};
hir::Ty {
id: ast::DUMMY_NODE_ID,
node: hir::TyKind::Path(hir::QPath::Resolved(None, P(new_path))),
span: DUMMY_SP,
hir_id: hir::DUMMY_HIR_ID,
}
}
pub fn get_blanket_impls<F>(
&self,
def_id: DefId,
def_ctor: &F,
name: Option<String>,
generics: &ty::Generics,
) -> Vec<Item>
where F: Fn(DefId) -> Def {
let ty = self.cx.tcx.type_of(def_id);
let mut traits = Vec::new();
if self.cx.access_levels.borrow().is_doc_reachable(def_id) {
let real_name = name.clone().map(|name| Ident::from_str(&name));
let param_env = self.cx.tcx.param_env(def_id);
for &trait_def_id in self.cx.all_traits.iter() {
if !self.cx.access_levels.borrow().is_doc_reachable(trait_def_id) ||
self.cx.generated_synthetics
.borrow_mut()
.get(&(def_id, trait_def_id))
.is_some() {
continue
}
self.cx.tcx.for_each_relevant_impl(trait_def_id, ty, |impl_def_id| {
self.cx.tcx.infer_ctxt().enter(|infcx| {
let t_generics = infcx.tcx.generics_of(impl_def_id);
let trait_ref = infcx.tcx.impl_trait_ref(impl_def_id).unwrap();
match infcx.tcx.type_of(impl_def_id).sty {
::rustc::ty::TypeVariants::TyParam(_) => {},
_ => return,
}
let substs = infcx.fresh_substs_for_item(DUMMY_SP, def_id);
let ty = ty.subst(infcx.tcx, substs);
let param_env = param_env.subst(infcx.tcx, substs);
let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
let trait_ref = trait_ref.subst(infcx.tcx, impl_substs);
// Require the type the impl is implemented on to match
// our type, and ignore the impl if there was a mismatch.
let cause = traits::ObligationCause::dummy();
let eq_result = infcx.at(&cause, param_env)
.eq(trait_ref.self_ty(), ty);
if let Ok(InferOk { value: (), obligations }) = eq_result {
// FIXME(eddyb) ignoring `obligations` might cause false positives.
drop(obligations);
let may_apply = infcx.predicate_may_hold(&traits::Obligation::new(
cause.clone(),
param_env,
trait_ref.to_predicate(),
));
if !may_apply {
return
}
self.cx.generated_synthetics.borrow_mut()
.insert((def_id, trait_def_id));
let trait_ = hir::TraitRef {
path: get_path_for_type(infcx.tcx,
trait_def_id,
hir::def::Def::Trait),
ref_id: ast::DUMMY_NODE_ID,
};
let provided_trait_methods =
infcx.tcx.provided_trait_methods(trait_def_id)
.into_iter()
.map(|meth| meth.ident.to_string())
.collect();
let ty = self.get_real_ty(def_id, def_ctor, &real_name, generics);
let predicates = infcx.tcx.predicates_of(impl_def_id);
traits.push(Item {
source: infcx.tcx.def_span(impl_def_id).clean(self.cx),
name: None,
attrs: Default::default(),
visibility: None,
def_id: self.next_def_id(impl_def_id.krate),
stability: None,
deprecation: None,
inner: ImplItem(Impl {
unsafety: hir::Unsafety::Normal,
generics: (t_generics, &predicates).clean(self.cx),
provided_trait_methods,
trait_: Some(trait_.clean(self.cx)),
for_: ty.clean(self.cx),
items: infcx.tcx.associated_items(impl_def_id)
.collect::<Vec<_>>()
.clean(self.cx),
polarity: None,
synthetic: false,
blanket_impl: Some(infcx.tcx.type_of(impl_def_id)
.clean(self.cx)),
}),
});
debug!("{:?} => {}", trait_ref, may_apply);
}
});
});
}
}
traits
get_def_from_node_id(&self.cx, id, name, &|def_ctor, name| {
let did = self.cx.tcx.hir.local_def_id(id);
self.get_auto_trait_impls(did, &def_ctor, Some(name))
})
}
pub fn get_auto_trait_impls<F>(
......@@ -263,7 +89,6 @@ pub fn get_auto_trait_impls<F>(
def_ctor,
tcx.require_lang_item(lang_items::SyncTraitLangItem),
).into_iter())
.chain(self.get_blanket_impls(def_id, def_ctor, name, &generics).into_iter())
.collect();
debug!(
......@@ -339,14 +164,14 @@ fn get_auto_trait_impl_for<F>(
_ => unreachable!(),
};
let real_name = name.map(|name| Ident::from_str(&name));
let ty = self.get_real_ty(def_id, def_ctor, &real_name, &generics);
let ty = self.cx.get_real_ty(def_id, def_ctor, &real_name, &generics);
return Some(Item {
source: Span::empty(),
name: None,
attrs: Default::default(),
visibility: None,
def_id: self.next_def_id(def_id.krate),
def_id: self.cx.next_def_id(def_id.krate),
stability: None,
deprecation: None,
inner: ImplItem(Impl {
......@@ -365,56 +190,6 @@ fn get_auto_trait_impl_for<F>(
None
}
fn generics_to_path_params(&self, generics: ty::Generics) -> hir::GenericArgs {
let mut args = vec![];
for param in generics.params.iter() {
match param.kind {
ty::GenericParamDefKind::Lifetime => {
let name = if param.name == "" {
hir::ParamName::Plain(keywords::StaticLifetime.ident())
} else {
hir::ParamName::Plain(ast::Ident::from_interned_str(param.name))
};
args.push(hir::GenericArg::Lifetime(hir::Lifetime {
id: ast::DUMMY_NODE_ID,
span: DUMMY_SP,
name: hir::LifetimeName::Param(name),
}));
}
ty::GenericParamDefKind::Type {..} => {
args.push(hir::GenericArg::Type(self.ty_param_to_ty(param.clone())));
}
}
}
hir::GenericArgs {
args: HirVec::from_vec(args),
bindings: HirVec::new(),
parenthesized: false,
}
}
fn ty_param_to_ty(&self, param: ty::GenericParamDef) -> hir::Ty {
debug!("ty_param_to_ty({:?}) {:?}", param, param.def_id);
hir::Ty {
id: ast::DUMMY_NODE_ID,
node: hir::TyKind::Path(hir::QPath::Resolved(
None,
P(hir::Path {
span: DUMMY_SP,
def: Def::TyParam(param.def_id),
segments: HirVec::from_vec(vec![
hir::PathSegment::from_ident(Ident::from_interned_str(param.name))
]),
}),
)),
span: DUMMY_SP,
hir_id: hir::DUMMY_HIR_ID,
}
}
fn find_auto_trait_generics(
&self,
did: DefId,
......@@ -531,7 +306,7 @@ fn handle_lifetimes<'cx>(
// Desired order is 'larger, smaller', so flip then
if self.region_name(r1) != self.region_name(r2) {
finished
.entry(self.region_name(r2).unwrap())
.entry(self.region_name(r2).expect("no region_name found"))
.or_insert_with(|| Vec::new())
.push(r1);
}
......@@ -566,7 +341,7 @@ fn handle_lifetimes<'cx>(
(&RegionTarget::Region(r1), &RegionTarget::Region(r2)) => {
if self.region_name(r1) != self.region_name(r2) {
finished
.entry(self.region_name(r2).unwrap())
.entry(self.region_name(r2).expect("no region name found"))
.or_insert_with(|| Vec::new())
.push(r1) // Larger, smaller
}
......@@ -663,7 +438,7 @@ fn make_final_bounds<'b, 'c, 'cx>(
.flat_map(|(ty, mut bounds)| {
if let Some(data) = ty_to_fn.get(&ty) {
let (poly_trait, output) =
(data.0.as_ref().unwrap().clone(), data.1.as_ref().cloned());
(data.0.as_ref().expect("as_ref failed").clone(), data.1.as_ref().cloned());
let new_ty = match &poly_trait.trait_ {
&Type::ResolvedPath {
ref path,
......@@ -672,7 +447,8 @@ fn make_final_bounds<'b, 'c, 'cx>(
ref is_generic,
} => {
let mut new_path = path.clone();
let last_segment = new_path.segments.pop().unwrap();
let last_segment = new_path.segments.pop()
.expect("segments were empty");
let (old_input, old_output) = match last_segment.args {
GenericArgs::AngleBracketed { types, .. } => (types, None),
......@@ -830,7 +606,7 @@ fn param_env_to_generics<'b, 'c, 'cx>(
let mut for_generics = self.extract_for_generics(tcx, orig_p.clone());
assert!(bounds.len() == 1);
let mut b = bounds.pop().unwrap();
let mut b = bounds.pop().expect("bounds were empty");
if b.is_sized_bound(self.cx) {
has_sized.insert(ty.clone());
......@@ -860,7 +636,7 @@ fn param_env_to_generics<'b, 'c, 'cx>(
_ => false,
};
let poly_trait = b.get_poly_trait().unwrap();
let poly_trait = b.get_poly_trait().expect("Cannot get poly trait");
if is_fn {
ty_to_fn
......@@ -913,7 +689,10 @@ fn param_env_to_generics<'b, 'c, 'cx>(
// FIXME: Remove this scope when NLL lands
{
let args =
&mut new_trait_path.segments.last_mut().unwrap().args;
&mut new_trait_path.segments
.last_mut()
.expect("segments were empty")
.args;
match args {
// Convert somethiung like '<T as Iterator::Item> = u8'
......@@ -1077,61 +856,6 @@ fn is_fn_ty(&self, tcx: &TyCtxt, ty: &Type) -> bool {
_ => false,
}
}
// This is an ugly hack, but it's the simplest way to handle synthetic impls without greatly
// refactoring either librustdoc or librustc. In particular, allowing new DefIds to be
// registered after the AST is constructed would require storing the defid mapping in a
// RefCell, decreasing the performance for normal compilation for very little gain.
//
// Instead, we construct 'fake' def ids, which start immediately after the last DefId in
// DefIndexAddressSpace::Low. In the Debug impl for clean::Item, we explicitly check for fake
// def ids, as we'll end up with a panic if we use the DefId Debug impl for fake DefIds
fn next_def_id(&self, crate_num: CrateNum) -> DefId {
let start_def_id = {
let next_id = if crate_num == LOCAL_CRATE {
self.cx
.tcx
.hir
.definitions()
.def_path_table()
.next_id(DefIndexAddressSpace::Low)
} else {
self.cx
.cstore
.def_path_table(crate_num)
.next_id(DefIndexAddressSpace::Low)
};
DefId {
krate: crate_num,
index: next_id,
}
};
let mut fake_ids = self.cx.fake_def_ids.borrow_mut();
let def_id = fake_ids.entry(crate_num).or_insert(start_def_id).clone();
fake_ids.insert(
crate_num,
DefId {
krate: crate_num,
index: DefIndex::from_array_index(
def_id.index.as_array_index() + 1,
def_id.index.address_space(),
),
},
);
MAX_DEF_ID.with(|m| {
m.borrow_mut()
.entry(def_id.krate.clone())
.or_insert(start_def_id);
});
self.cx.all_fake_def_ids.borrow_mut().insert(def_id);
def_id.clone()
}
}
// Replaces all ReVars in a type with ty::Region's, using the provided map
......
// Copyright 2018 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.
use rustc::hir;
use rustc::traits;
use rustc::ty::ToPredicate;
use rustc::ty::subst::Subst;
use rustc::infer::InferOk;
use syntax_pos::DUMMY_SP;
use core::DocAccessLevels;
use super::*;
use self::def_ctor::{get_def_from_def_id, get_def_from_node_id};
pub struct BlanketImplFinder<'a, 'tcx: 'a, 'rcx: 'a, 'cstore: 'rcx> {
pub cx: &'a core::DocContext<'a, 'tcx, 'rcx, 'cstore>,
}
impl<'a, 'tcx, 'rcx, 'cstore> BlanketImplFinder <'a, 'tcx, 'rcx, 'cstore> {
pub fn new(cx: &'a core::DocContext<'a, 'tcx, 'rcx, 'cstore>) -> Self {
BlanketImplFinder { cx }
}
pub fn get_with_def_id(&self, def_id: DefId) -> Vec<Item> {
get_def_from_def_id(&self.cx, def_id, &|def_ctor| {
self.get_blanket_impls(def_id, &def_ctor, None)
})
}
pub fn get_with_node_id(&self, id: ast::NodeId, name: String) -> Vec<Item> {
get_def_from_node_id(&self.cx, id, name, &|def_ctor, name| {
let did = self.cx.tcx.hir.local_def_id(id);
self.get_blanket_impls(did, &def_ctor, Some(name))
})
}
pub fn get_blanket_impls<F>(
&self,
def_id: DefId,
def_ctor: &F,
name: Option<String>,
) -> Vec<Item>
where F: Fn(DefId) -> Def {
let mut impls = Vec::new();
if self.cx
.tcx
.get_attrs(def_id)
.lists("doc")
.has_word("hidden")
{
debug!(
"get_blanket_impls(def_id={:?}, def_ctor=...): item has doc('hidden'), \
aborting",
def_id
);
return impls;
}
let ty = self.cx.tcx.type_of(def_id);
if self.cx.access_levels.borrow().is_doc_reachable(def_id) || ty.is_primitive() {
let generics = self.cx.tcx.generics_of(def_id);
let real_name = name.clone().map(|name| Ident::from_str(&name));
let param_env = self.cx.tcx.param_env(def_id);
for &trait_def_id in self.cx.all_traits.iter() {
if !self.cx.access_levels.borrow().is_doc_reachable(trait_def_id) ||
self.cx.generated_synthetics
.borrow_mut()
.get(&(def_id, trait_def_id))
.is_some() {
continue
}
self.cx.tcx.for_each_relevant_impl(trait_def_id, ty, |impl_def_id| {
self.cx.tcx.infer_ctxt().enter(|infcx| {
let t_generics = infcx.tcx.generics_of(impl_def_id);
let trait_ref = infcx.tcx.impl_trait_ref(impl_def_id)
.expect("Cannot get impl trait");
match trait_ref.self_ty().sty {
ty::TypeVariants::TyParam(_) => {},
_ => return,
}
let substs = infcx.fresh_substs_for_item(DUMMY_SP, def_id);
let ty = ty.subst(infcx.tcx, substs);
let param_env = param_env.subst(infcx.tcx, substs);
let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
let trait_ref = trait_ref.subst(infcx.tcx, impl_substs);
// Require the type the impl is implemented on to match
// our type, and ignore the impl if there was a mismatch.
let cause = traits::ObligationCause::dummy();
let eq_result = infcx.at(&cause, param_env)
.eq(trait_ref.self_ty(), ty);
if let Ok(InferOk { value: (), obligations }) = eq_result {
// FIXME(eddyb) ignoring `obligations` might cause false positives.
drop(obligations);
let may_apply = infcx.predicate_may_hold(&traits::Obligation::new(
cause.clone(),
param_env,
trait_ref.to_predicate(),
));
if !may_apply {
return
}
self.cx.generated_synthetics.borrow_mut()
.insert((def_id, trait_def_id));
let trait_ = hir::TraitRef {
path: get_path_for_type(infcx.tcx,
trait_def_id,
hir::def::Def::Trait),
ref_id: ast::DUMMY_NODE_ID,
};
let provided_trait_methods =
infcx.tcx.provided_trait_methods(trait_def_id)
.into_iter()
.map(|meth| meth.ident.to_string())
.collect();
let ty = self.cx.get_real_ty(def_id, def_ctor, &real_name, generics);
let predicates = infcx.tcx.predicates_of(impl_def_id);
impls.push(Item {
source: infcx.tcx.def_span(impl_def_id).clean(self.cx),
name: None,
attrs: Default::default(),
visibility: None,
def_id: self.cx.next_def_id(impl_def_id.krate),
stability: None,
deprecation: None,
inner: ImplItem(Impl {
unsafety: hir::Unsafety::Normal,
generics: (t_generics, &predicates).clean(self.cx),
provided_trait_methods,
trait_: Some(trait_.clean(self.cx)),
for_: ty.clean(self.cx),
items: infcx.tcx.associated_items(impl_def_id)
.collect::<Vec<_>>()
.clean(self.cx),
polarity: None,
synthetic: false,
blanket_impl: Some(infcx.tcx.type_of(impl_def_id)
.clean(self.cx)),
}),
});
}
});
});
}
}
impls
}
}
// Copyright 2018 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.
use core::DocContext;
use super::*;
pub fn get_def_from_def_id<F>(cx: &DocContext,
def_id: DefId,
callback: &F,
) -> Vec<Item>
where F: Fn(& dyn Fn(DefId) -> Def) -> Vec<Item> {
let ty = cx.tcx.type_of(def_id);
match ty.sty {
ty::TyAdt(adt, _) => callback(&match adt.adt_kind() {
AdtKind::Struct => Def::Struct,
AdtKind::Enum => Def::Enum,
AdtKind::Union => Def::Union,
}),
ty::TyInt(_) |
ty::TyUint(_) |
ty::TyFloat(_) |
ty::TyStr |
ty::TyBool |
ty::TyChar => callback(&move |_: DefId| {
match ty.sty {
ty::TyInt(x) => Def::PrimTy(hir::TyInt(x)),
ty::TyUint(x) => Def::PrimTy(hir::TyUint(x)),
ty::TyFloat(x) => Def::PrimTy(hir::TyFloat(x)),
ty::TyStr => Def::PrimTy(hir::TyStr),
ty::TyBool => Def::PrimTy(hir::TyBool),
ty::TyChar => Def::PrimTy(hir::TyChar),
_ => unreachable!(),
}
}),
_ => {
debug!("Unexpected type {:?}", def_id);
Vec::new()
}
}
}
pub fn get_def_from_node_id<F>(cx: &DocContext,
id: ast::NodeId,
name: String,
callback: &F,
) -> Vec<Item>
where F: Fn(& dyn Fn(DefId) -> Def, String) -> Vec<Item> {
let item = &cx.tcx.hir.expect_item(id).node;
callback(&match *item {
hir::ItemKind::Struct(_, _) => Def::Struct,
hir::ItemKind::Union(_, _) => Def::Union,
hir::ItemKind::Enum(_, _) => Def::Enum,
_ => panic!("Unexpected type {:?} {:?}", item, id),
}, name)
}
......@@ -25,7 +25,13 @@
use core::{DocContext, DocAccessLevels};
use doctree;
use clean::{self, GetDefId, ToSource, get_auto_traits_with_def_id};
use clean::{
self,
GetDefId,
ToSource,
get_auto_traits_with_def_id,
get_blanket_impls_with_def_id,
};
use super::Clean;
......@@ -168,7 +174,7 @@ pub fn record_extern_fqn(cx: &DocContext, did: DefId, kind: clean::TypeKind) {
}
});
let fqn = if let clean::TypeKind::Macro = kind {
vec![crate_name, relative.last().unwrap()]
vec![crate_name, relative.last().expect("relative was empty")]
} else {
once(crate_name).chain(relative).collect()
};
......@@ -274,11 +280,14 @@ pub fn build_impls(cx: &DocContext, did: DefId, auto_traits: bool) -> Vec<clean:
if auto_traits {
let auto_impls = get_auto_traits_with_def_id(cx, did);
let mut renderinfo = cx.renderinfo.borrow_mut();
let new_impls: Vec<clean::Item> = auto_impls.into_iter()
.filter(|i| renderinfo.inlined.insert(i.def_id)).collect();
{
let mut renderinfo = cx.renderinfo.borrow_mut();
let new_impls: Vec<clean::Item> = auto_impls.into_iter()
.filter(|i| renderinfo.inlined.insert(i.def_id)).collect();
impls.extend(new_impls);
impls.extend(new_impls);
}
impls.extend(get_blanket_impls_with_def_id(cx, did));
}
// If this is the first time we've inlined something from another crate, then
......@@ -336,10 +345,13 @@ pub fn build_impls(cx: &DocContext, did: DefId, auto_traits: bool) -> Vec<clean:
build_impl(cx, def_id, &mut impls);
let auto_impls = get_auto_traits_with_def_id(cx, def_id);
let blanket_impls = get_blanket_impls_with_def_id(cx, def_id);
let mut renderinfo = cx.renderinfo.borrow_mut();
let new_impls: Vec<clean::Item> = auto_impls.into_iter()
.filter(|i| renderinfo.inlined.insert(i.def_id)).collect();
.chain(blanket_impls.into_iter())
.filter(|i| renderinfo.inlined.insert(i.def_id))
.collect();
impls.extend(new_impls);
}
......
......@@ -37,8 +37,7 @@
use rustc::mir::interpret::GlobalId;
use rustc::hir::{self, GenericArg, HirVec};
use rustc::hir::def::{self, Def, CtorKind};
use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc::hir::def_id::DefIndexAddressSpace;
use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc::hir::map::Node;
use rustc::ty::subst::Substs;
use rustc::ty::{self, TyCtxt, Region, RegionVid, Ty, AdtKind};
......@@ -73,11 +72,15 @@
pub mod cfg;
mod simplify;
mod auto_trait;
mod blanket_impl;
pub mod def_ctor;
use self::cfg::Cfg;
use self::auto_trait::AutoTraitFinder;
use self::blanket_impl::BlanketImplFinder;
thread_local!(static MAX_DEF_ID: RefCell<FxHashMap<CrateNum, DefId>> = RefCell::new(FxHashMap()));
thread_local!(pub static MAX_DEF_ID: RefCell<FxHashMap<CrateNum, DefId>> =
RefCell::new(FxHashMap()));
const FN_OUTPUT_NAME: &'static str = "Output";
......@@ -569,7 +572,7 @@ pub struct Module {
impl Clean<Item> for doctree::Module {
fn clean(&self, cx: &DocContext) -> Item {
let name = if self.name.is_some() {
self.name.unwrap().clean(cx)
self.name.expect("No name provided").clean(cx)
} else {
"".to_string()
};
......@@ -1064,7 +1067,7 @@ fn span_of_attrs(attrs: &Attributes) -> syntax_pos::Span {
return DUMMY_SP;
}
let start = attrs.doc_strings[0].span();
let end = attrs.doc_strings.last().unwrap().span();
let end = attrs.doc_strings.last().expect("No doc strings provided").span();
start.to(end)
}
......@@ -1728,7 +1731,7 @@ fn clean(&self, _: &DocContext) -> Lifetime {
hir::GenericBound::Outlives(lt) => lt,
_ => panic!(),
});
let name = bounds.next().unwrap().name.ident();
let name = bounds.next().expect("no more bounds").name.ident();
let mut s = format!("{}: {}", self.name.ident(), name);
for bound in bounds {
s.push_str(&format!(" + {}", bound.name.ident()));
......@@ -1841,8 +1844,8 @@ impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<ty::Region<'tcx>, ty:
fn clean(&self, cx: &DocContext) -> WherePredicate {
let ty::OutlivesPredicate(ref a, ref b) = *self;
WherePredicate::RegionPredicate {
lifetime: a.clean(cx).unwrap(),
bounds: vec![GenericBound::Outlives(b.clean(cx).unwrap())]
lifetime: a.clean(cx).expect("failed to clean lifetime"),
bounds: vec![GenericBound::Outlives(b.clean(cx).expect("failed to clean bounds"))]
}
}
}
......@@ -1853,7 +1856,7 @@ fn clean(&self, cx: &DocContext) -> WherePredicate {
WherePredicate::BoundPredicate {
ty: ty.clean(cx),
bounds: vec![GenericBound::Outlives(lt.clean(cx).unwrap())]
bounds: vec![GenericBound::Outlives(lt.clean(cx).expect("failed to clean lifetimes"))]
}
}
}
......@@ -1947,7 +1950,7 @@ fn clean(&self, cx: &DocContext) -> GenericParamDef {
hir::GenericBound::Outlives(lt) => lt,
_ => panic!(),
});
let name = bounds.next().unwrap().name.ident();
let name = bounds.next().expect("no more bounds").name.ident();
let mut s = format!("{}: {}", self.name.ident(), name);
for bound in bounds {
s.push_str(&format!(" + {}", bound.name.ident()));
......@@ -2933,7 +2936,7 @@ fn clean(&self, cx: &DocContext) -> Type {
};
if let Some(&hir::ItemKind::Ty(ref ty, ref generics)) = alias {
let provided_params = &path.segments.last().unwrap();
let provided_params = &path.segments.last().expect("segments were empty");
let mut ty_substs = FxHashMap();
let mut lt_substs = FxHashMap();
provided_params.with_generic_args(|generic_args| {
......@@ -3006,7 +3009,7 @@ fn clean(&self, cx: &DocContext) -> Type {
segments: segments.into(),
};
Type::QPath {
name: p.segments.last().unwrap().ident.name.clean(cx),
name: p.segments.last().expect("segments were empty").ident.name.clean(cx),
self_type: box qself.clean(cx),
trait_: box resolve_type(cx, trait_path.clean(cx), self.id)
}
......@@ -3062,7 +3065,7 @@ fn clean(&self, cx: &DocContext) -> Type {
ty::TyStr => Primitive(PrimitiveType::Str),
ty::TySlice(ty) => Slice(box ty.clean(cx)),
ty::TyArray(ty, n) => {
let mut n = cx.tcx.lift(&n).unwrap();
let mut n = cx.tcx.lift(&n).expect("array lift failed");
if let ConstValue::Unevaluated(def_id, substs) = n.val {
let param_env = cx.tcx.param_env(def_id);
let cid = GlobalId {
......@@ -3084,7 +3087,7 @@ fn clean(&self, cx: &DocContext) -> Type {
},
ty::TyFnDef(..) |
ty::TyFnPtr(_) => {
let ty = cx.tcx.lift(self).unwrap();
let ty = cx.tcx.lift(self).expect("TyFnPtr lift failed");
let sig = ty.fn_sig(cx.tcx);
BareFunction(box BareFunctionDecl {
unsafety: sig.unsafety(),
......@@ -3175,7 +3178,7 @@ fn clean(&self, cx: &DocContext) -> Type {
// Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
// by looking up the projections associated with the def_id.
let predicates_of = cx.tcx.predicates_of(def_id);
let substs = cx.tcx.lift(&substs).unwrap();
let substs = cx.tcx.lift(&substs).expect("TyAnon lift failed");
let bounds = predicates_of.instantiate(cx.tcx, substs);
let mut regions = vec![];
let mut has_sized = false;
......@@ -3314,6 +3317,7 @@ impl Clean<Vec<Item>> for doctree::Struct {
fn clean(&self, cx: &DocContext) -> Vec<Item> {
let name = self.name.clean(cx);
let mut ret = get_auto_traits_with_node_id(cx, self.id, name.clone());
ret.extend(get_blanket_impls_with_node_id(cx, self.id, name.clone()));
*cx.current_item_name.borrow_mut() = Some(self.name);
ret.push(Item {
......@@ -3340,6 +3344,7 @@ impl Clean<Vec<Item>> for doctree::Union {
fn clean(&self, cx: &DocContext) -> Vec<Item> {
let name = self.name.clean(cx);
let mut ret = get_auto_traits_with_node_id(cx, self.id, name.clone());
ret.extend(get_blanket_impls_with_node_id(cx, self.id, name.clone()));
*cx.current_item_name.borrow_mut() = Some(self.name);
ret.push(Item {
......@@ -3393,6 +3398,7 @@ impl Clean<Vec<Item>> for doctree::Enum {
fn clean(&self, cx: &DocContext) -> Vec<Item> {
let name = self.name.clean(cx);
let mut ret = get_auto_traits_with_node_id(cx, self.id, name.clone());
ret.extend(get_blanket_impls_with_node_id(cx, self.id, name.clone()));
*cx.current_item_name.borrow_mut() = Some(self.name);
ret.push(Item {
......@@ -3545,7 +3551,7 @@ pub struct Path {
impl Path {
pub fn last_name(&self) -> &str {
self.segments.last().unwrap().name.as_str()
self.segments.last().expect("segments were empty").name.as_str()
}
}
......@@ -3875,6 +3881,17 @@ pub fn get_auto_traits_with_def_id(cx: &DocContext, id: DefId) -> Vec<Item> {
finder.get_with_def_id(id)
}
pub fn get_blanket_impls_with_node_id(cx: &DocContext, id: ast::NodeId, name: String) -> Vec<Item> {
let finder = BlanketImplFinder::new(cx);
finder.get_with_node_id(id, name)
}
pub fn get_blanket_impls_with_def_id(cx: &DocContext, id: DefId) -> Vec<Item> {
let finder = BlanketImplFinder::new(cx);
finder.get_with_def_id(id)
}
fn get_name_if_possible(cx: &DocContext, node: NodeId) -> Option<Name> {
match cx.tcx.hir.get(node) {
Node::NodeItem(_) |
......@@ -4196,7 +4213,7 @@ fn print_const(cx: &DocContext, n: &ty::Const) -> String {
},
_ => {
let mut s = String::new();
::rustc::mir::fmt_const_val(&mut s, n).unwrap();
::rustc::mir::fmt_const_val(&mut s, n).expect("fmt_const_val failed");
// array lengths are obviously usize
if s.ends_with("usize") {
let n = s.len() - "usize".len();
......@@ -4257,7 +4274,8 @@ fn register_def(cx: &DocContext, def: Def) -> DefId {
Def::TyForeign(i) => (i, TypeKind::Foreign),
Def::Const(i) => (i, TypeKind::Const),
Def::Static(i, _) => (i, TypeKind::Static),
Def::Variant(i) => (cx.tcx.parent_def_id(i).unwrap(), TypeKind::Enum),
Def::Variant(i) => (cx.tcx.parent_def_id(i).expect("cannot get parent def id"),
TypeKind::Enum),
Def::Macro(i, _) => (i, TypeKind::Macro),
Def::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait),
Def::SelfTy(_, Some(impl_def_id)) => {
......@@ -4486,7 +4504,7 @@ pub fn path_to_def(tcx: &TyCtxt, path: &[&str]) -> Option<DefId> {
}
}
fn get_path_for_type<F>(tcx: TyCtxt, def_id: DefId, def_ctor: F) -> hir::Path
pub fn get_path_for_type<F>(tcx: TyCtxt, def_id: DefId, def_ctor: F) -> hir::Path
where F: Fn(DefId) -> Def {
struct AbsolutePathBuffer {
names: Vec<String>,
......
......@@ -96,7 +96,7 @@ pub fn where_clauses(cx: &DocContext, clauses: Vec<WP>) -> Vec<WP> {
if !trait_is_same_or_supertrait(cx, did, trait_did) {
return false
}
let last = path.segments.last_mut().unwrap();
let last = path.segments.last_mut().expect("segments were empty");
match last.args {
PP::AngleBracketed { ref mut bindings, .. } => {
bindings.push(clean::TypeBinding {
......
......@@ -11,8 +11,10 @@
use rustc_lint;
use rustc_driver::{self, driver, target_features, abort_on_err};
use rustc::session::{self, config};
use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
use rustc::hir::def_id::{DefId, DefIndex, DefIndexAddressSpace, CrateNum, LOCAL_CRATE};
use rustc::hir::def::Def;
use rustc::hir::{self, HirVec};
use rustc::middle::cstore::CrateStore;
use rustc::middle::privacy::AccessLevels;
use rustc::ty::{self, TyCtxt, AllArenas};
use rustc::hir::map as hir_map;
......@@ -24,11 +26,14 @@
use rustc_metadata::cstore::CStore;
use rustc_target::spec::TargetTriple;
use syntax::ast::{Name, NodeId};
use syntax::ast::{self, Ident, Name, NodeId};
use syntax::codemap;
use syntax::edition::Edition;
use syntax::feature_gate::UnstableFeatures;
use syntax::json::JsonEmitter;
use syntax::ptr::P;
use syntax::symbol::keywords;
use syntax_pos::DUMMY_SP;
use errors;
use errors::emitter::{Emitter, EmitterWriter};
......@@ -40,7 +45,7 @@
use visit_ast::RustdocVisitor;
use clean;
use clean::Clean;
use clean::{get_path_for_type, Clean, MAX_DEF_ID};
use html::render::RenderInfo;
pub use rustc::session::config::{Input, Options, CodegenOptions};
......@@ -106,6 +111,140 @@ pub fn enter_alias<F, R>(&self,
*self.lt_substs.borrow_mut() = old_lts;
r
}
// This is an ugly hack, but it's the simplest way to handle synthetic impls without greatly
// refactoring either librustdoc or librustc. In particular, allowing new DefIds to be
// registered after the AST is constructed would require storing the defid mapping in a
// RefCell, decreasing the performance for normal compilation for very little gain.
//
// Instead, we construct 'fake' def ids, which start immediately after the last DefId in
// DefIndexAddressSpace::Low. In the Debug impl for clean::Item, we explicitly check for fake
// def ids, as we'll end up with a panic if we use the DefId Debug impl for fake DefIds
pub fn next_def_id(&self, crate_num: CrateNum) -> DefId {
let start_def_id = {
let next_id = if crate_num == LOCAL_CRATE {
self.tcx
.hir
.definitions()
.def_path_table()
.next_id(DefIndexAddressSpace::Low)
} else {
self.cstore
.def_path_table(crate_num)
.next_id(DefIndexAddressSpace::Low)
};
DefId {
krate: crate_num,
index: next_id,
}
};
let mut fake_ids = self.fake_def_ids.borrow_mut();
let def_id = fake_ids.entry(crate_num).or_insert(start_def_id).clone();
fake_ids.insert(
crate_num,
DefId {
krate: crate_num,
index: DefIndex::from_array_index(
def_id.index.as_array_index() + 1,
def_id.index.address_space(),
),
},
);
MAX_DEF_ID.with(|m| {
m.borrow_mut()
.entry(def_id.krate.clone())
.or_insert(start_def_id);
});
self.all_fake_def_ids.borrow_mut().insert(def_id);
def_id.clone()
}
pub fn get_real_ty<F>(&self,
def_id: DefId,
def_ctor: &F,
real_name: &Option<Ident>,
generics: &ty::Generics,
) -> hir::Ty
where F: Fn(DefId) -> Def {
let path = get_path_for_type(self.tcx, def_id, def_ctor);
let mut segments = path.segments.into_vec();
let last = segments.pop().expect("segments were empty");
segments.push(hir::PathSegment::new(
real_name.unwrap_or(last.ident),
self.generics_to_path_params(generics.clone()),
false,
));
let new_path = hir::Path {
span: path.span,
def: path.def,
segments: HirVec::from_vec(segments),
};
hir::Ty {
id: ast::DUMMY_NODE_ID,
node: hir::TyKind::Path(hir::QPath::Resolved(None, P(new_path))),
span: DUMMY_SP,
hir_id: hir::DUMMY_HIR_ID,
}
}
pub fn generics_to_path_params(&self, generics: ty::Generics) -> hir::GenericArgs {
let mut args = vec![];
for param in generics.params.iter() {
match param.kind {
ty::GenericParamDefKind::Lifetime => {
let name = if param.name == "" {
hir::ParamName::Plain(keywords::StaticLifetime.ident())
} else {
hir::ParamName::Plain(ast::Ident::from_interned_str(param.name))
};
args.push(hir::GenericArg::Lifetime(hir::Lifetime {
id: ast::DUMMY_NODE_ID,
span: DUMMY_SP,
name: hir::LifetimeName::Param(name),
}));
}
ty::GenericParamDefKind::Type {..} => {
args.push(hir::GenericArg::Type(self.ty_param_to_ty(param.clone())));
}
}
}
hir::GenericArgs {
args: HirVec::from_vec(args),
bindings: HirVec::new(),
parenthesized: false,
}
}
pub fn ty_param_to_ty(&self, param: ty::GenericParamDef) -> hir::Ty {
debug!("ty_param_to_ty({:?}) {:?}", param, param.def_id);
hir::Ty {
id: ast::DUMMY_NODE_ID,
node: hir::TyKind::Path(hir::QPath::Resolved(
None,
P(hir::Path {
span: DUMMY_SP,
def: Def::TyParam(param.def_id),
segments: HirVec::from_vec(vec![
hir::PathSegment::from_ident(Ident::from_interned_str(param.name))
]),
}),
)),
span: DUMMY_SP,
hir_id: hir::DUMMY_HIR_ID,
}
}
}
pub trait DocAccessLevels {
......
......@@ -17,6 +17,7 @@
// @has foo/struct.Foo.html '//h3[@id="impl-ToString"]//code' 'impl<T> ToString for T'
pub struct Foo;
// @has foo/struct.Foo.html '//div[@class="sidebar-links"]/a[@href="#impl-ToString"]' 'ToString'
impl fmt::Display for Foo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
......
// Copyright 2018 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.
#![crate_name = "foo"]
// we need to reexport something from libstd so that `all_trait_implementations` is called.
pub use std::string::String;
include!("primitive/primitive-generic-impl.rs");
// @has foo/primitive.i32.html '//h3[@id="impl-ToString"]//code' 'impl<T> ToString for T'
// Copyright 2018 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.
#[doc(primitive = "i32")]
/// Some useless docs, wouhou!
mod i32 {}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册