]>
Commit | Line | Data |
---|---|---|
dfeec247 XL |
1 | use std::cell::RefCell; |
2 | use std::default::Default; | |
60c5eb7d XL |
3 | use std::fmt; |
4 | use std::hash::{Hash, Hasher}; | |
60c5eb7d | 5 | use std::iter::FromIterator; |
3dfed10e | 6 | use std::lazy::SyncOnceCell as OnceCell; |
dfeec247 | 7 | use std::num::NonZeroU32; |
60c5eb7d | 8 | use std::rc::Rc; |
60c5eb7d | 9 | use std::sync::Arc; |
dfeec247 | 10 | use std::{slice, vec}; |
60c5eb7d | 11 | |
74b04a01 | 12 | use rustc_ast::attr; |
3dfed10e XL |
13 | use rustc_ast::util::comments::beautify_doc_string; |
14 | use rustc_ast::{self as ast, AttrStyle}; | |
dfeec247 XL |
15 | use rustc_data_structures::fx::{FxHashMap, FxHashSet}; |
16 | use rustc_hir as hir; | |
17 | use rustc_hir::def::Res; | |
ba9703b0 | 18 | use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; |
3dfed10e | 19 | use rustc_hir::lang_items::LangItem; |
dfeec247 | 20 | use rustc_hir::Mutability; |
60c5eb7d | 21 | use rustc_index::vec::IndexVec; |
ba9703b0 | 22 | use rustc_middle::middle::stability; |
3dfed10e | 23 | use rustc_middle::ty::{AssocKind, TyCtxt}; |
dfeec247 XL |
24 | use rustc_span::hygiene::MacroKind; |
25 | use rustc_span::source_map::DUMMY_SP; | |
3dfed10e | 26 | use rustc_span::symbol::{kw, sym, Ident, Symbol}; |
dfeec247 | 27 | use rustc_span::{self, FileName}; |
ba9703b0 | 28 | use rustc_target::abi::VariantIdx; |
60c5eb7d | 29 | use rustc_target::spec::abi::Abi; |
3dfed10e | 30 | use smallvec::{smallvec, SmallVec}; |
60c5eb7d | 31 | |
60c5eb7d | 32 | use crate::clean::cfg::Cfg; |
60c5eb7d | 33 | use crate::clean::external_path; |
dfeec247 | 34 | use crate::clean::inline; |
60c5eb7d | 35 | use crate::clean::types::Type::{QPath, ResolvedPath}; |
dfeec247 | 36 | use crate::core::DocContext; |
60c5eb7d | 37 | use crate::doctree; |
3dfed10e XL |
38 | use crate::formats::cache::cache; |
39 | use crate::formats::item_type::ItemType; | |
40 | use crate::html::render::cache::ExternalLocation; | |
60c5eb7d | 41 | |
74b04a01 | 42 | use self::FnRetTy::*; |
60c5eb7d XL |
43 | use self::ItemEnum::*; |
44 | use self::SelfTy::*; | |
dfeec247 | 45 | use self::Type::*; |
60c5eb7d XL |
46 | |
47 | thread_local!(pub static MAX_DEF_ID: RefCell<FxHashMap<CrateNum, DefId>> = Default::default()); | |
48 | ||
49 | #[derive(Clone, Debug)] | |
50 | pub struct Crate { | |
51 | pub name: String, | |
52 | pub version: Option<String>, | |
53 | pub src: FileName, | |
54 | pub module: Option<Item>, | |
55 | pub externs: Vec<(CrateNum, ExternalCrate)>, | |
56 | pub primitives: Vec<(DefId, PrimitiveType, Attributes)>, | |
57 | // These are later on moved into `CACHEKEY`, leaving the map empty. | |
58 | // Only here so that they can be filtered through the rustdoc passes. | |
59 | pub external_traits: Rc<RefCell<FxHashMap<DefId, Trait>>>, | |
60 | pub masked_crates: FxHashSet<CrateNum>, | |
61 | pub collapsed: bool, | |
62 | } | |
63 | ||
64 | #[derive(Clone, Debug)] | |
65 | pub struct ExternalCrate { | |
66 | pub name: String, | |
67 | pub src: FileName, | |
68 | pub attrs: Attributes, | |
69 | pub primitives: Vec<(DefId, PrimitiveType, Attributes)>, | |
70 | pub keywords: Vec<(DefId, String, Attributes)>, | |
71 | } | |
72 | ||
73 | /// Anything with a source location and set of attributes and, optionally, a | |
74 | /// name. That is, anything that can be documented. This doesn't correspond | |
75 | /// directly to the AST's concept of an item; it's a strict superset. | |
76 | #[derive(Clone)] | |
77 | pub struct Item { | |
78 | /// Stringified span | |
79 | pub source: Span, | |
80 | /// Not everything has a name. E.g., impls | |
81 | pub name: Option<String>, | |
82 | pub attrs: Attributes, | |
83 | pub inner: ItemEnum, | |
84 | pub visibility: Visibility, | |
85 | pub def_id: DefId, | |
86 | pub stability: Option<Stability>, | |
87 | pub deprecation: Option<Deprecation>, | |
88 | } | |
89 | ||
90 | impl fmt::Debug for Item { | |
91 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { | |
f035d41b | 92 | let fake = self.is_fake(); |
60c5eb7d XL |
93 | let def_id: &dyn fmt::Debug = if fake { &"**FAKE**" } else { &self.def_id }; |
94 | ||
95 | fmt.debug_struct("Item") | |
96 | .field("source", &self.source) | |
97 | .field("name", &self.name) | |
98 | .field("attrs", &self.attrs) | |
99 | .field("inner", &self.inner) | |
100 | .field("visibility", &self.visibility) | |
101 | .field("def_id", def_id) | |
102 | .field("stability", &self.stability) | |
103 | .field("deprecation", &self.deprecation) | |
104 | .finish() | |
105 | } | |
106 | } | |
107 | ||
108 | impl Item { | |
109 | /// Finds the `doc` attribute as a NameValue and returns the corresponding | |
110 | /// value found. | |
111 | pub fn doc_value(&self) -> Option<&str> { | |
112 | self.attrs.doc_value() | |
113 | } | |
114 | ||
115 | /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined | |
116 | /// with newlines. | |
117 | pub fn collapsed_doc_value(&self) -> Option<String> { | |
118 | self.attrs.collapsed_doc_value() | |
119 | } | |
120 | ||
121 | pub fn links(&self) -> Vec<(String, String)> { | |
122 | self.attrs.links(&self.def_id.krate) | |
123 | } | |
124 | ||
125 | pub fn is_crate(&self) -> bool { | |
126 | match self.inner { | |
dfeec247 XL |
127 | StrippedItem(box ModuleItem(Module { is_crate: true, .. })) |
128 | | ModuleItem(Module { is_crate: true, .. }) => true, | |
60c5eb7d XL |
129 | _ => false, |
130 | } | |
131 | } | |
132 | pub fn is_mod(&self) -> bool { | |
133 | self.type_() == ItemType::Module | |
134 | } | |
135 | pub fn is_trait(&self) -> bool { | |
136 | self.type_() == ItemType::Trait | |
137 | } | |
138 | pub fn is_struct(&self) -> bool { | |
139 | self.type_() == ItemType::Struct | |
140 | } | |
141 | pub fn is_enum(&self) -> bool { | |
142 | self.type_() == ItemType::Enum | |
143 | } | |
144 | pub fn is_variant(&self) -> bool { | |
145 | self.type_() == ItemType::Variant | |
146 | } | |
147 | pub fn is_associated_type(&self) -> bool { | |
148 | self.type_() == ItemType::AssocType | |
149 | } | |
150 | pub fn is_associated_const(&self) -> bool { | |
151 | self.type_() == ItemType::AssocConst | |
152 | } | |
153 | pub fn is_method(&self) -> bool { | |
154 | self.type_() == ItemType::Method | |
155 | } | |
156 | pub fn is_ty_method(&self) -> bool { | |
157 | self.type_() == ItemType::TyMethod | |
158 | } | |
159 | pub fn is_typedef(&self) -> bool { | |
160 | self.type_() == ItemType::Typedef | |
161 | } | |
162 | pub fn is_primitive(&self) -> bool { | |
163 | self.type_() == ItemType::Primitive | |
164 | } | |
165 | pub fn is_union(&self) -> bool { | |
166 | self.type_() == ItemType::Union | |
167 | } | |
168 | pub fn is_import(&self) -> bool { | |
169 | self.type_() == ItemType::Import | |
170 | } | |
171 | pub fn is_extern_crate(&self) -> bool { | |
172 | self.type_() == ItemType::ExternCrate | |
173 | } | |
174 | pub fn is_keyword(&self) -> bool { | |
175 | self.type_() == ItemType::Keyword | |
176 | } | |
177 | pub fn is_stripped(&self) -> bool { | |
dfeec247 XL |
178 | match self.inner { |
179 | StrippedItem(..) => true, | |
180 | _ => false, | |
181 | } | |
60c5eb7d XL |
182 | } |
183 | pub fn has_stripped_fields(&self) -> Option<bool> { | |
184 | match self.inner { | |
185 | StructItem(ref _struct) => Some(_struct.fields_stripped), | |
186 | UnionItem(ref union) => Some(union.fields_stripped), | |
dfeec247 | 187 | VariantItem(Variant { kind: VariantKind::Struct(ref vstruct) }) => { |
60c5eb7d | 188 | Some(vstruct.fields_stripped) |
dfeec247 | 189 | } |
60c5eb7d XL |
190 | _ => None, |
191 | } | |
192 | } | |
193 | ||
194 | pub fn stability_class(&self) -> Option<String> { | |
195 | self.stability.as_ref().and_then(|ref s| { | |
196 | let mut classes = Vec::with_capacity(2); | |
197 | ||
198 | if s.level == stability::Unstable { | |
199 | classes.push("unstable"); | |
200 | } | |
201 | ||
3dfed10e XL |
202 | // FIXME: what about non-staged API items that are deprecated? |
203 | if self.deprecation.is_some() { | |
60c5eb7d XL |
204 | classes.push("deprecated"); |
205 | } | |
206 | ||
74b04a01 | 207 | if !classes.is_empty() { Some(classes.join(" ")) } else { None } |
60c5eb7d XL |
208 | }) |
209 | } | |
210 | ||
211 | pub fn stable_since(&self) -> Option<&str> { | |
212 | self.stability.as_ref().map(|s| &s.since[..]) | |
213 | } | |
214 | ||
215 | pub fn is_non_exhaustive(&self) -> bool { | |
3dfed10e | 216 | self.attrs.other_attrs.iter().any(|a| a.has_name(sym::non_exhaustive)) |
60c5eb7d XL |
217 | } |
218 | ||
219 | /// Returns a documentation-level item type from the item. | |
220 | pub fn type_(&self) -> ItemType { | |
221 | ItemType::from(self) | |
222 | } | |
223 | ||
60c5eb7d XL |
224 | pub fn is_default(&self) -> bool { |
225 | match self.inner { | |
226 | ItemEnum::MethodItem(ref meth) => { | |
227 | if let Some(defaultness) = meth.defaultness { | |
228 | defaultness.has_value() && !defaultness.is_final() | |
229 | } else { | |
230 | false | |
231 | } | |
232 | } | |
233 | _ => false, | |
234 | } | |
235 | } | |
f035d41b XL |
236 | |
237 | /// See comments on next_def_id | |
238 | pub fn is_fake(&self) -> bool { | |
239 | MAX_DEF_ID.with(|m| { | |
240 | m.borrow().get(&self.def_id.krate).map(|id| self.def_id >= *id).unwrap_or(false) | |
241 | }) | |
242 | } | |
60c5eb7d XL |
243 | } |
244 | ||
245 | #[derive(Clone, Debug)] | |
246 | pub enum ItemEnum { | |
247 | ExternCrateItem(String, Option<String>), | |
248 | ImportItem(Import), | |
249 | StructItem(Struct), | |
250 | UnionItem(Union), | |
251 | EnumItem(Enum), | |
252 | FunctionItem(Function), | |
253 | ModuleItem(Module), | |
254 | TypedefItem(Typedef, bool /* is associated type */), | |
255 | OpaqueTyItem(OpaqueTy, bool /* is associated type */), | |
256 | StaticItem(Static), | |
257 | ConstantItem(Constant), | |
258 | TraitItem(Trait), | |
259 | TraitAliasItem(TraitAlias), | |
260 | ImplItem(Impl), | |
261 | /// A method signature only. Used for required methods in traits (ie, | |
262 | /// non-default-methods). | |
263 | TyMethodItem(TyMethod), | |
264 | /// A method with a body. | |
265 | MethodItem(Method), | |
266 | StructFieldItem(Type), | |
267 | VariantItem(Variant), | |
268 | /// `fn`s from an extern block | |
269 | ForeignFunctionItem(Function), | |
270 | /// `static`s from an extern block | |
271 | ForeignStaticItem(Static), | |
272 | /// `type`s from an extern block | |
273 | ForeignTypeItem, | |
274 | MacroItem(Macro), | |
275 | ProcMacroItem(ProcMacro), | |
276 | PrimitiveItem(PrimitiveType), | |
277 | AssocConstItem(Type, Option<String>), | |
278 | AssocTypeItem(Vec<GenericBound>, Option<Type>), | |
279 | /// An item that has been stripped by a rustdoc pass | |
280 | StrippedItem(Box<ItemEnum>), | |
281 | KeywordItem(String), | |
282 | } | |
283 | ||
284 | impl ItemEnum { | |
3dfed10e | 285 | pub fn is_type_alias(&self) -> bool { |
60c5eb7d | 286 | match *self { |
dfeec247 | 287 | ItemEnum::TypedefItem(_, _) | ItemEnum::AssocTypeItem(_, _) => true, |
60c5eb7d XL |
288 | _ => false, |
289 | } | |
290 | } | |
3dfed10e XL |
291 | |
292 | pub fn as_assoc_kind(&self) -> Option<AssocKind> { | |
293 | match *self { | |
294 | ItemEnum::AssocConstItem(..) => Some(AssocKind::Const), | |
295 | ItemEnum::AssocTypeItem(..) => Some(AssocKind::Type), | |
296 | ItemEnum::TyMethodItem(..) | ItemEnum::MethodItem(..) => Some(AssocKind::Fn), | |
297 | _ => None, | |
298 | } | |
299 | } | |
60c5eb7d XL |
300 | } |
301 | ||
302 | #[derive(Clone, Debug)] | |
303 | pub struct Module { | |
304 | pub items: Vec<Item>, | |
305 | pub is_crate: bool, | |
306 | } | |
307 | ||
308 | pub struct ListAttributesIter<'a> { | |
309 | attrs: slice::Iter<'a, ast::Attribute>, | |
310 | current_list: vec::IntoIter<ast::NestedMetaItem>, | |
311 | name: Symbol, | |
312 | } | |
313 | ||
314 | impl<'a> Iterator for ListAttributesIter<'a> { | |
315 | type Item = ast::NestedMetaItem; | |
316 | ||
317 | fn next(&mut self) -> Option<Self::Item> { | |
318 | if let Some(nested) = self.current_list.next() { | |
319 | return Some(nested); | |
320 | } | |
321 | ||
322 | for attr in &mut self.attrs { | |
323 | if let Some(list) = attr.meta_item_list() { | |
3dfed10e | 324 | if attr.has_name(self.name) { |
60c5eb7d XL |
325 | self.current_list = list.into_iter(); |
326 | if let Some(nested) = self.current_list.next() { | |
327 | return Some(nested); | |
328 | } | |
329 | } | |
330 | } | |
331 | } | |
332 | ||
333 | None | |
334 | } | |
335 | ||
336 | fn size_hint(&self) -> (usize, Option<usize>) { | |
337 | let lower = self.current_list.len(); | |
338 | (lower, None) | |
339 | } | |
340 | } | |
341 | ||
342 | pub trait AttributesExt { | |
343 | /// Finds an attribute as List and returns the list of attributes nested inside. | |
344 | fn lists(&self, name: Symbol) -> ListAttributesIter<'_>; | |
345 | } | |
346 | ||
347 | impl AttributesExt for [ast::Attribute] { | |
348 | fn lists(&self, name: Symbol) -> ListAttributesIter<'_> { | |
dfeec247 | 349 | ListAttributesIter { attrs: self.iter(), current_list: Vec::new().into_iter(), name } |
60c5eb7d XL |
350 | } |
351 | } | |
352 | ||
353 | pub trait NestedAttributesExt { | |
354 | /// Returns `true` if the attribute list contains a specific `Word` | |
355 | fn has_word(self, word: Symbol) -> bool; | |
356 | } | |
357 | ||
dfeec247 | 358 | impl<I: IntoIterator<Item = ast::NestedMetaItem>> NestedAttributesExt for I { |
60c5eb7d | 359 | fn has_word(self, word: Symbol) -> bool { |
3dfed10e | 360 | self.into_iter().any(|attr| attr.is_word() && attr.has_name(word)) |
60c5eb7d XL |
361 | } |
362 | } | |
363 | ||
364 | /// A portion of documentation, extracted from a `#[doc]` attribute. | |
365 | /// | |
366 | /// Each variant contains the line number within the complete doc-comment where the fragment | |
367 | /// starts, as well as the Span where the corresponding doc comment or attribute is located. | |
368 | /// | |
369 | /// Included files are kept separate from inline doc comments so that proper line-number | |
370 | /// information can be given when a doctest fails. Sugared doc comments and "raw" doc comments are | |
371 | /// kept separate because of issue #42760. | |
372 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
373 | pub enum DocFragment { | |
374 | /// A doc fragment created from a `///` or `//!` doc comment. | |
dfeec247 | 375 | SugaredDoc(usize, rustc_span::Span, String), |
60c5eb7d | 376 | /// A doc fragment created from a "raw" `#[doc=""]` attribute. |
dfeec247 | 377 | RawDoc(usize, rustc_span::Span, String), |
60c5eb7d XL |
378 | /// A doc fragment created from a `#[doc(include="filename")]` attribute. Contains both the |
379 | /// given filename and the file contents. | |
dfeec247 | 380 | Include(usize, rustc_span::Span, String, String), |
60c5eb7d XL |
381 | } |
382 | ||
383 | impl DocFragment { | |
384 | pub fn as_str(&self) -> &str { | |
385 | match *self { | |
386 | DocFragment::SugaredDoc(_, _, ref s) => &s[..], | |
387 | DocFragment::RawDoc(_, _, ref s) => &s[..], | |
388 | DocFragment::Include(_, _, _, ref s) => &s[..], | |
389 | } | |
390 | } | |
391 | ||
dfeec247 | 392 | pub fn span(&self) -> rustc_span::Span { |
60c5eb7d | 393 | match *self { |
dfeec247 XL |
394 | DocFragment::SugaredDoc(_, span, _) |
395 | | DocFragment::RawDoc(_, span, _) | |
396 | | DocFragment::Include(_, span, _, _) => span, | |
60c5eb7d XL |
397 | } |
398 | } | |
399 | } | |
400 | ||
401 | impl<'a> FromIterator<&'a DocFragment> for String { | |
402 | fn from_iter<T>(iter: T) -> Self | |
403 | where | |
dfeec247 | 404 | T: IntoIterator<Item = &'a DocFragment>, |
60c5eb7d XL |
405 | { |
406 | iter.into_iter().fold(String::new(), |mut acc, frag| { | |
407 | if !acc.is_empty() { | |
408 | acc.push('\n'); | |
409 | } | |
410 | match *frag { | |
411 | DocFragment::SugaredDoc(_, _, ref docs) | |
dfeec247 XL |
412 | | DocFragment::RawDoc(_, _, ref docs) |
413 | | DocFragment::Include(_, _, _, ref docs) => acc.push_str(docs), | |
60c5eb7d XL |
414 | } |
415 | ||
416 | acc | |
417 | }) | |
418 | } | |
419 | } | |
420 | ||
421 | #[derive(Clone, Debug, Default)] | |
422 | pub struct Attributes { | |
423 | pub doc_strings: Vec<DocFragment>, | |
424 | pub other_attrs: Vec<ast::Attribute>, | |
425 | pub cfg: Option<Arc<Cfg>>, | |
dfeec247 | 426 | pub span: Option<rustc_span::Span>, |
60c5eb7d XL |
427 | /// map from Rust paths to resolved defs and potential URL fragments |
428 | pub links: Vec<(String, Option<DefId>, Option<String>)>, | |
429 | pub inner_docs: bool, | |
430 | } | |
431 | ||
432 | impl Attributes { | |
433 | /// Extracts the content from an attribute `#[doc(cfg(content))]`. | |
434 | pub fn extract_cfg(mi: &ast::MetaItem) -> Option<&ast::MetaItem> { | |
3dfed10e | 435 | use rustc_ast::NestedMetaItem::MetaItem; |
60c5eb7d XL |
436 | |
437 | if let ast::MetaItemKind::List(ref nmis) = mi.kind { | |
438 | if nmis.len() == 1 { | |
439 | if let MetaItem(ref cfg_mi) = nmis[0] { | |
3dfed10e | 440 | if cfg_mi.has_name(sym::cfg) { |
60c5eb7d XL |
441 | if let ast::MetaItemKind::List(ref cfg_nmis) = cfg_mi.kind { |
442 | if cfg_nmis.len() == 1 { | |
443 | if let MetaItem(ref content_mi) = cfg_nmis[0] { | |
444 | return Some(content_mi); | |
445 | } | |
446 | } | |
447 | } | |
448 | } | |
449 | } | |
450 | } | |
451 | } | |
452 | ||
453 | None | |
454 | } | |
455 | ||
456 | /// Reads a `MetaItem` from within an attribute, looks for whether it is a | |
457 | /// `#[doc(include="file")]`, and returns the filename and contents of the file as loaded from | |
458 | /// its expansion. | |
459 | pub fn extract_include(mi: &ast::MetaItem) -> Option<(String, String)> { | |
460 | mi.meta_item_list().and_then(|list| { | |
461 | for meta in list { | |
3dfed10e | 462 | if meta.has_name(sym::include) { |
60c5eb7d XL |
463 | // the actual compiled `#[doc(include="filename")]` gets expanded to |
464 | // `#[doc(include(file="filename", contents="file contents")]` so we need to | |
465 | // look for that instead | |
466 | return meta.meta_item_list().and_then(|list| { | |
467 | let mut filename: Option<String> = None; | |
468 | let mut contents: Option<String> = None; | |
469 | ||
470 | for it in list { | |
3dfed10e | 471 | if it.has_name(sym::file) { |
60c5eb7d XL |
472 | if let Some(name) = it.value_str() { |
473 | filename = Some(name.to_string()); | |
474 | } | |
3dfed10e | 475 | } else if it.has_name(sym::contents) { |
60c5eb7d XL |
476 | if let Some(docs) = it.value_str() { |
477 | contents = Some(docs.to_string()); | |
478 | } | |
479 | } | |
480 | } | |
481 | ||
482 | if let (Some(filename), Some(contents)) = (filename, contents) { | |
483 | Some((filename, contents)) | |
484 | } else { | |
485 | None | |
486 | } | |
487 | }); | |
488 | } | |
489 | } | |
490 | ||
491 | None | |
492 | }) | |
493 | } | |
494 | ||
495 | pub fn has_doc_flag(&self, flag: Symbol) -> bool { | |
496 | for attr in &self.other_attrs { | |
3dfed10e | 497 | if !attr.has_name(sym::doc) { |
dfeec247 XL |
498 | continue; |
499 | } | |
60c5eb7d XL |
500 | |
501 | if let Some(items) = attr.meta_item_list() { | |
3dfed10e | 502 | if items.iter().filter_map(|i| i.meta_item()).any(|it| it.has_name(flag)) { |
60c5eb7d XL |
503 | return true; |
504 | } | |
505 | } | |
506 | } | |
507 | ||
508 | false | |
509 | } | |
510 | ||
dfeec247 | 511 | pub fn from_ast(diagnostic: &::rustc_errors::Handler, attrs: &[ast::Attribute]) -> Attributes { |
60c5eb7d XL |
512 | let mut doc_strings = vec![]; |
513 | let mut sp = None; | |
514 | let mut cfg = Cfg::True; | |
515 | let mut doc_line = 0; | |
516 | ||
dfeec247 XL |
517 | let other_attrs = attrs |
518 | .iter() | |
519 | .filter_map(|attr| { | |
520 | if let Some(value) = attr.doc_str() { | |
3dfed10e XL |
521 | let value = beautify_doc_string(value); |
522 | let mk_fragment: fn(_, _, _) -> _ = if attr.is_doc_comment() { | |
523 | DocFragment::SugaredDoc | |
dfeec247 | 524 | } else { |
3dfed10e | 525 | DocFragment::RawDoc |
dfeec247 | 526 | }; |
60c5eb7d | 527 | |
dfeec247 XL |
528 | let line = doc_line; |
529 | doc_line += value.lines().count(); | |
530 | doc_strings.push(mk_fragment(line, attr.span, value)); | |
60c5eb7d | 531 | |
dfeec247 XL |
532 | if sp.is_none() { |
533 | sp = Some(attr.span); | |
534 | } | |
535 | None | |
536 | } else { | |
3dfed10e | 537 | if attr.has_name(sym::doc) { |
dfeec247 XL |
538 | if let Some(mi) = attr.meta() { |
539 | if let Some(cfg_mi) = Attributes::extract_cfg(&mi) { | |
540 | // Extracted #[doc(cfg(...))] | |
541 | match Cfg::parse(cfg_mi) { | |
542 | Ok(new_cfg) => cfg &= new_cfg, | |
543 | Err(e) => diagnostic.span_err(e.span, e.msg), | |
544 | } | |
545 | } else if let Some((filename, contents)) = | |
546 | Attributes::extract_include(&mi) | |
547 | { | |
548 | let line = doc_line; | |
549 | doc_line += contents.lines().count(); | |
550 | doc_strings.push(DocFragment::Include( | |
551 | line, attr.span, filename, contents, | |
552 | )); | |
60c5eb7d | 553 | } |
60c5eb7d XL |
554 | } |
555 | } | |
dfeec247 | 556 | Some(attr.clone()) |
60c5eb7d | 557 | } |
60c5eb7d | 558 | }) |
dfeec247 | 559 | .collect(); |
60c5eb7d XL |
560 | |
561 | // treat #[target_feature(enable = "feat")] attributes as if they were | |
562 | // #[doc(cfg(target_feature = "feat"))] attributes as well | |
563 | for attr in attrs.lists(sym::target_feature) { | |
3dfed10e | 564 | if attr.has_name(sym::enable) { |
60c5eb7d XL |
565 | if let Some(feat) = attr.value_str() { |
566 | let meta = attr::mk_name_value_item_str( | |
dfeec247 XL |
567 | Ident::with_dummy_span(sym::target_feature), |
568 | feat, | |
569 | DUMMY_SP, | |
60c5eb7d XL |
570 | ); |
571 | if let Ok(feat_cfg) = Cfg::parse(&meta) { | |
572 | cfg &= feat_cfg; | |
573 | } | |
574 | } | |
575 | } | |
576 | } | |
577 | ||
dfeec247 XL |
578 | let inner_docs = attrs |
579 | .iter() | |
74b04a01 | 580 | .find(|a| a.doc_str().is_some()) |
dfeec247 | 581 | .map_or(true, |a| a.style == AttrStyle::Inner); |
60c5eb7d XL |
582 | |
583 | Attributes { | |
584 | doc_strings, | |
585 | other_attrs, | |
586 | cfg: if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }, | |
587 | span: sp, | |
588 | links: vec![], | |
589 | inner_docs, | |
590 | } | |
591 | } | |
592 | ||
593 | /// Finds the `doc` attribute as a NameValue and returns the corresponding | |
594 | /// value found. | |
595 | pub fn doc_value(&self) -> Option<&str> { | |
596 | self.doc_strings.first().map(|s| s.as_str()) | |
597 | } | |
598 | ||
599 | /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined | |
600 | /// with newlines. | |
601 | pub fn collapsed_doc_value(&self) -> Option<String> { | |
dfeec247 | 602 | if !self.doc_strings.is_empty() { Some(self.doc_strings.iter().collect()) } else { None } |
60c5eb7d XL |
603 | } |
604 | ||
605 | /// Gets links as a vector | |
606 | /// | |
607 | /// Cache must be populated before call | |
608 | pub fn links(&self, krate: &CrateNum) -> Vec<(String, String)> { | |
609 | use crate::html::format::href; | |
f035d41b | 610 | use crate::html::render::CURRENT_DEPTH; |
60c5eb7d | 611 | |
dfeec247 XL |
612 | self.links |
613 | .iter() | |
614 | .filter_map(|&(ref s, did, ref fragment)| { | |
615 | match did { | |
616 | Some(did) => { | |
617 | if let Some((mut href, ..)) = href(did) { | |
618 | if let Some(ref fragment) = *fragment { | |
619 | href.push_str("#"); | |
620 | href.push_str(fragment); | |
621 | } | |
622 | Some((s.clone(), href)) | |
623 | } else { | |
624 | None | |
60c5eb7d | 625 | } |
60c5eb7d | 626 | } |
dfeec247 XL |
627 | None => { |
628 | if let Some(ref fragment) = *fragment { | |
629 | let cache = cache(); | |
630 | let url = match cache.extern_locations.get(krate) { | |
f035d41b XL |
631 | Some(&(_, _, ExternalLocation::Local)) => { |
632 | let depth = CURRENT_DEPTH.with(|l| l.get()); | |
633 | "../".repeat(depth) | |
dfeec247 | 634 | } |
f035d41b | 635 | Some(&(_, _, ExternalLocation::Remote(ref s))) => s.to_string(), |
dfeec247 | 636 | Some(&(_, _, ExternalLocation::Unknown)) | None => { |
f035d41b | 637 | String::from("https://doc.rust-lang.org/nightly") |
dfeec247 XL |
638 | } |
639 | }; | |
640 | // This is a primitive so the url is done "by hand". | |
641 | let tail = fragment.find('#').unwrap_or_else(|| fragment.len()); | |
642 | Some(( | |
643 | s.clone(), | |
644 | format!( | |
645 | "{}{}std/primitive.{}.html{}", | |
646 | url, | |
647 | if !url.ends_with('/') { "/" } else { "" }, | |
648 | &fragment[..tail], | |
649 | &fragment[tail..] | |
650 | ), | |
651 | )) | |
652 | } else { | |
653 | panic!("This isn't a primitive?!"); | |
654 | } | |
60c5eb7d XL |
655 | } |
656 | } | |
dfeec247 XL |
657 | }) |
658 | .collect() | |
60c5eb7d | 659 | } |
f9f354fc XL |
660 | |
661 | pub fn get_doc_aliases(&self) -> FxHashSet<String> { | |
662 | self.other_attrs | |
663 | .lists(sym::doc) | |
3dfed10e | 664 | .filter(|a| a.has_name(sym::alias)) |
f9f354fc XL |
665 | .filter_map(|a| a.value_str().map(|s| s.to_string().replace("\"", ""))) |
666 | .filter(|v| !v.is_empty()) | |
667 | .collect::<FxHashSet<_>>() | |
668 | } | |
60c5eb7d XL |
669 | } |
670 | ||
671 | impl PartialEq for Attributes { | |
672 | fn eq(&self, rhs: &Self) -> bool { | |
dfeec247 XL |
673 | self.doc_strings == rhs.doc_strings |
674 | && self.cfg == rhs.cfg | |
675 | && self.span == rhs.span | |
676 | && self.links == rhs.links | |
677 | && self | |
678 | .other_attrs | |
679 | .iter() | |
680 | .map(|attr| attr.id) | |
681 | .eq(rhs.other_attrs.iter().map(|attr| attr.id)) | |
60c5eb7d XL |
682 | } |
683 | } | |
684 | ||
685 | impl Eq for Attributes {} | |
686 | ||
687 | impl Hash for Attributes { | |
688 | fn hash<H: Hasher>(&self, hasher: &mut H) { | |
689 | self.doc_strings.hash(hasher); | |
690 | self.cfg.hash(hasher); | |
691 | self.span.hash(hasher); | |
692 | self.links.hash(hasher); | |
693 | for attr in &self.other_attrs { | |
694 | attr.id.hash(hasher); | |
695 | } | |
696 | } | |
697 | } | |
698 | ||
699 | impl AttributesExt for Attributes { | |
700 | fn lists(&self, name: Symbol) -> ListAttributesIter<'_> { | |
701 | self.other_attrs.lists(name) | |
702 | } | |
703 | } | |
704 | ||
705 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
706 | pub enum GenericBound { | |
707 | TraitBound(PolyTrait, hir::TraitBoundModifier), | |
708 | Outlives(Lifetime), | |
709 | } | |
710 | ||
711 | impl GenericBound { | |
712 | pub fn maybe_sized(cx: &DocContext<'_>) -> GenericBound { | |
3dfed10e | 713 | let did = cx.tcx.require_lang_item(LangItem::Sized, None); |
60c5eb7d | 714 | let empty = cx.tcx.intern_substs(&[]); |
dfeec247 | 715 | let path = external_path(cx, cx.tcx.item_name(did), Some(did), false, vec![], empty); |
60c5eb7d | 716 | inline::record_extern_fqn(cx, did, TypeKind::Trait); |
dfeec247 XL |
717 | GenericBound::TraitBound( |
718 | PolyTrait { | |
719 | trait_: ResolvedPath { path, param_names: None, did, is_generic: false }, | |
720 | generic_params: Vec::new(), | |
60c5eb7d | 721 | }, |
dfeec247 XL |
722 | hir::TraitBoundModifier::Maybe, |
723 | ) | |
60c5eb7d XL |
724 | } |
725 | ||
726 | pub fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool { | |
dfeec247 | 727 | use rustc_hir::TraitBoundModifier as TBM; |
60c5eb7d XL |
728 | if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self { |
729 | if trait_.def_id() == cx.tcx.lang_items().sized_trait() { | |
730 | return true; | |
731 | } | |
732 | } | |
733 | false | |
734 | } | |
735 | ||
736 | pub fn get_poly_trait(&self) -> Option<PolyTrait> { | |
737 | if let GenericBound::TraitBound(ref p, _) = *self { | |
dfeec247 | 738 | return Some(p.clone()); |
60c5eb7d XL |
739 | } |
740 | None | |
741 | } | |
742 | ||
743 | pub fn get_trait_type(&self) -> Option<Type> { | |
744 | if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self { | |
745 | Some(trait_.clone()) | |
746 | } else { | |
747 | None | |
748 | } | |
749 | } | |
750 | } | |
751 | ||
752 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
753 | pub struct Lifetime(pub String); | |
754 | ||
755 | impl Lifetime { | |
756 | pub fn get_ref<'a>(&'a self) -> &'a str { | |
757 | let Lifetime(ref s) = *self; | |
758 | let s: &'a str = s; | |
759 | s | |
760 | } | |
761 | ||
762 | pub fn statik() -> Lifetime { | |
763 | Lifetime("'static".to_string()) | |
764 | } | |
3dfed10e XL |
765 | |
766 | pub fn elided() -> Lifetime { | |
767 | Lifetime("'_".to_string()) | |
768 | } | |
60c5eb7d XL |
769 | } |
770 | ||
771 | #[derive(Clone, Debug)] | |
772 | pub enum WherePredicate { | |
773 | BoundPredicate { ty: Type, bounds: Vec<GenericBound> }, | |
774 | RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> }, | |
775 | EqPredicate { lhs: Type, rhs: Type }, | |
776 | } | |
777 | ||
778 | impl WherePredicate { | |
779 | pub fn get_bounds(&self) -> Option<&[GenericBound]> { | |
780 | match *self { | |
781 | WherePredicate::BoundPredicate { ref bounds, .. } => Some(bounds), | |
782 | WherePredicate::RegionPredicate { ref bounds, .. } => Some(bounds), | |
783 | _ => None, | |
784 | } | |
785 | } | |
786 | } | |
787 | ||
788 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
789 | pub enum GenericParamDefKind { | |
790 | Lifetime, | |
791 | Type { | |
792 | did: DefId, | |
793 | bounds: Vec<GenericBound>, | |
794 | default: Option<Type>, | |
795 | synthetic: Option<hir::SyntheticTyParamKind>, | |
796 | }, | |
797 | Const { | |
798 | did: DefId, | |
799 | ty: Type, | |
800 | }, | |
801 | } | |
802 | ||
803 | impl GenericParamDefKind { | |
804 | pub fn is_type(&self) -> bool { | |
805 | match *self { | |
806 | GenericParamDefKind::Type { .. } => true, | |
807 | _ => false, | |
808 | } | |
809 | } | |
810 | ||
811 | // FIXME(eddyb) this either returns the default of a type parameter, or the | |
812 | // type of a `const` parameter. It seems that the intention is to *visit* | |
813 | // any embedded types, but `get_type` seems to be the wrong name for that. | |
814 | pub fn get_type(&self) -> Option<Type> { | |
815 | match self { | |
816 | GenericParamDefKind::Type { default, .. } => default.clone(), | |
817 | GenericParamDefKind::Const { ty, .. } => Some(ty.clone()), | |
818 | GenericParamDefKind::Lifetime => None, | |
819 | } | |
820 | } | |
821 | } | |
822 | ||
823 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
824 | pub struct GenericParamDef { | |
825 | pub name: String, | |
826 | pub kind: GenericParamDefKind, | |
827 | } | |
828 | ||
829 | impl GenericParamDef { | |
830 | pub fn is_synthetic_type_param(&self) -> bool { | |
831 | match self.kind { | |
dfeec247 | 832 | GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => false, |
60c5eb7d XL |
833 | GenericParamDefKind::Type { ref synthetic, .. } => synthetic.is_some(), |
834 | } | |
835 | } | |
836 | ||
837 | pub fn is_type(&self) -> bool { | |
838 | self.kind.is_type() | |
839 | } | |
840 | ||
841 | pub fn get_type(&self) -> Option<Type> { | |
842 | self.kind.get_type() | |
843 | } | |
844 | ||
845 | pub fn get_bounds(&self) -> Option<&[GenericBound]> { | |
846 | match self.kind { | |
847 | GenericParamDefKind::Type { ref bounds, .. } => Some(bounds), | |
848 | _ => None, | |
849 | } | |
850 | } | |
851 | } | |
852 | ||
853 | // maybe use a Generic enum and use Vec<Generic>? | |
854 | #[derive(Clone, Debug, Default)] | |
855 | pub struct Generics { | |
856 | pub params: Vec<GenericParamDef>, | |
857 | pub where_predicates: Vec<WherePredicate>, | |
858 | } | |
859 | ||
860 | #[derive(Clone, Debug)] | |
861 | pub struct Method { | |
862 | pub generics: Generics, | |
863 | pub decl: FnDecl, | |
864 | pub header: hir::FnHeader, | |
865 | pub defaultness: Option<hir::Defaultness>, | |
ba9703b0 XL |
866 | pub all_types: Vec<(Type, TypeKind)>, |
867 | pub ret_types: Vec<(Type, TypeKind)>, | |
60c5eb7d XL |
868 | } |
869 | ||
870 | #[derive(Clone, Debug)] | |
871 | pub struct TyMethod { | |
872 | pub header: hir::FnHeader, | |
873 | pub decl: FnDecl, | |
874 | pub generics: Generics, | |
ba9703b0 XL |
875 | pub all_types: Vec<(Type, TypeKind)>, |
876 | pub ret_types: Vec<(Type, TypeKind)>, | |
60c5eb7d XL |
877 | } |
878 | ||
879 | #[derive(Clone, Debug)] | |
880 | pub struct Function { | |
881 | pub decl: FnDecl, | |
882 | pub generics: Generics, | |
883 | pub header: hir::FnHeader, | |
ba9703b0 XL |
884 | pub all_types: Vec<(Type, TypeKind)>, |
885 | pub ret_types: Vec<(Type, TypeKind)>, | |
60c5eb7d XL |
886 | } |
887 | ||
888 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
889 | pub struct FnDecl { | |
890 | pub inputs: Arguments, | |
74b04a01 | 891 | pub output: FnRetTy, |
60c5eb7d XL |
892 | pub c_variadic: bool, |
893 | pub attrs: Attributes, | |
894 | } | |
895 | ||
896 | impl FnDecl { | |
897 | pub fn self_type(&self) -> Option<SelfTy> { | |
898 | self.inputs.values.get(0).and_then(|v| v.to_self()) | |
899 | } | |
900 | ||
901 | /// Returns the sugared return type for an async function. | |
902 | /// | |
903 | /// For example, if the return type is `impl std::future::Future<Output = i32>`, this function | |
904 | /// will return `i32`. | |
905 | /// | |
906 | /// # Panics | |
907 | /// | |
908 | /// This function will panic if the return type does not match the expected sugaring for async | |
909 | /// functions. | |
74b04a01 | 910 | pub fn sugared_async_return_type(&self) -> FnRetTy { |
60c5eb7d | 911 | match &self.output { |
74b04a01 | 912 | FnRetTy::Return(Type::ImplTrait(bounds)) => match &bounds[0] { |
dfeec247 XL |
913 | GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => { |
914 | let bindings = trait_.bindings().unwrap(); | |
74b04a01 | 915 | FnRetTy::Return(bindings[0].ty().clone()) |
60c5eb7d | 916 | } |
dfeec247 XL |
917 | _ => panic!("unexpected desugaring of async function"), |
918 | }, | |
60c5eb7d XL |
919 | _ => panic!("unexpected desugaring of async function"), |
920 | } | |
921 | } | |
922 | } | |
923 | ||
924 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
925 | pub struct Arguments { | |
926 | pub values: Vec<Argument>, | |
927 | } | |
928 | ||
929 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
930 | pub struct Argument { | |
931 | pub type_: Type, | |
932 | pub name: String, | |
933 | } | |
934 | ||
935 | #[derive(Clone, PartialEq, Debug)] | |
936 | pub enum SelfTy { | |
937 | SelfValue, | |
938 | SelfBorrowed(Option<Lifetime>, Mutability), | |
939 | SelfExplicit(Type), | |
940 | } | |
941 | ||
942 | impl Argument { | |
943 | pub fn to_self(&self) -> Option<SelfTy> { | |
944 | if self.name != "self" { | |
945 | return None; | |
946 | } | |
947 | if self.type_.is_self_type() { | |
948 | return Some(SelfValue); | |
949 | } | |
950 | match self.type_ { | |
dfeec247 | 951 | BorrowedRef { ref lifetime, mutability, ref type_ } if type_.is_self_type() => { |
60c5eb7d XL |
952 | Some(SelfBorrowed(lifetime.clone(), mutability)) |
953 | } | |
dfeec247 | 954 | _ => Some(SelfExplicit(self.type_.clone())), |
60c5eb7d XL |
955 | } |
956 | } | |
957 | } | |
958 | ||
959 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
74b04a01 | 960 | pub enum FnRetTy { |
60c5eb7d XL |
961 | Return(Type), |
962 | DefaultReturn, | |
963 | } | |
964 | ||
74b04a01 | 965 | impl GetDefId for FnRetTy { |
60c5eb7d XL |
966 | fn def_id(&self) -> Option<DefId> { |
967 | match *self { | |
968 | Return(ref ty) => ty.def_id(), | |
969 | DefaultReturn => None, | |
970 | } | |
971 | } | |
972 | } | |
973 | ||
974 | #[derive(Clone, Debug)] | |
975 | pub struct Trait { | |
976 | pub auto: bool, | |
977 | pub unsafety: hir::Unsafety, | |
978 | pub items: Vec<Item>, | |
979 | pub generics: Generics, | |
980 | pub bounds: Vec<GenericBound>, | |
3dfed10e | 981 | pub is_spotlight: bool, |
60c5eb7d XL |
982 | pub is_auto: bool, |
983 | } | |
984 | ||
985 | #[derive(Clone, Debug)] | |
986 | pub struct TraitAlias { | |
987 | pub generics: Generics, | |
988 | pub bounds: Vec<GenericBound>, | |
989 | } | |
990 | ||
991 | /// A trait reference, which may have higher ranked lifetimes. | |
992 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
993 | pub struct PolyTrait { | |
994 | pub trait_: Type, | |
995 | pub generic_params: Vec<GenericParamDef>, | |
996 | } | |
997 | ||
998 | /// A representation of a type suitable for hyperlinking purposes. Ideally, one can get the original | |
999 | /// type out of the AST/`TyCtxt` given one of these, if more information is needed. Most | |
1000 | /// importantly, it does not preserve mutability or boxes. | |
1001 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
1002 | pub enum Type { | |
1003 | /// Structs/enums/traits (most that would be an `hir::TyKind::Path`). | |
1004 | ResolvedPath { | |
1005 | path: Path, | |
1006 | param_names: Option<Vec<GenericBound>>, | |
1007 | did: DefId, | |
1008 | /// `true` if is a `T::Name` path for associated types. | |
1009 | is_generic: bool, | |
1010 | }, | |
1011 | /// For parameterized types, so the consumer of the JSON don't go | |
1012 | /// looking for types which don't exist anywhere. | |
1013 | Generic(String), | |
1014 | /// Primitives are the fixed-size numeric types (plus int/usize/float), char, | |
1015 | /// arrays, slices, and tuples. | |
1016 | Primitive(PrimitiveType), | |
1017 | /// `extern "ABI" fn` | |
1018 | BareFunction(Box<BareFunctionDecl>), | |
1019 | Tuple(Vec<Type>), | |
1020 | Slice(Box<Type>), | |
1021 | Array(Box<Type>, String), | |
1022 | Never, | |
1023 | RawPointer(Mutability, Box<Type>), | |
1024 | BorrowedRef { | |
1025 | lifetime: Option<Lifetime>, | |
1026 | mutability: Mutability, | |
1027 | type_: Box<Type>, | |
1028 | }, | |
1029 | ||
1030 | // `<Type as Trait>::Name` | |
1031 | QPath { | |
1032 | name: String, | |
1033 | self_type: Box<Type>, | |
dfeec247 | 1034 | trait_: Box<Type>, |
60c5eb7d XL |
1035 | }, |
1036 | ||
1037 | // `_` | |
1038 | Infer, | |
1039 | ||
1040 | // `impl TraitA + TraitB + ...` | |
1041 | ImplTrait(Vec<GenericBound>), | |
1042 | } | |
1043 | ||
1044 | #[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)] | |
1045 | pub enum PrimitiveType { | |
dfeec247 XL |
1046 | Isize, |
1047 | I8, | |
1048 | I16, | |
1049 | I32, | |
1050 | I64, | |
1051 | I128, | |
1052 | Usize, | |
1053 | U8, | |
1054 | U16, | |
1055 | U32, | |
1056 | U64, | |
1057 | U128, | |
1058 | F32, | |
1059 | F64, | |
60c5eb7d XL |
1060 | Char, |
1061 | Bool, | |
1062 | Str, | |
1063 | Slice, | |
1064 | Array, | |
1065 | Tuple, | |
1066 | Unit, | |
1067 | RawPointer, | |
1068 | Reference, | |
1069 | Fn, | |
1070 | Never, | |
1071 | } | |
1072 | ||
ba9703b0 | 1073 | #[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)] |
60c5eb7d XL |
1074 | pub enum TypeKind { |
1075 | Enum, | |
1076 | Function, | |
1077 | Module, | |
1078 | Const, | |
1079 | Static, | |
1080 | Struct, | |
1081 | Union, | |
1082 | Trait, | |
1083 | Typedef, | |
1084 | Foreign, | |
1085 | Macro, | |
1086 | Attr, | |
1087 | Derive, | |
1088 | TraitAlias, | |
1089 | } | |
1090 | ||
1091 | pub trait GetDefId { | |
1092 | fn def_id(&self) -> Option<DefId>; | |
1093 | } | |
1094 | ||
1095 | impl<T: GetDefId> GetDefId for Option<T> { | |
1096 | fn def_id(&self) -> Option<DefId> { | |
1097 | self.as_ref().and_then(|d| d.def_id()) | |
1098 | } | |
1099 | } | |
1100 | ||
1101 | impl Type { | |
1102 | pub fn primitive_type(&self) -> Option<PrimitiveType> { | |
1103 | match *self { | |
dfeec247 | 1104 | Primitive(p) | BorrowedRef { type_: box Primitive(p), .. } => Some(p), |
60c5eb7d XL |
1105 | Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice), |
1106 | Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array), | |
dfeec247 XL |
1107 | Tuple(ref tys) => { |
1108 | if tys.is_empty() { | |
1109 | Some(PrimitiveType::Unit) | |
1110 | } else { | |
1111 | Some(PrimitiveType::Tuple) | |
1112 | } | |
1113 | } | |
60c5eb7d XL |
1114 | RawPointer(..) => Some(PrimitiveType::RawPointer), |
1115 | BorrowedRef { type_: box Generic(..), .. } => Some(PrimitiveType::Reference), | |
1116 | BareFunction(..) => Some(PrimitiveType::Fn), | |
1117 | Never => Some(PrimitiveType::Never), | |
1118 | _ => None, | |
1119 | } | |
1120 | } | |
1121 | ||
1122 | pub fn is_generic(&self) -> bool { | |
1123 | match *self { | |
1124 | ResolvedPath { is_generic, .. } => is_generic, | |
1125 | _ => false, | |
1126 | } | |
1127 | } | |
1128 | ||
1129 | pub fn is_self_type(&self) -> bool { | |
1130 | match *self { | |
1131 | Generic(ref name) => name == "Self", | |
dfeec247 | 1132 | _ => false, |
60c5eb7d XL |
1133 | } |
1134 | } | |
1135 | ||
1136 | pub fn generics(&self) -> Option<Vec<Type>> { | |
1137 | match *self { | |
dfeec247 XL |
1138 | ResolvedPath { ref path, .. } => path.segments.last().and_then(|seg| { |
1139 | if let GenericArgs::AngleBracketed { ref args, .. } = seg.args { | |
1140 | Some( | |
1141 | args.iter() | |
1142 | .filter_map(|arg| match arg { | |
1143 | GenericArg::Type(ty) => Some(ty.clone()), | |
1144 | _ => None, | |
1145 | }) | |
1146 | .collect(), | |
1147 | ) | |
1148 | } else { | |
1149 | None | |
1150 | } | |
1151 | }), | |
60c5eb7d XL |
1152 | _ => None, |
1153 | } | |
1154 | } | |
1155 | ||
1156 | pub fn bindings(&self) -> Option<&[TypeBinding]> { | |
1157 | match *self { | |
dfeec247 XL |
1158 | ResolvedPath { ref path, .. } => path.segments.last().and_then(|seg| { |
1159 | if let GenericArgs::AngleBracketed { ref bindings, .. } = seg.args { | |
1160 | Some(&**bindings) | |
1161 | } else { | |
1162 | None | |
1163 | } | |
1164 | }), | |
1165 | _ => None, | |
60c5eb7d XL |
1166 | } |
1167 | } | |
1168 | ||
1169 | pub fn is_full_generic(&self) -> bool { | |
1170 | match *self { | |
1171 | Type::Generic(_) => true, | |
1172 | _ => false, | |
1173 | } | |
1174 | } | |
1175 | ||
1176 | pub fn projection(&self) -> Option<(&Type, DefId, &str)> { | |
1177 | let (self_, trait_, name) = match self { | |
dfeec247 | 1178 | QPath { ref self_type, ref trait_, ref name } => (self_type, trait_, name), |
60c5eb7d XL |
1179 | _ => return None, |
1180 | }; | |
1181 | let trait_did = match **trait_ { | |
1182 | ResolvedPath { did, .. } => did, | |
1183 | _ => return None, | |
1184 | }; | |
1185 | Some((&self_, trait_did, name)) | |
1186 | } | |
60c5eb7d XL |
1187 | } |
1188 | ||
1189 | impl GetDefId for Type { | |
1190 | fn def_id(&self) -> Option<DefId> { | |
1191 | match *self { | |
1192 | ResolvedPath { did, .. } => Some(did), | |
3dfed10e | 1193 | Primitive(p) => cache().primitive_locations.get(&p).cloned(), |
dfeec247 XL |
1194 | BorrowedRef { type_: box Generic(..), .. } => { |
1195 | Primitive(PrimitiveType::Reference).def_id() | |
1196 | } | |
60c5eb7d | 1197 | BorrowedRef { ref type_, .. } => type_.def_id(), |
dfeec247 XL |
1198 | Tuple(ref tys) => { |
1199 | if tys.is_empty() { | |
1200 | Primitive(PrimitiveType::Unit).def_id() | |
1201 | } else { | |
1202 | Primitive(PrimitiveType::Tuple).def_id() | |
1203 | } | |
1204 | } | |
60c5eb7d XL |
1205 | BareFunction(..) => Primitive(PrimitiveType::Fn).def_id(), |
1206 | Never => Primitive(PrimitiveType::Never).def_id(), | |
1207 | Slice(..) => Primitive(PrimitiveType::Slice).def_id(), | |
1208 | Array(..) => Primitive(PrimitiveType::Array).def_id(), | |
1209 | RawPointer(..) => Primitive(PrimitiveType::RawPointer).def_id(), | |
1210 | QPath { ref self_type, .. } => self_type.def_id(), | |
1211 | _ => None, | |
1212 | } | |
1213 | } | |
1214 | } | |
1215 | ||
1216 | impl PrimitiveType { | |
3dfed10e | 1217 | pub fn from_symbol(s: Symbol) -> Option<PrimitiveType> { |
60c5eb7d | 1218 | match s { |
3dfed10e XL |
1219 | sym::isize => Some(PrimitiveType::Isize), |
1220 | sym::i8 => Some(PrimitiveType::I8), | |
1221 | sym::i16 => Some(PrimitiveType::I16), | |
1222 | sym::i32 => Some(PrimitiveType::I32), | |
1223 | sym::i64 => Some(PrimitiveType::I64), | |
1224 | sym::i128 => Some(PrimitiveType::I128), | |
1225 | sym::usize => Some(PrimitiveType::Usize), | |
1226 | sym::u8 => Some(PrimitiveType::U8), | |
1227 | sym::u16 => Some(PrimitiveType::U16), | |
1228 | sym::u32 => Some(PrimitiveType::U32), | |
1229 | sym::u64 => Some(PrimitiveType::U64), | |
1230 | sym::u128 => Some(PrimitiveType::U128), | |
1231 | sym::bool => Some(PrimitiveType::Bool), | |
1232 | sym::char => Some(PrimitiveType::Char), | |
1233 | sym::str => Some(PrimitiveType::Str), | |
1234 | sym::f32 => Some(PrimitiveType::F32), | |
1235 | sym::f64 => Some(PrimitiveType::F64), | |
1236 | sym::array => Some(PrimitiveType::Array), | |
1237 | sym::slice => Some(PrimitiveType::Slice), | |
1238 | sym::tuple => Some(PrimitiveType::Tuple), | |
1239 | sym::unit => Some(PrimitiveType::Unit), | |
1240 | sym::pointer => Some(PrimitiveType::RawPointer), | |
1241 | sym::reference => Some(PrimitiveType::Reference), | |
1242 | kw::Fn => Some(PrimitiveType::Fn), | |
1243 | sym::never => Some(PrimitiveType::Never), | |
60c5eb7d XL |
1244 | _ => None, |
1245 | } | |
1246 | } | |
1247 | ||
1248 | pub fn as_str(&self) -> &'static str { | |
1249 | use self::PrimitiveType::*; | |
1250 | match *self { | |
1251 | Isize => "isize", | |
1252 | I8 => "i8", | |
1253 | I16 => "i16", | |
1254 | I32 => "i32", | |
1255 | I64 => "i64", | |
1256 | I128 => "i128", | |
1257 | Usize => "usize", | |
1258 | U8 => "u8", | |
1259 | U16 => "u16", | |
1260 | U32 => "u32", | |
1261 | U64 => "u64", | |
1262 | U128 => "u128", | |
1263 | F32 => "f32", | |
1264 | F64 => "f64", | |
1265 | Str => "str", | |
1266 | Bool => "bool", | |
1267 | Char => "char", | |
1268 | Array => "array", | |
1269 | Slice => "slice", | |
1270 | Tuple => "tuple", | |
1271 | Unit => "unit", | |
1272 | RawPointer => "pointer", | |
1273 | Reference => "reference", | |
1274 | Fn => "fn", | |
1275 | Never => "never", | |
1276 | } | |
1277 | } | |
1278 | ||
3dfed10e XL |
1279 | pub fn impls(&self, tcx: TyCtxt<'_>) -> &'static SmallVec<[DefId; 4]> { |
1280 | Self::all_impls(tcx).get(self).expect("missing impl for primitive type") | |
1281 | } | |
1282 | ||
1283 | pub fn all_impls(tcx: TyCtxt<'_>) -> &'static FxHashMap<PrimitiveType, SmallVec<[DefId; 4]>> { | |
1284 | static CELL: OnceCell<FxHashMap<PrimitiveType, SmallVec<[DefId; 4]>>> = OnceCell::new(); | |
1285 | ||
1286 | CELL.get_or_init(move || { | |
1287 | use self::PrimitiveType::*; | |
1288 | ||
1289 | /// A macro to create a FxHashMap. | |
1290 | /// | |
1291 | /// Example: | |
1292 | /// | |
1293 | /// ``` | |
1294 | /// let letters = map!{"a" => "b", "c" => "d"}; | |
1295 | /// ``` | |
1296 | /// | |
1297 | /// Trailing commas are allowed. | |
1298 | /// Commas between elements are required (even if the expression is a block). | |
1299 | macro_rules! map { | |
1300 | ($( $key: expr => $val: expr ),* $(,)*) => {{ | |
1301 | let mut map = ::rustc_data_structures::fx::FxHashMap::default(); | |
1302 | $( map.insert($key, $val); )* | |
1303 | map | |
1304 | }} | |
1305 | } | |
1306 | ||
1307 | let single = |a: Option<DefId>| a.into_iter().collect(); | |
1308 | let both = |a: Option<DefId>, b: Option<DefId>| -> SmallVec<_> { | |
1309 | a.into_iter().chain(b).collect() | |
1310 | }; | |
1311 | ||
1312 | let lang_items = tcx.lang_items(); | |
1313 | map! { | |
1314 | Isize => single(lang_items.isize_impl()), | |
1315 | I8 => single(lang_items.i8_impl()), | |
1316 | I16 => single(lang_items.i16_impl()), | |
1317 | I32 => single(lang_items.i32_impl()), | |
1318 | I64 => single(lang_items.i64_impl()), | |
1319 | I128 => single(lang_items.i128_impl()), | |
1320 | Usize => single(lang_items.usize_impl()), | |
1321 | U8 => single(lang_items.u8_impl()), | |
1322 | U16 => single(lang_items.u16_impl()), | |
1323 | U32 => single(lang_items.u32_impl()), | |
1324 | U64 => single(lang_items.u64_impl()), | |
1325 | U128 => single(lang_items.u128_impl()), | |
1326 | F32 => both(lang_items.f32_impl(), lang_items.f32_runtime_impl()), | |
1327 | F64 => both(lang_items.f64_impl(), lang_items.f64_runtime_impl()), | |
1328 | Char => single(lang_items.char_impl()), | |
1329 | Bool => single(lang_items.bool_impl()), | |
1330 | Str => both(lang_items.str_impl(), lang_items.str_alloc_impl()), | |
1331 | Slice => { | |
1332 | lang_items | |
1333 | .slice_impl() | |
1334 | .into_iter() | |
1335 | .chain(lang_items.slice_u8_impl()) | |
1336 | .chain(lang_items.slice_alloc_impl()) | |
1337 | .chain(lang_items.slice_u8_alloc_impl()) | |
1338 | .collect() | |
1339 | }, | |
1340 | Array => single(lang_items.array_impl()), | |
1341 | Tuple => smallvec![], | |
1342 | Unit => smallvec![], | |
1343 | RawPointer => { | |
1344 | lang_items | |
1345 | .const_ptr_impl() | |
1346 | .into_iter() | |
1347 | .chain(lang_items.mut_ptr_impl()) | |
1348 | .chain(lang_items.const_slice_ptr_impl()) | |
1349 | .chain(lang_items.mut_slice_ptr_impl()) | |
1350 | .collect() | |
1351 | }, | |
1352 | Reference => smallvec![], | |
1353 | Fn => smallvec![], | |
1354 | Never => smallvec![], | |
1355 | } | |
1356 | }) | |
1357 | } | |
1358 | ||
60c5eb7d XL |
1359 | pub fn to_url_str(&self) -> &'static str { |
1360 | self.as_str() | |
1361 | } | |
1362 | } | |
1363 | ||
1364 | impl From<ast::IntTy> for PrimitiveType { | |
1365 | fn from(int_ty: ast::IntTy) -> PrimitiveType { | |
1366 | match int_ty { | |
1367 | ast::IntTy::Isize => PrimitiveType::Isize, | |
1368 | ast::IntTy::I8 => PrimitiveType::I8, | |
1369 | ast::IntTy::I16 => PrimitiveType::I16, | |
1370 | ast::IntTy::I32 => PrimitiveType::I32, | |
1371 | ast::IntTy::I64 => PrimitiveType::I64, | |
1372 | ast::IntTy::I128 => PrimitiveType::I128, | |
1373 | } | |
1374 | } | |
1375 | } | |
1376 | ||
1377 | impl From<ast::UintTy> for PrimitiveType { | |
1378 | fn from(uint_ty: ast::UintTy) -> PrimitiveType { | |
1379 | match uint_ty { | |
1380 | ast::UintTy::Usize => PrimitiveType::Usize, | |
1381 | ast::UintTy::U8 => PrimitiveType::U8, | |
1382 | ast::UintTy::U16 => PrimitiveType::U16, | |
1383 | ast::UintTy::U32 => PrimitiveType::U32, | |
1384 | ast::UintTy::U64 => PrimitiveType::U64, | |
1385 | ast::UintTy::U128 => PrimitiveType::U128, | |
1386 | } | |
1387 | } | |
1388 | } | |
1389 | ||
1390 | impl From<ast::FloatTy> for PrimitiveType { | |
1391 | fn from(float_ty: ast::FloatTy) -> PrimitiveType { | |
1392 | match float_ty { | |
1393 | ast::FloatTy::F32 => PrimitiveType::F32, | |
1394 | ast::FloatTy::F64 => PrimitiveType::F64, | |
1395 | } | |
1396 | } | |
1397 | } | |
1398 | ||
74b04a01 XL |
1399 | impl From<hir::PrimTy> for PrimitiveType { |
1400 | fn from(prim_ty: hir::PrimTy) -> PrimitiveType { | |
1401 | match prim_ty { | |
1402 | hir::PrimTy::Int(int_ty) => int_ty.into(), | |
1403 | hir::PrimTy::Uint(uint_ty) => uint_ty.into(), | |
1404 | hir::PrimTy::Float(float_ty) => float_ty.into(), | |
1405 | hir::PrimTy::Str => PrimitiveType::Str, | |
1406 | hir::PrimTy::Bool => PrimitiveType::Bool, | |
1407 | hir::PrimTy::Char => PrimitiveType::Char, | |
1408 | } | |
1409 | } | |
1410 | } | |
1411 | ||
60c5eb7d XL |
1412 | #[derive(Clone, PartialEq, Eq, Debug)] |
1413 | pub enum Visibility { | |
1414 | Public, | |
1415 | Inherited, | |
1416 | Crate, | |
1417 | Restricted(DefId, Path), | |
1418 | } | |
1419 | ||
1420 | #[derive(Clone, Debug)] | |
1421 | pub struct Struct { | |
1422 | pub struct_type: doctree::StructType, | |
1423 | pub generics: Generics, | |
1424 | pub fields: Vec<Item>, | |
1425 | pub fields_stripped: bool, | |
1426 | } | |
1427 | ||
1428 | #[derive(Clone, Debug)] | |
1429 | pub struct Union { | |
1430 | pub struct_type: doctree::StructType, | |
1431 | pub generics: Generics, | |
1432 | pub fields: Vec<Item>, | |
1433 | pub fields_stripped: bool, | |
1434 | } | |
1435 | ||
1436 | /// This is a more limited form of the standard Struct, different in that | |
1437 | /// it lacks the things most items have (name, id, parameterization). Found | |
1438 | /// only as a variant in an enum. | |
1439 | #[derive(Clone, Debug)] | |
1440 | pub struct VariantStruct { | |
1441 | pub struct_type: doctree::StructType, | |
1442 | pub fields: Vec<Item>, | |
1443 | pub fields_stripped: bool, | |
1444 | } | |
1445 | ||
1446 | #[derive(Clone, Debug)] | |
1447 | pub struct Enum { | |
1448 | pub variants: IndexVec<VariantIdx, Item>, | |
1449 | pub generics: Generics, | |
1450 | pub variants_stripped: bool, | |
1451 | } | |
1452 | ||
1453 | #[derive(Clone, Debug)] | |
1454 | pub struct Variant { | |
1455 | pub kind: VariantKind, | |
1456 | } | |
1457 | ||
1458 | #[derive(Clone, Debug)] | |
1459 | pub enum VariantKind { | |
1460 | CLike, | |
1461 | Tuple(Vec<Type>), | |
1462 | Struct(VariantStruct), | |
1463 | } | |
1464 | ||
1465 | #[derive(Clone, Debug)] | |
1466 | pub struct Span { | |
1467 | pub filename: FileName, | |
ba9703b0 | 1468 | pub cnum: CrateNum, |
60c5eb7d XL |
1469 | pub loline: usize, |
1470 | pub locol: usize, | |
1471 | pub hiline: usize, | |
1472 | pub hicol: usize, | |
dfeec247 | 1473 | pub original: rustc_span::Span, |
60c5eb7d XL |
1474 | } |
1475 | ||
1476 | impl Span { | |
1477 | pub fn empty() -> Span { | |
1478 | Span { | |
1479 | filename: FileName::Anon(0), | |
ba9703b0 | 1480 | cnum: LOCAL_CRATE, |
dfeec247 XL |
1481 | loline: 0, |
1482 | locol: 0, | |
1483 | hiline: 0, | |
1484 | hicol: 0, | |
1485 | original: rustc_span::DUMMY_SP, | |
60c5eb7d XL |
1486 | } |
1487 | } | |
1488 | ||
dfeec247 | 1489 | pub fn span(&self) -> rustc_span::Span { |
60c5eb7d XL |
1490 | self.original |
1491 | } | |
1492 | } | |
1493 | ||
1494 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
1495 | pub struct Path { | |
1496 | pub global: bool, | |
1497 | pub res: Res, | |
1498 | pub segments: Vec<PathSegment>, | |
1499 | } | |
1500 | ||
1501 | impl Path { | |
1502 | pub fn last_name(&self) -> &str { | |
1503 | self.segments.last().expect("segments were empty").name.as_str() | |
1504 | } | |
1505 | } | |
1506 | ||
1507 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
1508 | pub enum GenericArg { | |
1509 | Lifetime(Lifetime), | |
1510 | Type(Type), | |
1511 | Const(Constant), | |
1512 | } | |
1513 | ||
1514 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
1515 | pub enum GenericArgs { | |
dfeec247 XL |
1516 | AngleBracketed { args: Vec<GenericArg>, bindings: Vec<TypeBinding> }, |
1517 | Parenthesized { inputs: Vec<Type>, output: Option<Type> }, | |
60c5eb7d XL |
1518 | } |
1519 | ||
1520 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
1521 | pub struct PathSegment { | |
1522 | pub name: String, | |
1523 | pub args: GenericArgs, | |
1524 | } | |
1525 | ||
1526 | #[derive(Clone, Debug)] | |
1527 | pub struct Typedef { | |
1528 | pub type_: Type, | |
1529 | pub generics: Generics, | |
dfeec247 XL |
1530 | // Type of target item. |
1531 | pub item_type: Option<Type>, | |
1532 | } | |
1533 | ||
1534 | impl GetDefId for Typedef { | |
1535 | fn def_id(&self) -> Option<DefId> { | |
1536 | self.type_.def_id() | |
1537 | } | |
60c5eb7d XL |
1538 | } |
1539 | ||
1540 | #[derive(Clone, Debug)] | |
1541 | pub struct OpaqueTy { | |
1542 | pub bounds: Vec<GenericBound>, | |
1543 | pub generics: Generics, | |
1544 | } | |
1545 | ||
1546 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
1547 | pub struct BareFunctionDecl { | |
1548 | pub unsafety: hir::Unsafety, | |
1549 | pub generic_params: Vec<GenericParamDef>, | |
1550 | pub decl: FnDecl, | |
1551 | pub abi: Abi, | |
1552 | } | |
1553 | ||
1554 | #[derive(Clone, Debug)] | |
1555 | pub struct Static { | |
1556 | pub type_: Type, | |
1557 | pub mutability: Mutability, | |
1558 | /// It's useful to have the value of a static documented, but I have no | |
1559 | /// desire to represent expressions (that'd basically be all of the AST, | |
1560 | /// which is huge!). So, have a string. | |
1561 | pub expr: String, | |
1562 | } | |
1563 | ||
1564 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] | |
1565 | pub struct Constant { | |
1566 | pub type_: Type, | |
1567 | pub expr: String, | |
dfeec247 XL |
1568 | pub value: Option<String>, |
1569 | pub is_literal: bool, | |
60c5eb7d XL |
1570 | } |
1571 | ||
1572 | #[derive(Clone, PartialEq, Debug)] | |
1573 | pub enum ImplPolarity { | |
1574 | Positive, | |
1575 | Negative, | |
1576 | } | |
1577 | ||
1578 | #[derive(Clone, Debug)] | |
1579 | pub struct Impl { | |
1580 | pub unsafety: hir::Unsafety, | |
1581 | pub generics: Generics, | |
1582 | pub provided_trait_methods: FxHashSet<String>, | |
1583 | pub trait_: Option<Type>, | |
1584 | pub for_: Type, | |
1585 | pub items: Vec<Item>, | |
1586 | pub polarity: Option<ImplPolarity>, | |
1587 | pub synthetic: bool, | |
1588 | pub blanket_impl: Option<Type>, | |
1589 | } | |
1590 | ||
1591 | #[derive(Clone, Debug)] | |
1592 | pub enum Import { | |
1593 | // use source as str; | |
1594 | Simple(String, ImportSource), | |
1595 | // use source::*; | |
dfeec247 | 1596 | Glob(ImportSource), |
60c5eb7d XL |
1597 | } |
1598 | ||
1599 | #[derive(Clone, Debug)] | |
1600 | pub struct ImportSource { | |
1601 | pub path: Path, | |
1602 | pub did: Option<DefId>, | |
1603 | } | |
1604 | ||
1605 | #[derive(Clone, Debug)] | |
1606 | pub struct Macro { | |
1607 | pub source: String, | |
1608 | pub imported_from: Option<String>, | |
1609 | } | |
1610 | ||
1611 | #[derive(Clone, Debug)] | |
1612 | pub struct ProcMacro { | |
1613 | pub kind: MacroKind, | |
1614 | pub helpers: Vec<String>, | |
1615 | } | |
1616 | ||
1617 | #[derive(Clone, Debug)] | |
1618 | pub struct Stability { | |
1619 | pub level: stability::StabilityLevel, | |
3dfed10e | 1620 | pub feature: String, |
60c5eb7d | 1621 | pub since: String, |
60c5eb7d XL |
1622 | pub unstable_reason: Option<String>, |
1623 | pub issue: Option<NonZeroU32>, | |
1624 | } | |
1625 | ||
1626 | #[derive(Clone, Debug)] | |
1627 | pub struct Deprecation { | |
1628 | pub since: Option<String>, | |
1629 | pub note: Option<String>, | |
3dfed10e | 1630 | pub is_since_rustc_version: bool, |
60c5eb7d XL |
1631 | } |
1632 | ||
1633 | /// An type binding on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or | |
1634 | /// `A: Send + Sync` in `Foo<A: Send + Sync>`). | |
1635 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
1636 | pub struct TypeBinding { | |
1637 | pub name: String, | |
1638 | pub kind: TypeBindingKind, | |
1639 | } | |
1640 | ||
1641 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
1642 | pub enum TypeBindingKind { | |
dfeec247 XL |
1643 | Equality { ty: Type }, |
1644 | Constraint { bounds: Vec<GenericBound> }, | |
60c5eb7d XL |
1645 | } |
1646 | ||
1647 | impl TypeBinding { | |
1648 | pub fn ty(&self) -> &Type { | |
1649 | match self.kind { | |
1650 | TypeBindingKind::Equality { ref ty } => ty, | |
1651 | _ => panic!("expected equality type binding for parenthesized generic args"), | |
1652 | } | |
1653 | } | |
1654 | } |