use std::sync::Arc;
use std::{slice, vec};
+use arrayvec::ArrayVec;
use rustc_ast::attr;
use rustc_ast::util::comments::beautify_doc_string;
use rustc_ast::{self as ast, AttrStyle};
-use rustc_ast::{FloatTy, IntTy, UintTy};
use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_feature::UnstableFeatures;
use rustc_hir as hir;
-use rustc_hir::def::Res;
-use rustc_hir::def_id::{CrateNum, DefId};
+use rustc_hir::def::{CtorKind, Res};
+use rustc_hir::def_id::{CrateNum, DefId, DefIndex};
use rustc_hir::lang_items::LangItem;
-use rustc_hir::Mutability;
+use rustc_hir::{BodyId, Mutability};
use rustc_index::vec::IndexVec;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{self, TyCtxt};
use rustc_session::Session;
use rustc_span::hygiene::MacroKind;
use rustc_span::source_map::DUMMY_SP;
use rustc_span::{self, FileName, Loc};
use rustc_target::abi::VariantIdx;
use rustc_target::spec::abi::Abi;
-use smallvec::{smallvec, SmallVec};
use crate::clean::cfg::Cfg;
use crate::clean::external_path;
use crate::clean::types::Type::{QPath, ResolvedPath};
use crate::clean::Clean;
use crate::core::DocContext;
-use crate::doctree;
-use crate::formats::cache::cache;
+use crate::formats::cache::Cache;
use crate::formats::item_type::ItemType;
use crate::html::render::cache::ExternalLocation;
use self::SelfTy::*;
use self::Type::*;
-thread_local!(crate static MAX_DEF_ID: RefCell<FxHashMap<CrateNum, DefId>> = Default::default());
+thread_local!(crate static MAX_DEF_IDX: RefCell<FxHashMap<CrateNum, DefIndex>> = Default::default());
#[derive(Clone, Debug)]
crate struct Crate {
crate name: Symbol,
- crate version: Option<String>,
crate src: FileName,
crate module: Option<Item>,
crate externs: Vec<(CrateNum, ExternalCrate)>,
crate primitives: Vec<(DefId, PrimitiveType)>,
// These are later on moved into `CACHEKEY`, leaving the map empty.
// Only here so that they can be filtered through the rustdoc passes.
- crate external_traits: Rc<RefCell<FxHashMap<DefId, Trait>>>,
- crate masked_crates: FxHashSet<CrateNum>,
+ crate external_traits: Rc<RefCell<FxHashMap<DefId, TraitWithExtraInfo>>>,
crate collapsed: bool,
}
+/// This struct is used to wrap additional information added by rustdoc on a `trait` item.
+#[derive(Clone, Debug)]
+crate struct TraitWithExtraInfo {
+ crate trait_: Trait,
+ crate is_spotlight: bool,
+}
+
#[derive(Clone, Debug)]
crate struct ExternalCrate {
crate name: Symbol,
crate source: Span,
/// Not everything has a name. E.g., impls
crate name: Option<Symbol>,
- crate attrs: Attributes,
+ crate attrs: Box<Attributes>,
crate visibility: Visibility,
- crate kind: ItemKind,
+ crate kind: Box<ItemKind>,
crate def_id: DefId,
}
+// `Item` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+rustc_data_structures::static_assert_size!(Item, 48);
+
impl fmt::Debug for Item {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let def_id: &dyn fmt::Debug = if self.is_fake() { &"**FAKE**" } else { &self.def_id };
/// Finds the `doc` attribute as a NameValue and returns the corresponding
/// value found.
- crate fn doc_value(&self) -> Option<&str> {
+ crate fn doc_value(&self) -> Option<String> {
self.attrs.doc_value()
}
hir_id: hir::HirId,
name: Option<Symbol>,
kind: ItemKind,
- cx: &DocContext<'_>,
+ cx: &mut DocContext<'_>,
) -> Item {
Item::from_def_id_and_parts(cx.tcx.hir().local_def_id(hir_id).to_def_id(), name, kind, cx)
}
def_id: DefId,
name: Option<Symbol>,
kind: ItemKind,
- cx: &DocContext<'_>,
+ cx: &mut DocContext<'_>,
+ ) -> Item {
+ Self::from_def_id_and_attrs_and_parts(
+ def_id,
+ name,
+ kind,
+ box cx.tcx.get_attrs(def_id).clean(cx),
+ cx,
+ )
+ }
+
+ pub fn from_def_id_and_attrs_and_parts(
+ def_id: DefId,
+ name: Option<Symbol>,
+ kind: ItemKind,
+ attrs: Box<Attributes>,
+ cx: &mut DocContext<'_>,
) -> Item {
debug!("name={:?}, def_id={:?}", name, def_id);
Item {
def_id,
- kind,
+ kind: box kind,
name,
source: source.clean(cx),
- attrs: cx.tcx.get_attrs(def_id).clean(cx),
+ attrs,
visibility: cx.tcx.visibility(def_id).clean(cx),
}
}
self.attrs.collapsed_doc_value()
}
- crate fn links(&self) -> Vec<RenderedLink> {
- self.attrs.links(&self.def_id.krate)
+ crate fn links(&self, cache: &Cache) -> Vec<RenderedLink> {
+ self.attrs.links(self.def_id.krate, cache)
}
crate fn is_crate(&self) -> bool {
- match self.kind {
+ matches!(
+ *self.kind,
StrippedItem(box ModuleItem(Module { is_crate: true, .. }))
- | ModuleItem(Module { is_crate: true, .. }) => true,
- _ => false,
- }
+ | ModuleItem(Module { is_crate: true, .. })
+ )
}
crate fn is_mod(&self) -> bool {
self.type_() == ItemType::Module
self.type_() == ItemType::Keyword
}
crate fn is_stripped(&self) -> bool {
- match self.kind {
+ match *self.kind {
StrippedItem(..) => true,
ImportItem(ref i) => !i.should_be_displayed,
_ => false,
}
}
crate fn has_stripped_fields(&self) -> Option<bool> {
- match self.kind {
+ match *self.kind {
StructItem(ref _struct) => Some(_struct.fields_stripped),
UnionItem(ref union) => Some(union.fields_stripped),
- VariantItem(Variant { kind: VariantKind::Struct(ref vstruct) }) => {
- Some(vstruct.fields_stripped)
- }
+ VariantItem(Variant::Struct(ref vstruct)) => Some(vstruct.fields_stripped),
_ => None,
}
}
}
crate fn is_default(&self) -> bool {
- match self.kind {
+ match *self.kind {
ItemKind::MethodItem(_, Some(defaultness)) => {
defaultness.has_value() && !defaultness.is_final()
}
}
}
- /// See comments on next_def_id
+ /// See the documentation for [`next_def_id()`].
+ ///
+ /// [`next_def_id()`]: DocContext::next_def_id()
crate fn is_fake(&self) -> bool {
- MAX_DEF_ID.with(|m| {
- m.borrow().get(&self.def_id.krate).map(|id| self.def_id >= *id).unwrap_or(false)
+ MAX_DEF_IDX.with(|m| {
+ m.borrow().get(&self.def_id.krate).map(|&idx| idx <= self.def_id.index).unwrap_or(false)
})
}
}
#[derive(Clone, Debug)]
crate enum ItemKind {
- ExternCrateItem(Symbol, Option<Symbol>),
+ ExternCrateItem {
+ /// The crate's name, *not* the name it's imported as.
+ src: Option<Symbol>,
+ },
ImportItem(Import),
StructItem(Struct),
UnionItem(Union),
ProcMacroItem(ProcMacro),
PrimitiveItem(PrimitiveType),
AssocConstItem(Type, Option<String>),
+ /// An associated item in a trait or trait impl.
+ ///
+ /// The bounds may be non-empty if there is a `where` clause.
+ /// The `Option<Type>` is the default concrete type (e.g. `trait Trait { type Target = usize; }`)
AssocTypeItem(Vec<GenericBound>, Option<Type>),
/// An item that has been stripped by a rustdoc pass
StrippedItem(Box<ItemKind>),
match self {
StructItem(s) => s.fields.iter(),
UnionItem(u) => u.fields.iter(),
- VariantItem(Variant { kind: VariantKind::Struct(v) }) => v.fields.iter(),
+ VariantItem(Variant::Struct(v)) => v.fields.iter(),
EnumItem(e) => e.variants.iter(),
TraitItem(t) => t.items.iter(),
ImplItem(i) => i.items.iter(),
ModuleItem(m) => m.items.iter(),
- ExternCrateItem(_, _)
+ ExternCrateItem { .. }
| ImportItem(_)
| FunctionItem(_)
| TypedefItem(_, _)
}
crate fn is_type_alias(&self) -> bool {
- match *self {
- ItemKind::TypedefItem(_, _) | ItemKind::AssocTypeItem(_, _) => true,
- _ => false,
- }
+ matches!(self, ItemKind::TypedefItem(..) | ItemKind::AssocTypeItem(..))
}
}
crate trait NestedAttributesExt {
/// Returns `true` if the attribute list contains a specific `Word`
fn has_word(self, word: Symbol) -> bool;
+ fn get_word_attr(self, word: Symbol) -> Option<ast::NestedMetaItem>;
}
-impl<I: IntoIterator<Item = ast::NestedMetaItem>> NestedAttributesExt for I {
+impl<I: Iterator<Item = ast::NestedMetaItem> + IntoIterator<Item = ast::NestedMetaItem>>
+ NestedAttributesExt for I
+{
fn has_word(self, word: Symbol) -> bool {
self.into_iter().any(|attr| attr.is_word() && attr.has_name(word))
}
+
+ fn get_word_attr(mut self, word: Symbol) -> Option<ast::NestedMetaItem> {
+ self.find(|attr| attr.is_word() && attr.has_name(word))
+ }
}
/// A portion of documentation, extracted from a `#[doc]` attribute.
/// This allows distinguishing between the original documentation and a pub re-export.
/// If it is `None`, the item was not re-exported.
crate parent_module: Option<DefId>,
- crate doc: String,
+ crate doc: Symbol,
crate kind: DocFragmentKind,
+ crate need_backline: bool,
+ crate indent: usize,
}
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
crate enum DocFragmentKind {
/// A doc fragment created from a `///` or `//!` doc comment.
SugaredDoc,
RawDoc,
/// A doc fragment created from a `#[doc(include="filename")]` attribute. Contains both the
/// given filename and the file contents.
- Include { filename: String },
+ Include { filename: Symbol },
+}
+
+// The goal of this function is to apply the `DocFragment` transformations that are required when
+// transforming into the final markdown. So the transformations in here are:
+//
+// * Applying the computed indent to each lines in each doc fragment (a `DocFragment` can contain
+// multiple lines in case of `#[doc = ""]`).
+// * Adding backlines between `DocFragment`s and adding an extra one if required (stored in the
+// `need_backline` field).
+fn add_doc_fragment(out: &mut String, frag: &DocFragment) {
+ let s = frag.doc.as_str();
+ let mut iter = s.lines().peekable();
+ while let Some(line) = iter.next() {
+ if line.chars().any(|c| !c.is_whitespace()) {
+ assert!(line.len() >= frag.indent);
+ out.push_str(&line[frag.indent..]);
+ } else {
+ out.push_str(line);
+ }
+ if iter.peek().is_some() {
+ out.push('\n');
+ }
+ }
+ if frag.need_backline {
+ out.push('\n');
+ }
}
impl<'a> FromIterator<&'a DocFragment> for String {
where
T: IntoIterator<Item = &'a DocFragment>,
{
+ let mut prev_kind: Option<DocFragmentKind> = None;
iter.into_iter().fold(String::new(), |mut acc, frag| {
- if !acc.is_empty() {
+ if !acc.is_empty()
+ && prev_kind
+ .take()
+ .map(|p| matches!(p, DocFragmentKind::Include { .. }) && p != frag.kind)
+ .unwrap_or(false)
+ {
acc.push('\n');
}
- acc.push_str(&frag.doc);
+ add_doc_fragment(&mut acc, &frag);
+ prev_kind = Some(frag.kind);
acc
})
}
/// Reads a `MetaItem` from within an attribute, looks for whether it is a
/// `#[doc(include="file")]`, and returns the filename and contents of the file as loaded from
/// its expansion.
- crate fn extract_include(mi: &ast::MetaItem) -> Option<(String, String)> {
+ crate fn extract_include(mi: &ast::MetaItem) -> Option<(Symbol, Symbol)> {
mi.meta_item_list().and_then(|list| {
for meta in list {
if meta.has_name(sym::include) {
// `#[doc(include(file="filename", contents="file contents")]` so we need to
// look for that instead
return meta.meta_item_list().and_then(|list| {
- let mut filename: Option<String> = None;
- let mut contents: Option<String> = None;
+ let mut filename: Option<Symbol> = None;
+ let mut contents: Option<Symbol> = None;
for it in list {
if it.has_name(sym::file) {
if let Some(name) = it.value_str() {
- filename = Some(name.to_string());
+ filename = Some(name);
}
} else if it.has_name(sym::contents) {
if let Some(docs) = it.value_str() {
- contents = Some(docs.to_string());
+ contents = Some(docs);
}
}
}
attrs: &[ast::Attribute],
additional_attrs: Option<(&[ast::Attribute], DefId)>,
) -> Attributes {
- let mut doc_strings = vec![];
+ let mut doc_strings: Vec<DocFragment> = vec![];
let mut sp = None;
let mut cfg = Cfg::True;
let mut doc_line = 0;
+ fn update_need_backline(doc_strings: &mut Vec<DocFragment>, frag: &DocFragment) {
+ if let Some(prev) = doc_strings.last_mut() {
+ if matches!(prev.kind, DocFragmentKind::Include { .. })
+ || prev.kind != frag.kind
+ || prev.parent_module != frag.parent_module
+ {
+ // add a newline for extra padding between segments
+ prev.need_backline = prev.kind == DocFragmentKind::SugaredDoc
+ || prev.kind == DocFragmentKind::RawDoc
+ } else {
+ prev.need_backline = true;
+ }
+ }
+ }
+
let clean_attr = |(attr, parent_module): (&ast::Attribute, _)| {
if let Some(value) = attr.doc_str() {
trace!("got doc_str={:?}", value);
- let value = beautify_doc_string(value).to_string();
+ let value = beautify_doc_string(value);
let kind = if attr.is_doc_comment() {
DocFragmentKind::SugaredDoc
} else {
};
let line = doc_line;
- doc_line += value.lines().count();
- doc_strings.push(DocFragment {
+ doc_line += value.as_str().lines().count();
+ let frag = DocFragment {
line,
span: attr.span,
doc: value,
kind,
parent_module,
- });
+ need_backline: false,
+ indent: 0,
+ };
+
+ update_need_backline(&mut doc_strings, &frag);
+
+ doc_strings.push(frag);
if sp.is_none() {
sp = Some(attr.span);
} else if let Some((filename, contents)) = Attributes::extract_include(&mi)
{
let line = doc_line;
- doc_line += contents.lines().count();
- doc_strings.push(DocFragment {
+ doc_line += contents.as_str().lines().count();
+ let frag = DocFragment {
line,
span: attr.span,
doc: contents,
kind: DocFragmentKind::Include { filename },
- parent_module: parent_module,
- });
+ parent_module,
+ need_backline: false,
+ indent: 0,
+ };
+ update_need_backline(&mut doc_strings, &frag);
+ doc_strings.push(frag);
}
}
}
/// Finds the `doc` attribute as a NameValue and returns the corresponding
/// value found.
- crate fn doc_value(&self) -> Option<&str> {
- self.doc_strings.first().map(|s| s.doc.as_str())
+ crate fn doc_value(&self) -> Option<String> {
+ let mut iter = self.doc_strings.iter();
+
+ let ori = iter.next()?;
+ let mut out = String::new();
+ add_doc_fragment(&mut out, &ori);
+ while let Some(new_frag) = iter.next() {
+ if matches!(ori.kind, DocFragmentKind::Include { .. })
+ || new_frag.kind != ori.kind
+ || new_frag.parent_module != ori.parent_module
+ {
+ break;
+ }
+ add_doc_fragment(&mut out, &new_frag);
+ }
+ if out.is_empty() { None } else { Some(out) }
+ }
+
+ /// Return the doc-comments on this item, grouped by the module they came from.
+ ///
+ /// The module can be different if this is a re-export with added documentation.
+ crate fn collapsed_doc_value_by_module_level(&self) -> FxHashMap<Option<DefId>, String> {
+ let mut ret = FxHashMap::default();
+
+ for new_frag in self.doc_strings.iter() {
+ let out = ret.entry(new_frag.parent_module).or_default();
+ add_doc_fragment(out, &new_frag);
+ }
+ ret
}
/// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
/// with newlines.
crate fn collapsed_doc_value(&self) -> Option<String> {
- if !self.doc_strings.is_empty() { Some(self.doc_strings.iter().collect()) } else { None }
+ if self.doc_strings.is_empty() { None } else { Some(self.doc_strings.iter().collect()) }
}
/// Gets links as a vector
///
/// Cache must be populated before call
- crate fn links(&self, krate: &CrateNum) -> Vec<RenderedLink> {
+ crate fn links(&self, krate: CrateNum, cache: &Cache) -> Vec<RenderedLink> {
use crate::html::format::href;
use crate::html::render::CURRENT_DEPTH;
.filter_map(|ItemLink { link: s, link_text, did, fragment }| {
match *did {
Some(did) => {
- if let Some((mut href, ..)) = href(did) {
+ if let Some((mut href, ..)) = href(did, cache) {
if let Some(ref fragment) = *fragment {
- href.push_str("#");
+ href.push('#');
href.push_str(fragment);
}
Some(RenderedLink {
}
None => {
if let Some(ref fragment) = *fragment {
- let cache = cache();
- let url = match cache.extern_locations.get(krate) {
+ let url = match cache.extern_locations.get(&krate) {
Some(&(_, _, ExternalLocation::Local)) => {
let depth = CURRENT_DEPTH.with(|l| l.get());
"../".repeat(depth)
}
crate fn get_doc_aliases(&self) -> FxHashSet<String> {
- self.other_attrs
- .lists(sym::doc)
- .filter(|a| a.has_name(sym::alias))
- .filter_map(|a| a.value_str().map(|s| s.to_string()))
- .filter(|v| !v.is_empty())
- .collect::<FxHashSet<_>>()
+ let mut aliases = FxHashSet::default();
+
+ for attr in self.other_attrs.lists(sym::doc).filter(|a| a.has_name(sym::alias)) {
+ if let Some(values) = attr.meta_item_list() {
+ for l in values {
+ match l.literal().unwrap().kind {
+ ast::LitKind::Str(s, _) => {
+ aliases.insert(s.as_str().to_string());
+ }
+ _ => unreachable!(),
+ }
+ }
+ } else {
+ aliases.insert(attr.value_str().map(|s| s.to_string()).unwrap());
+ }
+ }
+ aliases
}
}
}
impl GenericBound {
- crate fn maybe_sized(cx: &DocContext<'_>) -> GenericBound {
+ crate fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
let did = cx.tcx.require_lang_item(LangItem::Sized, None);
let empty = cx.tcx.intern_substs(&[]);
let path = external_path(cx, cx.tcx.item_name(did), Some(did), false, vec![], empty);
impl GenericParamDefKind {
crate fn is_type(&self) -> bool {
- match *self {
- GenericParamDefKind::Type { .. } => true,
- _ => false,
- }
+ matches!(self, GenericParamDefKind::Type { .. })
}
// FIXME(eddyb) this either returns the default of a type parameter, or the
crate decl: FnDecl,
crate generics: Generics,
crate header: hir::FnHeader,
- crate all_types: Vec<(Type, TypeKind)>,
- crate ret_types: Vec<(Type, TypeKind)>,
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
DefaultReturn => None,
}
}
+
+ fn def_id_full(&self, cache: &Cache) -> Option<DefId> {
+ match *self {
+ Return(ref ty) => ty.def_id_full(cache),
+ DefaultReturn => None,
+ }
+ }
}
#[derive(Clone, Debug)]
crate items: Vec<Item>,
crate generics: Generics,
crate bounds: Vec<GenericBound>,
- crate is_spotlight: bool,
crate is_auto: bool,
}
BareFunction(Box<BareFunctionDecl>),
Tuple(Vec<Type>),
Slice(Box<Type>),
+ /// The `String` field is about the size or the constant representing the array's length.
Array(Box<Type>, String),
Never,
RawPointer(Mutability, Box<Type>),
Attr,
Derive,
TraitAlias,
+ Primitive,
+}
+
+impl From<hir::def::DefKind> for TypeKind {
+ fn from(other: hir::def::DefKind) -> Self {
+ match other {
+ hir::def::DefKind::Enum => Self::Enum,
+ hir::def::DefKind::Fn => Self::Function,
+ hir::def::DefKind::Mod => Self::Module,
+ hir::def::DefKind::Const => Self::Const,
+ hir::def::DefKind::Static => Self::Static,
+ hir::def::DefKind::Struct => Self::Struct,
+ hir::def::DefKind::Union => Self::Union,
+ hir::def::DefKind::Trait => Self::Trait,
+ hir::def::DefKind::TyAlias => Self::Typedef,
+ hir::def::DefKind::TraitAlias => Self::TraitAlias,
+ hir::def::DefKind::Macro(_) => Self::Macro,
+ hir::def::DefKind::ForeignTy
+ | hir::def::DefKind::Variant
+ | hir::def::DefKind::AssocTy
+ | hir::def::DefKind::TyParam
+ | hir::def::DefKind::ConstParam
+ | hir::def::DefKind::Ctor(..)
+ | hir::def::DefKind::AssocFn
+ | hir::def::DefKind::AssocConst
+ | hir::def::DefKind::ExternCrate
+ | hir::def::DefKind::Use
+ | hir::def::DefKind::ForeignMod
+ | hir::def::DefKind::AnonConst
+ | hir::def::DefKind::OpaqueTy
+ | hir::def::DefKind::Field
+ | hir::def::DefKind::LifetimeParam
+ | hir::def::DefKind::GlobalAsm
+ | hir::def::DefKind::Impl
+ | hir::def::DefKind::Closure
+ | hir::def::DefKind::Generator => Self::Foreign,
+ }
+ }
}
crate trait GetDefId {
+ /// Use this method to get the [`DefId`] of a [`clean`] AST node.
+ /// This will return [`None`] when called on a primitive [`clean::Type`].
+ /// Use [`Self::def_id_full`] if you want to include primitives.
+ ///
+ /// [`clean`]: crate::clean
+ /// [`clean::Type`]: crate::clean::Type
+ // FIXME: get rid of this function and always use `def_id_full`
fn def_id(&self) -> Option<DefId>;
+
+ /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
+ ///
+ /// See [`Self::def_id`] for more.
+ ///
+ /// [clean]: crate::clean
+ fn def_id_full(&self, cache: &Cache) -> Option<DefId>;
}
impl<T: GetDefId> GetDefId for Option<T> {
fn def_id(&self) -> Option<DefId> {
self.as_ref().and_then(|d| d.def_id())
}
+
+ fn def_id_full(&self, cache: &Cache) -> Option<DefId> {
+ self.as_ref().and_then(|d| d.def_id_full(cache))
+ }
}
impl Type {
}
}
- crate fn generics(&self) -> Option<Vec<Type>> {
+ crate fn generics(&self) -> Option<Vec<&Type>> {
match *self {
ResolvedPath { ref path, .. } => path.segments.last().and_then(|seg| {
if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
Some(
args.iter()
.filter_map(|arg| match arg {
- GenericArg::Type(ty) => Some(ty.clone()),
+ GenericArg::Type(ty) => Some(ty),
_ => None,
})
.collect(),
}
crate fn is_full_generic(&self) -> bool {
- match *self {
- Type::Generic(_) => true,
+ matches!(self, Type::Generic(_))
+ }
+
+ crate fn is_primitive(&self) -> bool {
+ match self {
+ Self::Primitive(_) => true,
+ Self::BorrowedRef { ref type_, .. } | Self::RawPointer(_, ref type_) => {
+ type_.is_primitive()
+ }
_ => false,
}
}
crate fn projection(&self) -> Option<(&Type, DefId, Symbol)> {
let (self_, trait_, name) = match self {
- QPath { ref self_type, ref trait_, name } => (self_type, trait_, name),
+ QPath { self_type, trait_, name } => (self_type, trait_, name),
_ => return None,
};
let trait_did = match **trait_ {
}
}
-impl GetDefId for Type {
- fn def_id(&self) -> Option<DefId> {
- match *self {
- ResolvedPath { did, .. } => Some(did),
- Primitive(p) => cache().primitive_locations.get(&p).cloned(),
- BorrowedRef { type_: box Generic(..), .. } => {
- Primitive(PrimitiveType::Reference).def_id()
- }
- BorrowedRef { ref type_, .. } => type_.def_id(),
+impl Type {
+ fn inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId> {
+ let t: PrimitiveType = match *self {
+ ResolvedPath { did, .. } => return Some(did),
+ Primitive(p) => return cache.and_then(|c| c.primitive_locations.get(&p).cloned()),
+ BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
+ BorrowedRef { ref type_, .. } => return type_.inner_def_id(cache),
Tuple(ref tys) => {
if tys.is_empty() {
- Primitive(PrimitiveType::Unit).def_id()
+ PrimitiveType::Unit
} else {
- Primitive(PrimitiveType::Tuple).def_id()
+ PrimitiveType::Tuple
}
}
- BareFunction(..) => Primitive(PrimitiveType::Fn).def_id(),
- Never => Primitive(PrimitiveType::Never).def_id(),
- Slice(..) => Primitive(PrimitiveType::Slice).def_id(),
- Array(..) => Primitive(PrimitiveType::Array).def_id(),
- RawPointer(..) => Primitive(PrimitiveType::RawPointer).def_id(),
- QPath { ref self_type, .. } => self_type.def_id(),
- _ => None,
- }
+ BareFunction(..) => PrimitiveType::Fn,
+ Never => PrimitiveType::Never,
+ Slice(..) => PrimitiveType::Slice,
+ Array(..) => PrimitiveType::Array,
+ RawPointer(..) => PrimitiveType::RawPointer,
+ QPath { ref self_type, .. } => return self_type.inner_def_id(cache),
+ Generic(_) | Infer | ImplTrait(_) => return None,
+ };
+ cache.and_then(|c| Primitive(t).def_id_full(c))
+ }
+}
+
+impl GetDefId for Type {
+ fn def_id(&self) -> Option<DefId> {
+ self.inner_def_id(None)
+ }
+
+ fn def_id_full(&self, cache: &Cache) -> Option<DefId> {
+ self.inner_def_id(Some(cache))
}
}
impl PrimitiveType {
crate fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
+ use ast::{FloatTy, IntTy, UintTy};
match prim {
hir::PrimTy::Int(IntTy::Isize) => PrimitiveType::Isize,
hir::PrimTy::Int(IntTy::I8) => PrimitiveType::I8,
}
}
- crate fn impls(&self, tcx: TyCtxt<'_>) -> &'static SmallVec<[DefId; 4]> {
+ crate fn impls(&self, tcx: TyCtxt<'_>) -> &'static ArrayVec<[DefId; 4]> {
Self::all_impls(tcx).get(self).expect("missing impl for primitive type")
}
- crate fn all_impls(tcx: TyCtxt<'_>) -> &'static FxHashMap<PrimitiveType, SmallVec<[DefId; 4]>> {
- static CELL: OnceCell<FxHashMap<PrimitiveType, SmallVec<[DefId; 4]>>> = OnceCell::new();
+ crate fn all_impls(tcx: TyCtxt<'_>) -> &'static FxHashMap<PrimitiveType, ArrayVec<[DefId; 4]>> {
+ static CELL: OnceCell<FxHashMap<PrimitiveType, ArrayVec<[DefId; 4]>>> = OnceCell::new();
CELL.get_or_init(move || {
use self::PrimitiveType::*;
- /// A macro to create a FxHashMap.
- ///
- /// Example:
- ///
- /// ```
- /// let letters = map!{"a" => "b", "c" => "d"};
- /// ```
- ///
- /// Trailing commas are allowed.
- /// Commas between elements are required (even if the expression is a block).
- macro_rules! map {
- ($( $key: expr => $val: expr ),* $(,)*) => {{
- let mut map = ::rustc_data_structures::fx::FxHashMap::default();
- $( map.insert($key, $val); )*
- map
- }}
- }
-
let single = |a: Option<DefId>| a.into_iter().collect();
- let both = |a: Option<DefId>, b: Option<DefId>| -> SmallVec<_> {
+ let both = |a: Option<DefId>, b: Option<DefId>| -> ArrayVec<_> {
a.into_iter().chain(b).collect()
};
.collect()
},
Array => single(lang_items.array_impl()),
- Tuple => smallvec![],
- Unit => smallvec![],
+ Tuple => ArrayVec::new(),
+ Unit => ArrayVec::new(),
RawPointer => {
lang_items
.const_ptr_impl()
.chain(lang_items.mut_slice_ptr_impl())
.collect()
},
- Reference => smallvec![],
- Fn => smallvec![],
- Never => smallvec![],
+ Reference => ArrayVec::new(),
+ Fn => ArrayVec::new(),
+ Never => ArrayVec::new(),
}
})
}
}
}
+impl From<ty::IntTy> for PrimitiveType {
+ fn from(int_ty: ty::IntTy) -> PrimitiveType {
+ match int_ty {
+ ty::IntTy::Isize => PrimitiveType::Isize,
+ ty::IntTy::I8 => PrimitiveType::I8,
+ ty::IntTy::I16 => PrimitiveType::I16,
+ ty::IntTy::I32 => PrimitiveType::I32,
+ ty::IntTy::I64 => PrimitiveType::I64,
+ ty::IntTy::I128 => PrimitiveType::I128,
+ }
+ }
+}
+
+impl From<ty::UintTy> for PrimitiveType {
+ fn from(uint_ty: ty::UintTy) -> PrimitiveType {
+ match uint_ty {
+ ty::UintTy::Usize => PrimitiveType::Usize,
+ ty::UintTy::U8 => PrimitiveType::U8,
+ ty::UintTy::U16 => PrimitiveType::U16,
+ ty::UintTy::U32 => PrimitiveType::U32,
+ ty::UintTy::U64 => PrimitiveType::U64,
+ ty::UintTy::U128 => PrimitiveType::U128,
+ }
+ }
+}
+
+impl From<ty::FloatTy> for PrimitiveType {
+ fn from(float_ty: ty::FloatTy) -> PrimitiveType {
+ match float_ty {
+ ty::FloatTy::F32 => PrimitiveType::F32,
+ ty::FloatTy::F64 => PrimitiveType::F64,
+ }
+ }
+}
+
impl From<hir::PrimTy> for PrimitiveType {
fn from(prim_ty: hir::PrimTy) -> PrimitiveType {
match prim_ty {
#[derive(Clone, Debug)]
crate struct Struct {
- crate struct_type: doctree::StructType,
+ crate struct_type: CtorKind,
crate generics: Generics,
crate fields: Vec<Item>,
crate fields_stripped: bool,
#[derive(Clone, Debug)]
crate struct Union {
- crate struct_type: doctree::StructType,
crate generics: Generics,
crate fields: Vec<Item>,
crate fields_stripped: bool,
/// only as a variant in an enum.
#[derive(Clone, Debug)]
crate struct VariantStruct {
- crate struct_type: doctree::StructType,
+ crate struct_type: CtorKind,
crate fields: Vec<Item>,
crate fields_stripped: bool,
}
}
#[derive(Clone, Debug)]
-crate struct Variant {
- crate kind: VariantKind,
-}
-
-#[derive(Clone, Debug)]
-crate enum VariantKind {
+crate enum Variant {
CLike,
Tuple(Vec<Type>),
Struct(VariantStruct),
self.0
}
+ crate fn is_dummy(&self) -> bool {
+ self.0.is_dummy()
+ }
+
crate fn filename(&self, sess: &Session) -> FileName {
sess.source_map().span_to_filename(self.0)
}
crate struct Typedef {
crate type_: Type,
crate generics: Generics,
- // Type of target item.
+ /// `type_` can come from either the HIR or from metadata. If it comes from HIR, it may be a type
+ /// alias instead of the final type. This will always have the final type, regardless of whether
+ /// `type_` came from HIR or from metadata.
+ ///
+ /// If `item_type.is_none()`, `type_` is guarenteed to come from metadata (and therefore hold the
+ /// final type).
crate item_type: Option<Type>,
}
fn def_id(&self) -> Option<DefId> {
self.type_.def_id()
}
+
+ fn def_id_full(&self, cache: &Cache) -> Option<DefId> {
+ self.type_.def_id_full(cache)
+ }
}
#[derive(Clone, Debug)]
crate struct Static {
crate type_: Type,
crate mutability: Mutability,
- /// It's useful to have the value of a static documented, but I have no
- /// desire to represent expressions (that'd basically be all of the AST,
- /// which is huge!). So, have a string.
- crate expr: String,
+ crate expr: Option<BodyId>,
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
crate is_literal: bool,
}
-#[derive(Clone, PartialEq, Debug)]
-crate enum ImplPolarity {
- Positive,
- Negative,
-}
-
#[derive(Clone, Debug)]
crate struct Impl {
crate unsafety: hir::Unsafety,
crate trait_: Option<Type>,
crate for_: Type,
crate items: Vec<Item>,
- crate polarity: Option<ImplPolarity>,
+ crate negative_polarity: bool,
crate synthetic: bool,
crate blanket_impl: Option<Type>,
}