mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 00:03:43 +00:00
rustdoc-search: simplify rules for generics and type params
This commit is a response to feedback on the displayed type signatures results, by making generics act stricter. Generics are tightened by making order significant. This means `Vec<Allocator>` now matches only with a true vector of allocators, instead of matching the second type param. It also makes unboxing within generics stricter, so `Result<A, B>` only matches if `B` is in the error type and `A` is in the success type. The top level of the function search is unaffected. Find the discussion on: * <https://rust-lang.zulipchat.com/#narrow/stream/393423-t-rustdoc.2Fmeetings/topic/meeting.202024-07-08/near/449965149> * <https://github.com/rust-lang/rust/pull/124544#issuecomment-2204272265> * <https://rust-lang.zulipchat.com/#narrow/channel/266220-t-rustdoc/topic/deciding.20on.20semantics.20of.20generics.20in.20rustdoc.20search/near/476841363>
This commit is contained in:
parent
20a4b4fea1
commit
12dc24f460
@ -204,6 +204,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
"meant for internal use only" {
|
||||
keyword => rustdoc_internals
|
||||
fake_variadic => rustdoc_internals
|
||||
search_unbox => rustdoc_internals
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -234,6 +234,9 @@ passes_doc_masked_only_extern_crate =
|
||||
passes_doc_rust_logo =
|
||||
the `#[doc(rust_logo)]` attribute is used for Rust branding
|
||||
|
||||
passes_doc_search_unbox_invalid =
|
||||
`#[doc(search_unbox)]` should be used on generic structs and enums
|
||||
|
||||
passes_doc_test_literal = `#![doc(test(...)]` does not take a literal
|
||||
|
||||
passes_doc_test_takes_list =
|
||||
|
@ -16,8 +16,8 @@ use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, B
|
||||
use rustc_hir::def_id::LocalModDefId;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::{
|
||||
self as hir, self, CRATE_HIR_ID, CRATE_OWNER_ID, FnSig, ForeignItem, HirId, Item, ItemKind,
|
||||
MethodKind, Safety, Target, TraitItem,
|
||||
self as hir, self, AssocItemKind, CRATE_HIR_ID, CRATE_OWNER_ID, FnSig, ForeignItem, HirId,
|
||||
Item, ItemKind, MethodKind, Safety, Target, TraitItem,
|
||||
};
|
||||
use rustc_macros::LintDiagnostic;
|
||||
use rustc_middle::hir::nested_filter;
|
||||
@ -940,6 +940,23 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_doc_search_unbox(&self, meta: &MetaItemInner, hir_id: HirId) {
|
||||
let hir::Node::Item(item) = self.tcx.hir_node(hir_id) else {
|
||||
self.dcx().emit_err(errors::DocSearchUnboxInvalid { span: meta.span() });
|
||||
return;
|
||||
};
|
||||
match item.kind {
|
||||
ItemKind::Enum(_, generics) | ItemKind::Struct(_, generics)
|
||||
if generics.params.len() != 0 => {}
|
||||
ItemKind::Trait(_, _, generics, _, items)
|
||||
if generics.params.len() != 0
|
||||
|| items.iter().any(|item| matches!(item.kind, AssocItemKind::Type)) => {}
|
||||
_ => {
|
||||
self.dcx().emit_err(errors::DocSearchUnboxInvalid { span: meta.span() });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks `#[doc(inline)]`/`#[doc(no_inline)]` attributes.
|
||||
///
|
||||
/// A doc inlining attribute is invalid if it is applied to a non-`use` item, or
|
||||
@ -1152,6 +1169,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
sym::search_unbox => {
|
||||
if self.check_attr_not_crate_level(meta, hir_id, "fake_variadic") {
|
||||
self.check_doc_search_unbox(meta, hir_id);
|
||||
}
|
||||
}
|
||||
|
||||
sym::test => {
|
||||
if self.check_attr_crate_level(attr, meta, hir_id) {
|
||||
self.check_test_attr(meta, hir_id);
|
||||
|
@ -244,6 +244,13 @@ pub(crate) struct DocKeywordOnlyImpl {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_doc_search_unbox_invalid)]
|
||||
pub(crate) struct DocSearchUnboxInvalid {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_doc_inline_conflict)]
|
||||
#[help]
|
||||
|
@ -1762,6 +1762,7 @@ symbols! {
|
||||
saturating_add,
|
||||
saturating_div,
|
||||
saturating_sub,
|
||||
search_unbox,
|
||||
select_unpredictable,
|
||||
self_in_typedefs,
|
||||
self_struct_ctor,
|
||||
|
@ -225,6 +225,7 @@ pub use thin::ThinBox;
|
||||
#[fundamental]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_insignificant_dtor]
|
||||
#[cfg_attr(not(bootstrap), doc(search_unbox))]
|
||||
// The declaration of the `Box` struct must be kept in sync with the
|
||||
// compiler or ICEs will happen.
|
||||
pub struct Box<
|
||||
|
@ -307,6 +307,7 @@ fn rc_inner_layout_for_value_layout(layout: Layout) -> Layout {
|
||||
/// `value.get_mut()`. This avoids conflicts with methods of the inner type `T`.
|
||||
///
|
||||
/// [get_mut]: Rc::get_mut
|
||||
#[cfg_attr(not(bootstrap), doc(search_unbox))]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "Rc")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_insignificant_dtor]
|
||||
|
@ -235,6 +235,7 @@ macro_rules! acquire {
|
||||
/// counting in general.
|
||||
///
|
||||
/// [rc_examples]: crate::rc#examples
|
||||
#[cfg_attr(not(bootstrap), doc(search_unbox))]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "Arc")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_insignificant_dtor]
|
||||
|
@ -25,6 +25,7 @@ use crate::task::{Context, Poll};
|
||||
/// [`async`]: ../../std/keyword.async.html
|
||||
/// [`Waker`]: crate::task::Waker
|
||||
#[doc(notable_trait)]
|
||||
#[cfg_attr(not(bootstrap), doc(search_unbox))]
|
||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||
#[stable(feature = "futures_api", since = "1.36.0")]
|
||||
#[lang = "future_trait"]
|
||||
|
@ -563,6 +563,7 @@ use crate::pin::Pin;
|
||||
use crate::{cmp, convert, hint, mem, slice};
|
||||
|
||||
/// The `Option` type. See [the module level documentation](self) for more.
|
||||
#[cfg_attr(not(bootstrap), doc(search_unbox))]
|
||||
#[derive(Copy, Eq, Debug, Hash)]
|
||||
#[rustc_diagnostic_item = "Option"]
|
||||
#[lang = "Option"]
|
||||
|
@ -520,6 +520,7 @@ use crate::{convert, fmt, hint};
|
||||
/// `Result` is a type that represents either success ([`Ok`]) or failure ([`Err`]).
|
||||
///
|
||||
/// See the [module documentation](self) for details.
|
||||
#[cfg_attr(not(bootstrap), doc(search_unbox))]
|
||||
#[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
|
||||
#[must_use = "this `Result` may be an `Err` variant, which should be handled"]
|
||||
#[rustc_diagnostic_item = "Result"]
|
||||
|
@ -130,29 +130,31 @@ pub trait MyTrait {
|
||||
/// This function can be found using the following search queries:
|
||||
///
|
||||
/// MyTrait<First=u8, Second=u32> -> bool
|
||||
/// MyTrait<u32, First=u8> -> bool
|
||||
/// MyTrait<Second=u32> -> bool
|
||||
/// MyTrait<u32, u8> -> bool
|
||||
///
|
||||
/// The following queries, however, will *not* match it:
|
||||
///
|
||||
/// MyTrait<First=u32> -> bool
|
||||
/// MyTrait<u32, u32> -> bool
|
||||
/// MyTrait<u32, First=u8> -> bool
|
||||
/// MyTrait<u32, u8> -> bool
|
||||
pub fn my_fn(x: impl MyTrait<First=u8, Second=u32>) -> bool { true }
|
||||
```
|
||||
|
||||
Generics and function parameters are order-agnostic, but sensitive to nesting
|
||||
Function parameters are order-agnostic, but sensitive to nesting
|
||||
and number of matches. For example, a function with the signature
|
||||
`fn read_all(&mut self: impl Read) -> Result<Vec<u8>, Error>`
|
||||
will match these queries:
|
||||
|
||||
* `&mut Read -> Result<Vec<u8>, Error>`
|
||||
* `Read -> Result<Vec<u8>, Error>`
|
||||
* `Read -> Result<Error, Vec>`
|
||||
* `Read -> Result<Vec<u8>>`
|
||||
* `Read -> u8`
|
||||
|
||||
But it *does not* match `Result<Vec, u8>` or `Result<u8<Vec>>`.
|
||||
But it *does not* match `Result<Vec, u8>` or `Result<u8<Vec>>`,
|
||||
because those are nested incorrectly, and it does not match
|
||||
`Result<Error, Vec<u8>>` or `Result<Error>`, because those are
|
||||
in the wrong order.
|
||||
|
||||
To search for a function that accepts a function as a parameter,
|
||||
like `Iterator::all`, wrap the nested signature in parenthesis,
|
||||
|
@ -13,8 +13,8 @@ use serde::ser::{Serialize, SerializeSeq, SerializeStruct, Serializer};
|
||||
use thin_vec::ThinVec;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::clean;
|
||||
use crate::clean::types::{Function, Generics, ItemId, Type, WherePredicate};
|
||||
use crate::clean::{self, utils};
|
||||
use crate::formats::cache::{Cache, OrphanImplItem};
|
||||
use crate::formats::item_type::ItemType;
|
||||
use crate::html::format::join_with_double_colon;
|
||||
@ -66,7 +66,7 @@ pub(crate) fn build_index<'tcx>(
|
||||
let mut associated_types = FxHashMap::default();
|
||||
|
||||
// item type, display path, re-exported internal path
|
||||
let mut crate_paths: Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>)> = vec![];
|
||||
let mut crate_paths: Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>, bool)> = vec![];
|
||||
|
||||
// Attach all orphan items to the type's definition if the type
|
||||
// has since been learned.
|
||||
@ -132,10 +132,11 @@ pub(crate) fn build_index<'tcx>(
|
||||
map: &mut FxHashMap<F, isize>,
|
||||
itemid: F,
|
||||
lastpathid: &mut isize,
|
||||
crate_paths: &mut Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>)>,
|
||||
crate_paths: &mut Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>, bool)>,
|
||||
item_type: ItemType,
|
||||
path: &[Symbol],
|
||||
exact_path: Option<&[Symbol]>,
|
||||
search_unbox: bool,
|
||||
) -> RenderTypeId {
|
||||
match map.entry(itemid) {
|
||||
Entry::Occupied(entry) => RenderTypeId::Index(*entry.get()),
|
||||
@ -147,6 +148,7 @@ pub(crate) fn build_index<'tcx>(
|
||||
item_type,
|
||||
path.to_vec(),
|
||||
exact_path.map(|path| path.to_vec()),
|
||||
search_unbox,
|
||||
));
|
||||
RenderTypeId::Index(pathid)
|
||||
}
|
||||
@ -160,9 +162,21 @@ pub(crate) fn build_index<'tcx>(
|
||||
primitives: &mut FxHashMap<Symbol, isize>,
|
||||
associated_types: &mut FxHashMap<Symbol, isize>,
|
||||
lastpathid: &mut isize,
|
||||
crate_paths: &mut Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>)>,
|
||||
crate_paths: &mut Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>, bool)>,
|
||||
tcx: TyCtxt<'_>,
|
||||
) -> Option<RenderTypeId> {
|
||||
use crate::clean::PrimitiveType;
|
||||
let Cache { ref paths, ref external_paths, ref exact_paths, .. } = *cache;
|
||||
let search_unbox = match id {
|
||||
RenderTypeId::Mut => false,
|
||||
RenderTypeId::DefId(defid) => utils::has_doc_flag(tcx, defid, sym::search_unbox),
|
||||
RenderTypeId::Primitive(PrimitiveType::Reference | PrimitiveType::Tuple) => true,
|
||||
RenderTypeId::Primitive(..) => false,
|
||||
RenderTypeId::AssociatedType(..) => false,
|
||||
// this bool is only used by `insert_into_map`, so it doesn't matter what we set here
|
||||
// because Index means we've already inserted into the map
|
||||
RenderTypeId::Index(_) => false,
|
||||
};
|
||||
match id {
|
||||
RenderTypeId::Mut => Some(insert_into_map(
|
||||
primitives,
|
||||
@ -172,6 +186,7 @@ pub(crate) fn build_index<'tcx>(
|
||||
ItemType::Keyword,
|
||||
&[kw::Mut],
|
||||
None,
|
||||
search_unbox,
|
||||
)),
|
||||
RenderTypeId::DefId(defid) => {
|
||||
if let Some(&(ref fqp, item_type)) =
|
||||
@ -195,6 +210,7 @@ pub(crate) fn build_index<'tcx>(
|
||||
item_type,
|
||||
fqp,
|
||||
exact_fqp.map(|x| &x[..]).filter(|exact_fqp| exact_fqp != fqp),
|
||||
search_unbox,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
@ -210,6 +226,7 @@ pub(crate) fn build_index<'tcx>(
|
||||
ItemType::Primitive,
|
||||
&[sym],
|
||||
None,
|
||||
search_unbox,
|
||||
))
|
||||
}
|
||||
RenderTypeId::Index(_) => Some(id),
|
||||
@ -221,6 +238,7 @@ pub(crate) fn build_index<'tcx>(
|
||||
ItemType::AssocType,
|
||||
&[sym],
|
||||
None,
|
||||
search_unbox,
|
||||
)),
|
||||
}
|
||||
}
|
||||
@ -232,7 +250,8 @@ pub(crate) fn build_index<'tcx>(
|
||||
primitives: &mut FxHashMap<Symbol, isize>,
|
||||
associated_types: &mut FxHashMap<Symbol, isize>,
|
||||
lastpathid: &mut isize,
|
||||
crate_paths: &mut Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>)>,
|
||||
crate_paths: &mut Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>, bool)>,
|
||||
tcx: TyCtxt<'_>,
|
||||
) {
|
||||
if let Some(generics) = &mut ty.generics {
|
||||
for item in generics {
|
||||
@ -244,6 +263,7 @@ pub(crate) fn build_index<'tcx>(
|
||||
associated_types,
|
||||
lastpathid,
|
||||
crate_paths,
|
||||
tcx,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -257,6 +277,7 @@ pub(crate) fn build_index<'tcx>(
|
||||
associated_types,
|
||||
lastpathid,
|
||||
crate_paths,
|
||||
tcx,
|
||||
);
|
||||
let Some(converted_associated_type) = converted_associated_type else {
|
||||
return false;
|
||||
@ -271,6 +292,7 @@ pub(crate) fn build_index<'tcx>(
|
||||
associated_types,
|
||||
lastpathid,
|
||||
crate_paths,
|
||||
tcx,
|
||||
);
|
||||
}
|
||||
true
|
||||
@ -288,6 +310,7 @@ pub(crate) fn build_index<'tcx>(
|
||||
associated_types,
|
||||
lastpathid,
|
||||
crate_paths,
|
||||
tcx,
|
||||
);
|
||||
}
|
||||
if let Some(search_type) = &mut item.search_type {
|
||||
@ -300,6 +323,7 @@ pub(crate) fn build_index<'tcx>(
|
||||
&mut associated_types,
|
||||
&mut lastpathid,
|
||||
&mut crate_paths,
|
||||
tcx,
|
||||
);
|
||||
}
|
||||
for item in &mut search_type.output {
|
||||
@ -311,6 +335,7 @@ pub(crate) fn build_index<'tcx>(
|
||||
&mut associated_types,
|
||||
&mut lastpathid,
|
||||
&mut crate_paths,
|
||||
tcx,
|
||||
);
|
||||
}
|
||||
for constraint in &mut search_type.where_clause {
|
||||
@ -323,6 +348,7 @@ pub(crate) fn build_index<'tcx>(
|
||||
&mut associated_types,
|
||||
&mut lastpathid,
|
||||
&mut crate_paths,
|
||||
tcx,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -350,7 +376,12 @@ pub(crate) fn build_index<'tcx>(
|
||||
.filter(|exact_fqp| {
|
||||
exact_fqp.last() == Some(&item.name) && *exact_fqp != fqp
|
||||
});
|
||||
crate_paths.push((short, fqp.clone(), exact_fqp.cloned()));
|
||||
crate_paths.push((
|
||||
short,
|
||||
fqp.clone(),
|
||||
exact_fqp.cloned(),
|
||||
utils::has_doc_flag(tcx, defid, sym::search_unbox),
|
||||
));
|
||||
Some(pathid)
|
||||
} else {
|
||||
None
|
||||
@ -431,7 +462,7 @@ pub(crate) fn build_index<'tcx>(
|
||||
|
||||
struct CrateData<'a> {
|
||||
items: Vec<&'a IndexItem>,
|
||||
paths: Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>)>,
|
||||
paths: Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>, bool)>,
|
||||
// The String is alias name and the vec is the list of the elements with this alias.
|
||||
//
|
||||
// To be noted: the `usize` elements are indexes to `items`.
|
||||
@ -450,6 +481,7 @@ pub(crate) fn build_index<'tcx>(
|
||||
name: Symbol,
|
||||
path: Option<usize>,
|
||||
exact_path: Option<usize>,
|
||||
search_unbox: bool,
|
||||
}
|
||||
|
||||
impl Serialize for Paths {
|
||||
@ -467,6 +499,15 @@ pub(crate) fn build_index<'tcx>(
|
||||
assert!(self.path.is_some());
|
||||
seq.serialize_element(path)?;
|
||||
}
|
||||
if self.search_unbox {
|
||||
if self.path.is_none() {
|
||||
seq.serialize_element(&None::<u8>)?;
|
||||
}
|
||||
if self.exact_path.is_none() {
|
||||
seq.serialize_element(&None::<u8>)?;
|
||||
}
|
||||
seq.serialize_element(&1)?;
|
||||
}
|
||||
seq.end()
|
||||
}
|
||||
}
|
||||
@ -489,9 +530,15 @@ pub(crate) fn build_index<'tcx>(
|
||||
mod_paths.insert(&item.path, index);
|
||||
}
|
||||
let mut paths = Vec::with_capacity(self.paths.len());
|
||||
for (ty, path, exact) in &self.paths {
|
||||
for &(ty, ref path, ref exact, search_unbox) in &self.paths {
|
||||
if path.len() < 2 {
|
||||
paths.push(Paths { ty: *ty, name: path[0], path: None, exact_path: None });
|
||||
paths.push(Paths {
|
||||
ty,
|
||||
name: path[0],
|
||||
path: None,
|
||||
exact_path: None,
|
||||
search_unbox,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
let full_path = join_with_double_colon(&path[..path.len() - 1]);
|
||||
@ -517,10 +564,11 @@ pub(crate) fn build_index<'tcx>(
|
||||
});
|
||||
if let Some(index) = mod_paths.get(&full_path) {
|
||||
paths.push(Paths {
|
||||
ty: *ty,
|
||||
ty,
|
||||
name: *path.last().unwrap(),
|
||||
path: Some(*index),
|
||||
exact_path,
|
||||
search_unbox,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
@ -532,10 +580,11 @@ pub(crate) fn build_index<'tcx>(
|
||||
match extra_paths.entry(full_path.clone()) {
|
||||
Entry::Occupied(entry) => {
|
||||
paths.push(Paths {
|
||||
ty: *ty,
|
||||
ty,
|
||||
name: *path.last().unwrap(),
|
||||
path: Some(*entry.get()),
|
||||
exact_path,
|
||||
search_unbox,
|
||||
});
|
||||
}
|
||||
Entry::Vacant(entry) => {
|
||||
@ -544,10 +593,11 @@ pub(crate) fn build_index<'tcx>(
|
||||
revert_extra_paths.insert(index, full_path);
|
||||
}
|
||||
paths.push(Paths {
|
||||
ty: *ty,
|
||||
ty,
|
||||
name: *path.last().unwrap(),
|
||||
path: Some(index),
|
||||
exact_path,
|
||||
search_unbox,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1327,6 +1327,7 @@ class DocSearch {
|
||||
exactPath: null,
|
||||
generics,
|
||||
bindings,
|
||||
unboxFlag: true,
|
||||
};
|
||||
} else if (pathIndex === 0) {
|
||||
// `0` is used as a sentinel because it's fewer bytes than `null`
|
||||
@ -1338,6 +1339,7 @@ class DocSearch {
|
||||
exactPath: null,
|
||||
generics,
|
||||
bindings,
|
||||
unboxFlag: true,
|
||||
};
|
||||
} else {
|
||||
const item = lowercasePaths[pathIndex - 1];
|
||||
@ -1353,6 +1355,7 @@ class DocSearch {
|
||||
exactPath: item.exactPath,
|
||||
generics,
|
||||
bindings,
|
||||
unboxFlag: item.unboxFlag,
|
||||
};
|
||||
}
|
||||
const cr = this.TYPES_POOL.get(result.id);
|
||||
@ -1390,6 +1393,7 @@ class DocSearch {
|
||||
if (cr.ty === result.ty && cr.path === result.path
|
||||
&& cr.bindings === result.bindings && cr.generics === result.generics
|
||||
&& cr.ty === result.ty && cr.name === result.name
|
||||
&& cr.unboxFlag === result.unboxFlag
|
||||
) {
|
||||
return cr;
|
||||
}
|
||||
@ -1681,14 +1685,17 @@ class DocSearch {
|
||||
const ty = elem[0];
|
||||
const name = elem[1];
|
||||
let path = null;
|
||||
if (elem.length > 2) {
|
||||
if (elem.length > 2 && elem[2] !== null) {
|
||||
path = itemPaths.has(elem[2]) ? itemPaths.get(elem[2]) : lastPath;
|
||||
lastPath = path;
|
||||
}
|
||||
const exactPath = elem.length > 3 ? itemPaths.get(elem[3]) : path;
|
||||
const exactPath = elem.length > 3 && elem[3] !== null ?
|
||||
itemPaths.get(elem[3]) :
|
||||
path;
|
||||
const unboxFlag = elem.length > 4 && !!elem[4];
|
||||
|
||||
lowercasePaths.push({ ty, name: name.toLowerCase(), path, exactPath });
|
||||
paths[i] = { ty, name, path, exactPath };
|
||||
lowercasePaths.push({ ty, name: name.toLowerCase(), path, exactPath, unboxFlag });
|
||||
paths[i] = { ty, name, path, exactPath, unboxFlag };
|
||||
}
|
||||
|
||||
// convert `item*` into an object form, and construct word indices.
|
||||
@ -2376,17 +2383,20 @@ class DocSearch {
|
||||
*/
|
||||
const writeFn = (fnType, result) => {
|
||||
if (fnType.id < 0) {
|
||||
const queryId = mgens && mgens.has(fnType.id) ? mgens.get(fnType.id) : null;
|
||||
if (fnParamNames[-1 - fnType.id] === "") {
|
||||
for (const nested of fnType.generics) {
|
||||
writeFn(nested, result);
|
||||
}
|
||||
return;
|
||||
} else if (queryId < 0) {
|
||||
mappedNames.set(
|
||||
fnParamNames[-1 - fnType.id],
|
||||
queryParamNames[-1 - queryId],
|
||||
);
|
||||
} else if (mgens) {
|
||||
for (const [queryId, fnId] of mgens) {
|
||||
if (fnId === fnType.id) {
|
||||
mappedNames.set(
|
||||
queryParamNames[-1 - queryId],
|
||||
fnParamNames[-1 - fnType.id],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
pushText({
|
||||
name: fnParamNames[-1 - fnType.id],
|
||||
@ -2436,15 +2446,15 @@ class DocSearch {
|
||||
}
|
||||
pushText({ name, highlighted: false }, result);
|
||||
pushText({
|
||||
name: values.length > 1 ? "=(" : "=",
|
||||
name: values.length !== 1 ? "=(" : "=",
|
||||
highlighted: false,
|
||||
}, result);
|
||||
onEachBtwn(
|
||||
values,
|
||||
values || [],
|
||||
value => writeFn(value, result),
|
||||
() => pushText({ name: " + ", highlighted: false }, result),
|
||||
);
|
||||
if (values.length > 1) {
|
||||
if (values.length !== 1) {
|
||||
pushText({ name: ")", highlighted: false }, result);
|
||||
}
|
||||
},
|
||||
@ -2616,8 +2626,8 @@ class DocSearch {
|
||||
* @param {Array<QueryElement>} queryElems - The elements from the parsed query.
|
||||
* @param {[FunctionType]} whereClause - Trait bounds for generic items.
|
||||
* @param {Map<number,number>|null} mgensIn
|
||||
* - Map functions generics to query generics (never modified).
|
||||
* @param {null|Map<number,number> -> bool} solutionCb - Called for each `mgens` solution.
|
||||
* - Map query generics to function generics (never modified).
|
||||
* @param {Map<number,number> -> bool} solutionCb - Called for each `mgens` solution.
|
||||
* @param {number} unboxingDepth
|
||||
* - Limit checks that Ty matches Vec<Ty>,
|
||||
* but not Vec<ParamEnvAnd<WithInfcx<ConstTy<Interner<Ty=Ty>>>>>
|
||||
@ -2640,7 +2650,7 @@ class DocSearch {
|
||||
*/
|
||||
const mgens = mgensIn === null ? null : new Map(mgensIn);
|
||||
if (queryElems.length === 0) {
|
||||
return (!solutionCb || solutionCb(mgens)) ? fnTypesIn : null;
|
||||
return solutionCb(mgens) ? fnTypesIn : null;
|
||||
}
|
||||
if (!fnTypesIn || fnTypesIn.length === 0) {
|
||||
return null;
|
||||
@ -2657,12 +2667,12 @@ class DocSearch {
|
||||
continue;
|
||||
}
|
||||
if (fnType.id < 0 && queryElem.id < 0) {
|
||||
if (mgens && mgens.has(fnType.id) &&
|
||||
mgens.get(fnType.id) !== queryElem.id) {
|
||||
if (mgens && mgens.has(queryElem.id) &&
|
||||
mgens.get(queryElem.id) !== fnType.id) {
|
||||
continue;
|
||||
}
|
||||
const mgensScratch = new Map(mgens);
|
||||
mgensScratch.set(fnType.id, queryElem.id);
|
||||
mgensScratch.set(queryElem.id, fnType.id);
|
||||
if (!solutionCb || solutionCb(mgensScratch)) {
|
||||
const highlighted = [...fnTypesIn];
|
||||
highlighted[i] = Object.assign({
|
||||
@ -2672,13 +2682,13 @@ class DocSearch {
|
||||
});
|
||||
return highlighted;
|
||||
}
|
||||
} else if (!solutionCb || solutionCb(mgens ? new Map(mgens) : null)) {
|
||||
} else if (solutionCb(mgens ? new Map(mgens) : null)) {
|
||||
// unifyFunctionTypeIsMatchCandidate already checks that ids match
|
||||
const highlighted = [...fnTypesIn];
|
||||
highlighted[i] = Object.assign({
|
||||
highlighted: true,
|
||||
}, fnType, {
|
||||
generics: unifyFunctionTypes(
|
||||
generics: unifyGenericTypes(
|
||||
fnType.generics,
|
||||
queryElem.generics,
|
||||
whereClause,
|
||||
@ -2701,17 +2711,11 @@ class DocSearch {
|
||||
continue;
|
||||
}
|
||||
if (fnType.id < 0) {
|
||||
if (mgens && mgens.has(fnType.id) &&
|
||||
mgens.get(fnType.id) !== 0) {
|
||||
continue;
|
||||
}
|
||||
const mgensScratch = new Map(mgens);
|
||||
mgensScratch.set(fnType.id, 0);
|
||||
const highlightedGenerics = unifyFunctionTypes(
|
||||
whereClause[(-fnType.id) - 1],
|
||||
queryElems,
|
||||
whereClause,
|
||||
mgensScratch,
|
||||
mgens,
|
||||
solutionCb,
|
||||
unboxingDepth + 1,
|
||||
);
|
||||
@ -2782,11 +2786,11 @@ class DocSearch {
|
||||
let mgensScratch;
|
||||
if (fnType.id < 0) {
|
||||
mgensScratch = new Map(mgens);
|
||||
if (mgensScratch.has(fnType.id)
|
||||
&& mgensScratch.get(fnType.id) !== queryElem.id) {
|
||||
if (mgensScratch.has(queryElem.id)
|
||||
&& mgensScratch.get(queryElem.id) !== fnType.id) {
|
||||
continue;
|
||||
}
|
||||
mgensScratch.set(fnType.id, queryElem.id);
|
||||
mgensScratch.set(queryElem.id, fnType.id);
|
||||
} else {
|
||||
mgensScratch = mgens;
|
||||
}
|
||||
@ -2809,7 +2813,7 @@ class DocSearch {
|
||||
mgensScratch => {
|
||||
if (fnType.generics.length === 0 && queryElem.generics.length === 0
|
||||
&& fnType.bindings.size === 0 && queryElem.bindings.size === 0) {
|
||||
return !solutionCb || solutionCb(mgensScratch);
|
||||
return solutionCb(mgensScratch);
|
||||
}
|
||||
const solution = unifyFunctionTypeCheckBindings(
|
||||
fnType,
|
||||
@ -2823,7 +2827,7 @@ class DocSearch {
|
||||
}
|
||||
const simplifiedGenerics = solution.simplifiedGenerics;
|
||||
for (const simplifiedMgens of solution.mgens) {
|
||||
unifiedGenerics = unifyFunctionTypes(
|
||||
unifiedGenerics = unifyGenericTypes(
|
||||
simplifiedGenerics,
|
||||
queryElem.generics,
|
||||
whereClause,
|
||||
@ -2831,7 +2835,7 @@ class DocSearch {
|
||||
solutionCb,
|
||||
unboxingDepth,
|
||||
);
|
||||
if (unifiedGenerics) {
|
||||
if (unifiedGenerics !== null) {
|
||||
unifiedGenericsMgens = simplifiedMgens;
|
||||
return true;
|
||||
}
|
||||
@ -2875,16 +2879,6 @@ class DocSearch {
|
||||
)) {
|
||||
continue;
|
||||
}
|
||||
let mgensScratch;
|
||||
if (fnType.id < 0) {
|
||||
mgensScratch = new Map(mgens);
|
||||
if (mgensScratch.has(fnType.id) && mgensScratch.get(fnType.id) !== 0) {
|
||||
continue;
|
||||
}
|
||||
mgensScratch.set(fnType.id, 0);
|
||||
} else {
|
||||
mgensScratch = mgens;
|
||||
}
|
||||
const generics = fnType.id < 0 ?
|
||||
whereClause[(-fnType.id) - 1] :
|
||||
fnType.generics;
|
||||
@ -2895,7 +2889,7 @@ class DocSearch {
|
||||
fnTypes.toSpliced(i, 1, ...bindings, ...generics),
|
||||
queryElems,
|
||||
whereClause,
|
||||
mgensScratch,
|
||||
mgens,
|
||||
solutionCb,
|
||||
unboxingDepth + 1,
|
||||
);
|
||||
@ -2919,6 +2913,199 @@ class DocSearch {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* This function compares two lists of generics.
|
||||
*
|
||||
* This function behaves very similarly to `unifyFunctionTypes`, except that it
|
||||
* doesn't skip or reorder anything. This is intended to match the behavior of
|
||||
* the ordinary Rust type system, so that `Vec<Allocator>` only matches an actual
|
||||
* `Vec` of `Allocators` and not the implicit `Allocator` parameter that every
|
||||
* `Vec` has.
|
||||
*
|
||||
* @param {Array<FunctionType>} fnTypesIn - The objects to check.
|
||||
* @param {Array<QueryElement>} queryElems - The elements from the parsed query.
|
||||
* @param {[FunctionType]} whereClause - Trait bounds for generic items.
|
||||
* @param {Map<number,number>|null} mgensIn
|
||||
* - Map functions generics to query generics (never modified).
|
||||
* @param {Map<number,number> -> bool} solutionCb - Called for each `mgens` solution.
|
||||
* @param {number} unboxingDepth
|
||||
* - Limit checks that Ty matches Vec<Ty>,
|
||||
* but not Vec<ParamEnvAnd<WithInfcx<ConstTy<Interner<Ty=Ty>>>>>
|
||||
*
|
||||
* @return {[FunctionType]|null} - Returns highlighed results if a match, null otherwise.
|
||||
*/
|
||||
function unifyGenericTypes(
|
||||
fnTypesIn,
|
||||
queryElems,
|
||||
whereClause,
|
||||
mgensIn,
|
||||
solutionCb,
|
||||
unboxingDepth,
|
||||
) {
|
||||
if (unboxingDepth >= UNBOXING_LIMIT) {
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* @type Map<integer, integer>|null
|
||||
*/
|
||||
const mgens = mgensIn === null ? null : new Map(mgensIn);
|
||||
if (queryElems.length === 0) {
|
||||
return solutionCb(mgens) ? fnTypesIn : null;
|
||||
}
|
||||
if (!fnTypesIn || fnTypesIn.length === 0) {
|
||||
return null;
|
||||
}
|
||||
const fnType = fnTypesIn[0];
|
||||
const queryElem = queryElems[0];
|
||||
if (unifyFunctionTypeIsMatchCandidate(fnType, queryElem, mgens)) {
|
||||
if (fnType.id < 0 && queryElem.id < 0) {
|
||||
if (!mgens || !mgens.has(queryElem.id) ||
|
||||
mgens.get(queryElem.id) === fnType.id
|
||||
) {
|
||||
const mgensScratch = new Map(mgens);
|
||||
mgensScratch.set(queryElem.id, fnType.id);
|
||||
const fnTypesRemaining = unifyGenericTypes(
|
||||
fnTypesIn.slice(1),
|
||||
queryElems.slice(1),
|
||||
whereClause,
|
||||
mgensScratch,
|
||||
solutionCb,
|
||||
unboxingDepth,
|
||||
);
|
||||
if (fnTypesRemaining) {
|
||||
const highlighted = [fnType, ...fnTypesRemaining];
|
||||
highlighted[0] = Object.assign({
|
||||
highlighted: true,
|
||||
}, fnType, {
|
||||
generics: whereClause[-1 - fnType.id],
|
||||
});
|
||||
return highlighted;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let unifiedGenerics;
|
||||
const fnTypesRemaining = unifyGenericTypes(
|
||||
fnTypesIn.slice(1),
|
||||
queryElems.slice(1),
|
||||
whereClause,
|
||||
mgens,
|
||||
mgensScratch => {
|
||||
const solution = unifyFunctionTypeCheckBindings(
|
||||
fnType,
|
||||
queryElem,
|
||||
whereClause,
|
||||
mgensScratch,
|
||||
unboxingDepth,
|
||||
);
|
||||
if (!solution) {
|
||||
return false;
|
||||
}
|
||||
const simplifiedGenerics = solution.simplifiedGenerics;
|
||||
for (const simplifiedMgens of solution.mgens) {
|
||||
unifiedGenerics = unifyGenericTypes(
|
||||
simplifiedGenerics,
|
||||
queryElem.generics,
|
||||
whereClause,
|
||||
simplifiedMgens,
|
||||
solutionCb,
|
||||
unboxingDepth,
|
||||
);
|
||||
if (unifiedGenerics !== null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
},
|
||||
unboxingDepth,
|
||||
);
|
||||
if (fnTypesRemaining) {
|
||||
const highlighted = [fnType, ...fnTypesRemaining];
|
||||
highlighted[0] = Object.assign({
|
||||
highlighted: true,
|
||||
}, fnType, {
|
||||
generics: unifiedGenerics || fnType.generics,
|
||||
});
|
||||
return highlighted;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unifyFunctionTypeIsUnboxCandidate(
|
||||
fnType,
|
||||
queryElem,
|
||||
whereClause,
|
||||
mgens,
|
||||
unboxingDepth + 1,
|
||||
)) {
|
||||
let highlightedRemaining;
|
||||
if (fnType.id < 0) {
|
||||
// Where clause corresponds to `F: A + B`
|
||||
// ^^^^^
|
||||
// The order of the constraints doesn't matter, so
|
||||
// use order-agnostic matching for it.
|
||||
const highlightedGenerics = unifyFunctionTypes(
|
||||
whereClause[(-fnType.id) - 1],
|
||||
[queryElem],
|
||||
whereClause,
|
||||
mgens,
|
||||
mgensScratch => {
|
||||
const hl = unifyGenericTypes(
|
||||
fnTypesIn.slice(1),
|
||||
queryElems.slice(1),
|
||||
whereClause,
|
||||
mgensScratch,
|
||||
solutionCb,
|
||||
unboxingDepth,
|
||||
);
|
||||
if (hl) {
|
||||
highlightedRemaining = hl;
|
||||
}
|
||||
return hl;
|
||||
},
|
||||
unboxingDepth + 1,
|
||||
);
|
||||
if (highlightedGenerics) {
|
||||
return [Object.assign({
|
||||
highlighted: true,
|
||||
}, fnType, {
|
||||
generics: highlightedGenerics,
|
||||
}), ...highlightedRemaining];
|
||||
}
|
||||
} else {
|
||||
const highlightedGenerics = unifyGenericTypes(
|
||||
[
|
||||
...Array.from(fnType.bindings.values()).flat(),
|
||||
...fnType.generics,
|
||||
],
|
||||
[queryElem],
|
||||
whereClause,
|
||||
mgens,
|
||||
mgensScratch => {
|
||||
const hl = unifyGenericTypes(
|
||||
fnTypesIn.slice(1),
|
||||
queryElems.slice(1),
|
||||
whereClause,
|
||||
mgensScratch,
|
||||
solutionCb,
|
||||
unboxingDepth,
|
||||
);
|
||||
if (hl) {
|
||||
highlightedRemaining = hl;
|
||||
}
|
||||
return hl;
|
||||
},
|
||||
unboxingDepth + 1,
|
||||
);
|
||||
if (highlightedGenerics) {
|
||||
return [Object.assign({}, fnType, {
|
||||
generics: highlightedGenerics,
|
||||
bindings: new Map([...fnType.bindings.entries()].map(([k, v]) => {
|
||||
return [k, highlightedGenerics.splice(0, v.length)];
|
||||
})),
|
||||
}), ...highlightedRemaining];
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Check if this function is a match candidate.
|
||||
*
|
||||
@ -2930,7 +3117,7 @@ class DocSearch {
|
||||
*
|
||||
* @param {FunctionType} fnType
|
||||
* @param {QueryElement} queryElem
|
||||
* @param {Map<number,number>|null} mgensIn - Map functions generics to query generics.
|
||||
* @param {Map<number,number>|null} mgensIn - Map query generics to function generics.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
const unifyFunctionTypeIsMatchCandidate = (fnType, queryElem, mgensIn) => {
|
||||
@ -2940,22 +3127,13 @@ class DocSearch {
|
||||
}
|
||||
// fnType.id < 0 means generic
|
||||
// queryElem.id < 0 does too
|
||||
// mgensIn[fnType.id] = queryElem.id
|
||||
// or, if mgensIn[fnType.id] = 0, then we've matched this generic with a bare trait
|
||||
// and should make that same decision everywhere it appears
|
||||
// mgensIn[queryElem.id] = fnType.id
|
||||
if (fnType.id < 0 && queryElem.id < 0) {
|
||||
if (mgensIn) {
|
||||
if (mgensIn.has(fnType.id) && mgensIn.get(fnType.id) !== queryElem.id) {
|
||||
return false;
|
||||
}
|
||||
for (const [fid, qid] of mgensIn.entries()) {
|
||||
if (fnType.id !== fid && queryElem.id === qid) {
|
||||
return false;
|
||||
}
|
||||
if (fnType.id === fid && queryElem.id !== qid) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (
|
||||
mgensIn && mgensIn.has(queryElem.id) &&
|
||||
mgensIn.get(queryElem.id) !== fnType.id
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
@ -3032,7 +3210,7 @@ class DocSearch {
|
||||
* @param {FunctionType} fnType
|
||||
* @param {QueryElement} queryElem
|
||||
* @param {[FunctionType]} whereClause - Trait bounds for generic items.
|
||||
* @param {Map<number,number>} mgensIn - Map functions generics to query generics.
|
||||
* @param {Map<number,number>} mgensIn - Map query generics to function generics.
|
||||
* Never modified.
|
||||
* @param {number} unboxingDepth
|
||||
* @returns {false|{mgens: [Map<number,number>], simplifiedGenerics: [FunctionType]}}
|
||||
@ -3100,7 +3278,7 @@ class DocSearch {
|
||||
* @param {FunctionType} fnType
|
||||
* @param {QueryElement} queryElem
|
||||
* @param {[FunctionType]} whereClause - Trait bounds for generic items.
|
||||
* @param {Map<number,number>|null} mgens - Map functions generics to query generics.
|
||||
* @param {Map<number,number>|null} mgens - Map query generics to function generics.
|
||||
* @param {number} unboxingDepth
|
||||
* @returns {boolean}
|
||||
*/
|
||||
@ -3114,19 +3292,10 @@ class DocSearch {
|
||||
if (unboxingDepth >= UNBOXING_LIMIT) {
|
||||
return false;
|
||||
}
|
||||
if (fnType.id < 0 && queryElem.id >= 0) {
|
||||
if (fnType.id < 0) {
|
||||
if (!whereClause) {
|
||||
return false;
|
||||
}
|
||||
// mgens[fnType.id] === 0 indicates that we committed to unboxing this generic
|
||||
// mgens[fnType.id] === null indicates that we haven't decided yet
|
||||
if (mgens && mgens.has(fnType.id) && mgens.get(fnType.id) !== 0) {
|
||||
return false;
|
||||
}
|
||||
// Where clauses can represent cyclical data.
|
||||
// `null` prevents it from trying to unbox in an infinite loop
|
||||
const mgensTmp = new Map(mgens);
|
||||
mgensTmp.set(fnType.id, null);
|
||||
// This is only a potential unbox if the search query appears in the where clause
|
||||
// for example, searching `Read -> usize` should find
|
||||
// `fn read_all<R: Read>(R) -> Result<usize>`
|
||||
@ -3135,10 +3304,11 @@ class DocSearch {
|
||||
whereClause[(-fnType.id) - 1],
|
||||
queryElem,
|
||||
whereClause,
|
||||
mgensTmp,
|
||||
mgens,
|
||||
unboxingDepth,
|
||||
);
|
||||
} else if (fnType.generics.length > 0 || fnType.bindings.size > 0) {
|
||||
} else if (fnType.unboxFlag &&
|
||||
(fnType.generics.length > 0 || fnType.bindings.size > 0)) {
|
||||
const simplifiedGenerics = [
|
||||
...fnType.generics,
|
||||
...Array.from(fnType.bindings.values()).flat(),
|
||||
@ -3182,7 +3352,7 @@ class DocSearch {
|
||||
* @param {Row} row
|
||||
* @param {QueryElement} elem - The element from the parsed query.
|
||||
* @param {[FunctionType]} whereClause - Trait bounds for generic items.
|
||||
* @param {Map<number,number>|null} mgens - Map functions generics to query generics.
|
||||
* @param {Map<number,number>|null} mgens - Map query generics to function generics.
|
||||
*
|
||||
* @return {boolean} - Returns true if the type matches, false otherwise.
|
||||
*/
|
||||
@ -3200,10 +3370,34 @@ class DocSearch {
|
||||
) {
|
||||
return row.id === elem.id && typePassesFilter(elem.typeFilter, row.ty);
|
||||
} else {
|
||||
return unifyFunctionTypes([row], [elem], whereClause, mgens, null, unboxingDepth);
|
||||
return unifyFunctionTypes(
|
||||
[row],
|
||||
[elem],
|
||||
whereClause,
|
||||
mgens,
|
||||
() => true,
|
||||
unboxingDepth,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check a query solution for conflicting generics.
|
||||
*/
|
||||
const checkTypeMgensForConflict = mgens => {
|
||||
if (!mgens) {
|
||||
return true;
|
||||
}
|
||||
const fnTypes = new Set();
|
||||
for (const [_qid, fid] of mgens) {
|
||||
if (fnTypes.has(fid)) {
|
||||
return false;
|
||||
}
|
||||
fnTypes.add(fid);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Compute an "edit distance" that ignores missing path elements.
|
||||
* @param {string[]} contains search query path
|
||||
@ -3523,7 +3717,7 @@ class DocSearch {
|
||||
parsedQuery.returned,
|
||||
row.type.where_clause,
|
||||
mgens,
|
||||
null,
|
||||
checkTypeMgensForConflict,
|
||||
0, // unboxing depth
|
||||
);
|
||||
},
|
||||
@ -3973,7 +4167,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
|
||||
displayType.appendChild(line);
|
||||
addWhereLineFn = () => {};
|
||||
};
|
||||
for (const [name, qname] of mappedNames) {
|
||||
for (const [qname, name] of mappedNames) {
|
||||
// don't care unless the generic name is different
|
||||
if (name === qname) {
|
||||
continue;
|
||||
|
@ -11,8 +11,8 @@ assert-count: ("#search-tabs button", 1)
|
||||
assert-count: (".search-results > a", 1)
|
||||
|
||||
assert: "//div[@class='type-signature']/strong[text()='Iterator']"
|
||||
assert: "//div[@class='type-signature']/strong[text()='(']"
|
||||
assert: "//div[@class='type-signature']/strong[text()=')']"
|
||||
assert: "//div[@class='type-signature']/strong[text()='(B']"
|
||||
assert: "//div[@class='type-signature']/strong[text()='B)']"
|
||||
|
||||
assert: "//div[@class='type-signature']/div[@class='where']/strong[text()='FnMut']"
|
||||
assert: "//div[@class='type-signature']/div[@class='where']/strong[text()='Iterator::Item']"
|
||||
|
@ -2,12 +2,15 @@
|
||||
|
||||
const EXPECTED = [
|
||||
{
|
||||
'query': 'bufread -> result<u8>',
|
||||
'query': 'bufread -> result<[u8]>',
|
||||
'others': [
|
||||
{ 'path': 'std::boxed::Box', 'name': 'fill_buf' },
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'split<bufread> -> option<result<vec<u8>>>',
|
||||
'others': [
|
||||
{ 'path': 'std::io::Split', 'name': 'next' },
|
||||
{ 'path': 'std::boxed::Box', 'name': 'fill_buf' },
|
||||
{ 'path': 'std::io::Chain', 'name': 'fill_buf' },
|
||||
{ 'path': 'std::io::Take', 'name': 'fill_buf' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
@ -80,11 +80,6 @@ const EXPECTED = [
|
||||
'name': 'and',
|
||||
'displayType': '`Option`<`T`>, `Option`<`U`> -> `Option`<`U`>',
|
||||
},
|
||||
{
|
||||
'path': 'std::option::Option',
|
||||
'name': 'zip',
|
||||
'displayType': '`Option`<`T`>, `Option`<`U`> -> `Option`<(T, `U`)>',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -103,12 +98,12 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'option<t>, option<u> -> option<t, u>',
|
||||
'query': 'option<t>, option<u> -> option<(t, u)>',
|
||||
'others': [
|
||||
{
|
||||
'path': 'std::option::Option',
|
||||
'name': 'zip',
|
||||
'displayType': '`Option`<`T`>, `Option`<`U`> -> `Option`<(`T`, `U`)>',
|
||||
'displayType': '`Option`<`T`>, `Option`<`U`> -> `Option`<`(T`, `U)`>',
|
||||
},
|
||||
],
|
||||
},
|
||||
@ -174,37 +169,23 @@ const EXPECTED = [
|
||||
'path': 'std::option::Option',
|
||||
'name': 'map',
|
||||
'displayType': '`Option`<`T`>, F -> `Option`<U>',
|
||||
'displayMappedNames': `T = t, U = u`,
|
||||
'displayMappedNames': `t = T, u = U`,
|
||||
'displayWhereClause': "F: `FnOnce` (T) -> `U`",
|
||||
},
|
||||
{
|
||||
'path': 'std::option::Option',
|
||||
'name': 'and_then',
|
||||
'displayType': '`Option`<`T`>, F -> `Option`<U>',
|
||||
'displayMappedNames': `T = t, U = u`,
|
||||
'displayMappedNames': `t = T, u = U`,
|
||||
'displayWhereClause': "F: `FnOnce` (T) -> Option<`U`>",
|
||||
},
|
||||
{
|
||||
'path': 'std::option::Option',
|
||||
'name': 'zip_with',
|
||||
'displayType': 'Option<T>, `Option`<`U`>, F -> `Option`<R>',
|
||||
'displayMappedNames': `U = t, R = u`,
|
||||
'displayMappedNames': `t = U, u = R`,
|
||||
'displayWhereClause': "F: `FnOnce` (T, U) -> `R`",
|
||||
},
|
||||
{
|
||||
'path': 'std::task::Poll',
|
||||
'name': 'map_ok',
|
||||
'displayType': 'Poll<`Option`<Result<`T`, E>>>, F -> Poll<`Option`<Result<U, E>>>',
|
||||
'displayMappedNames': `T = t, U = u`,
|
||||
'displayWhereClause': "F: `FnOnce` (T) -> `U`",
|
||||
},
|
||||
{
|
||||
'path': 'std::task::Poll',
|
||||
'name': 'map_err',
|
||||
'displayType': 'Poll<`Option`<Result<`T`, E>>>, F -> Poll<`Option`<Result<T, U>>>',
|
||||
'displayMappedNames': `T = t, U = u`,
|
||||
'displayWhereClause': "F: `FnOnce` (E) -> `U`",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -214,7 +195,7 @@ const EXPECTED = [
|
||||
'path': 'std::option::Option',
|
||||
'name': 'and_then',
|
||||
'displayType': '`Option`<`T`>, F -> `Option`<U>',
|
||||
'displayMappedNames': `T = t, U = u`,
|
||||
'displayMappedNames': `t = T, u = U`,
|
||||
'displayWhereClause': "F: `FnOnce` (T) -> `Option`<`U`>",
|
||||
},
|
||||
],
|
||||
|
@ -19,4 +19,16 @@ const EXPECTED = [
|
||||
{ 'path': 'std::vec::IntoIter', 'name': 'next_chunk' },
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'vec<T, Allocator> -> Box<[T]>',
|
||||
'others': [
|
||||
{
|
||||
'path': 'std::boxed::Box',
|
||||
'name': 'from',
|
||||
'displayType': '`Vec`<`T`, `A`> -> `Box`<`[T]`, A>',
|
||||
'displayMappedNames': `T = T`,
|
||||
'displayWhereClause': 'A: `Allocator`',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
@ -6,7 +6,6 @@ const EXPECTED = [
|
||||
'correction': null,
|
||||
'others': [
|
||||
{ 'path': 'assoc_type_backtrack::MyTrait', 'name': 'fold' },
|
||||
{ 'path': 'assoc_type_backtrack::Cloned', 'name': 'fold' },
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -14,6 +13,19 @@ const EXPECTED = [
|
||||
'correction': null,
|
||||
'others': [
|
||||
{ 'path': 'assoc_type_backtrack::MyTrait', 'name': 'fold' },
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'cloned<mytrait>, mytrait2 -> T',
|
||||
'correction': null,
|
||||
'others': [
|
||||
{ 'path': 'assoc_type_backtrack::Cloned', 'name': 'fold' },
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'cloned<mytrait<U>>, mytrait2 -> T',
|
||||
'correction': null,
|
||||
'others': [
|
||||
{ 'path': 'assoc_type_backtrack::Cloned', 'name': 'fold' },
|
||||
],
|
||||
},
|
||||
@ -22,7 +34,6 @@ const EXPECTED = [
|
||||
'correction': null,
|
||||
'others': [
|
||||
{ 'path': 'assoc_type_backtrack::MyTrait', 'name': 'fold' },
|
||||
{ 'path': 'assoc_type_backtrack::Cloned', 'name': 'fold' },
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -50,14 +61,14 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'mytrait<U> -> Option<T>',
|
||||
'query': 'cloned<mytrait<U>> -> Option<T>',
|
||||
'correction': null,
|
||||
'others': [
|
||||
{ 'path': 'assoc_type_backtrack::Cloned', 'name': 'next' },
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'mytrait<Item=U> -> Option<T>',
|
||||
'query': 'cloned<mytrait<Item=U>> -> Option<T>',
|
||||
'correction': null,
|
||||
'others': [
|
||||
{ 'path': 'assoc_type_backtrack::Cloned', 'name': 'next' },
|
||||
@ -89,19 +100,21 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'myintofuture<myfuture<t>> -> myfuture<t>',
|
||||
'query': 'myintofuture<t, myfuture<t>> -> myfuture<t>',
|
||||
'correction': null,
|
||||
'others': [
|
||||
{ 'path': 'assoc_type_backtrack::MyIntoFuture', 'name': 'into_future' },
|
||||
{ 'path': 'assoc_type_backtrack::MyIntoFuture', 'name': 'into_future_2' },
|
||||
],
|
||||
},
|
||||
// Invalid unboxing of the one-argument case.
|
||||
// If you unbox one of the myfutures, you need to unbox both of them.
|
||||
// Unboxings of the one-argument case.
|
||||
{
|
||||
'query': 'myintofuture<fut=t> -> myfuture<t>',
|
||||
'correction': null,
|
||||
'others': [],
|
||||
'others': [
|
||||
{ 'path': 'assoc_type_backtrack::MyIntoFuture', 'name': 'into_future' },
|
||||
{ 'path': 'assoc_type_backtrack::MyIntoFuture', 'name': 'into_future_2' },
|
||||
],
|
||||
},
|
||||
// Unboxings of the two-argument case.
|
||||
{
|
||||
@ -119,7 +132,7 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'myintofuture<myfuture>, myintofuture<myfuture> -> myfuture',
|
||||
'query': 'myintofuture<t, myfuture>, myintofuture<t, myfuture> -> myfuture',
|
||||
'correction': null,
|
||||
'others': [
|
||||
{ 'path': 'assoc_type_backtrack::MyIntoFuture', 'name': 'into_future_2' },
|
||||
@ -132,24 +145,29 @@ const EXPECTED = [
|
||||
{ 'path': 'assoc_type_backtrack::MyIntoFuture', 'name': 'into_future_2' },
|
||||
],
|
||||
},
|
||||
// Invalid unboxings of the two-argument case.
|
||||
// If you unbox one of the myfutures, you need to unbox all of them.
|
||||
// If you unbox one of the myfutures, you don't need to unbox all of them.
|
||||
{
|
||||
'query': 'myintofuture<fut=t>, myintofuture<fut=myfuture<t>> -> myfuture<t>',
|
||||
'correction': null,
|
||||
'others': [],
|
||||
'others': [
|
||||
{ 'path': 'assoc_type_backtrack::MyIntoFuture', 'name': 'into_future_2' },
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'myintofuture<fut=myfuture<t>>, myintofuture<fut=t> -> myfuture<t>',
|
||||
'correction': null,
|
||||
'others': [],
|
||||
'others': [
|
||||
{ 'path': 'assoc_type_backtrack::MyIntoFuture', 'name': 'into_future_2' },
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'myintofuture<fut=myfuture<t>>, myintofuture<fut=myfuture<t>> -> t',
|
||||
'correction': null,
|
||||
'others': [],
|
||||
'others': [
|
||||
{ 'path': 'assoc_type_backtrack::MyIntoFuture', 'name': 'into_future_2' },
|
||||
],
|
||||
},
|
||||
// different generics don't match up either
|
||||
// different generics must match up
|
||||
{
|
||||
'query': 'myintofuture<fut=myfuture<u>>, myintofuture<fut=myfuture<t>> -> myfuture<t>',
|
||||
'correction': null,
|
||||
|
@ -1,3 +1,5 @@
|
||||
#![feature(rustdoc_internals)]
|
||||
|
||||
pub trait MyTrait2<X> {
|
||||
type Output;
|
||||
}
|
||||
@ -31,10 +33,12 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(search_unbox)]
|
||||
pub trait MyFuture {
|
||||
type Output;
|
||||
}
|
||||
|
||||
#[doc(search_unbox)]
|
||||
pub trait MyIntoFuture {
|
||||
type Output;
|
||||
type Fut: MyFuture<Output = Self::Output>;
|
||||
|
@ -13,7 +13,7 @@ const EXPECTED = [
|
||||
'path': 'assoc_type_unbound::MyIter',
|
||||
'name': 'next',
|
||||
'displayType': '&mut `MyIter` -> `Option`<`MyIter::Item`>',
|
||||
'displayMappedNames': 'MyIter::Item = T',
|
||||
'displayMappedNames': 'T = MyIter::Item',
|
||||
'displayWhereClause': '',
|
||||
},
|
||||
],
|
||||
@ -26,7 +26,7 @@ const EXPECTED = [
|
||||
'path': 'assoc_type_unbound::MyIter',
|
||||
'name': 'next',
|
||||
'displayType': '&mut `MyIter` -> `Option`<`MyIter::Item`>',
|
||||
'displayMappedNames': 'MyIter::Item = T',
|
||||
'displayMappedNames': 'T = MyIter::Item',
|
||||
'displayWhereClause': '',
|
||||
},
|
||||
],
|
||||
|
@ -1,12 +1,22 @@
|
||||
pub fn my_fn<X: Iterator<Item = Something>>(_x: X) -> u32 {
|
||||
#![feature(rustdoc_internals)]
|
||||
|
||||
pub fn my_fn<X: other::Iterator<Item = Something>>(_x: X) -> u32 {
|
||||
3
|
||||
}
|
||||
|
||||
pub struct Something;
|
||||
|
||||
pub mod my {
|
||||
#[doc(search_unbox)]
|
||||
pub trait Iterator<T> {}
|
||||
pub fn other_fn<X: Iterator<crate::Something>>(_: X) -> u32 {
|
||||
3
|
||||
}
|
||||
}
|
||||
|
||||
pub mod other {
|
||||
#[doc(search_unbox)]
|
||||
pub trait Iterator {
|
||||
type Item;
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'Aaaaaaa -> usize',
|
||||
'query': 'Aaaaaaa -> Result<usize>',
|
||||
'others': [
|
||||
{ 'path': 'generics_impl::Aaaaaaa', 'name': 'read' },
|
||||
],
|
||||
@ -23,6 +23,11 @@ const EXPECTED = [
|
||||
'query': 'Read -> u64',
|
||||
'others': [
|
||||
{ 'path': 'generics_impl::Ddddddd', 'name': 'eeeeeee' },
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'Ddddddd<Read> -> u64',
|
||||
'others': [
|
||||
{ 'path': 'generics_impl::Ddddddd', 'name': 'ggggggg' },
|
||||
],
|
||||
},
|
||||
@ -30,7 +35,6 @@ const EXPECTED = [
|
||||
'query': 'trait:Read -> u64',
|
||||
'others': [
|
||||
{ 'path': 'generics_impl::Ddddddd', 'name': 'eeeeeee' },
|
||||
{ 'path': 'generics_impl::Ddddddd', 'name': 'ggggggg' },
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::io::{Read, Result as IoResult};
|
||||
use std::io::{self, Read};
|
||||
|
||||
pub struct Aaaaaaa;
|
||||
|
||||
@ -12,7 +12,7 @@ impl Aaaaaaa {
|
||||
}
|
||||
|
||||
impl Read for Aaaaaaa {
|
||||
fn read(&mut self, out: &mut [u8]) -> IoResult<usize> {
|
||||
fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
|
||||
Ok(out.len())
|
||||
}
|
||||
}
|
||||
|
68
tests/rustdoc-js/generics-match-ambiguity-no-unbox.js
Normal file
68
tests/rustdoc-js/generics-match-ambiguity-no-unbox.js
Normal file
@ -0,0 +1,68 @@
|
||||
// ignore-order
|
||||
// exact-check
|
||||
|
||||
// Make sure that results are order-agnostic, even when there's search items that only differ
|
||||
// by generics.
|
||||
|
||||
const EXPECTED = [
|
||||
{
|
||||
'query': 'Wrap',
|
||||
'in_args': [
|
||||
{ 'path': 'generics_match_ambiguity', 'name': 'bar' },
|
||||
{ 'path': 'generics_match_ambiguity', 'name': 'foo' },
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'Wrap<i32>',
|
||||
'in_args': [
|
||||
{ 'path': 'generics_match_ambiguity', 'name': 'bar' },
|
||||
{ 'path': 'generics_match_ambiguity', 'name': 'foo' },
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'Wrap<i32>, Wrap<i32, u32>',
|
||||
'others': [
|
||||
{ 'path': 'generics_match_ambiguity', 'name': 'bar' },
|
||||
{ 'path': 'generics_match_ambiguity', 'name': 'foo' },
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'Wrap<i32, u32>, Wrap<i32>',
|
||||
'others': [
|
||||
{ 'path': 'generics_match_ambiguity', 'name': 'bar' },
|
||||
{ 'path': 'generics_match_ambiguity', 'name': 'foo' },
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'W3<i32>, W3<i32, u32>',
|
||||
'others': [
|
||||
{ 'path': 'generics_match_ambiguity', 'name': 'baaa' },
|
||||
{ 'path': 'generics_match_ambiguity', 'name': 'baab' },
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'W3<i32, u32>, W3<i32>',
|
||||
'others': [
|
||||
{ 'path': 'generics_match_ambiguity', 'name': 'baaa' },
|
||||
{ 'path': 'generics_match_ambiguity', 'name': 'baab' },
|
||||
],
|
||||
},
|
||||
{
|
||||
// strict generics matching; W2<i32, u32> doesn't match W2<W3<i32, u32>>,
|
||||
// even though W2<i32> works just fine (ignoring the W3)
|
||||
'query': 'W2<i32>, W2<i32, u32>',
|
||||
'others': [],
|
||||
},
|
||||
{
|
||||
'query': 'W2<i32, u32>, W2<i32>',
|
||||
'others': [],
|
||||
},
|
||||
{
|
||||
'query': 'W2<i32>, W3<i32, u32>',
|
||||
'others': [],
|
||||
},
|
||||
{
|
||||
'query': 'W2<i32>, W2<i32>',
|
||||
'others': [],
|
||||
},
|
||||
];
|
18
tests/rustdoc-js/generics-match-ambiguity-no-unbox.rs
Normal file
18
tests/rustdoc-js/generics-match-ambiguity-no-unbox.rs
Normal file
@ -0,0 +1,18 @@
|
||||
#![crate_name = "generics_match_ambiguity"]
|
||||
|
||||
pub struct Wrap<T, U = ()>(pub T, pub U);
|
||||
|
||||
pub fn foo(a: Wrap<i32>, b: Wrap<i32, u32>) {}
|
||||
pub fn bar(a: Wrap<i32, u32>, b: Wrap<i32>) {}
|
||||
|
||||
pub struct W2<T>(pub T);
|
||||
pub struct W3<T, U = ()>(pub T, pub U);
|
||||
|
||||
pub fn baaa(a: W3<i32>, b: W3<i32, u32>) {}
|
||||
pub fn baab(a: W3<i32, u32>, b: W3<i32>) {}
|
||||
pub fn baac(a: W2<W3<i32>>, b: W3<i32, u32>) {}
|
||||
pub fn baad(a: W2<W3<i32, u32>>, b: W3<i32>) {}
|
||||
pub fn baae(a: W3<i32>, b: W2<W3<i32, u32>>) {}
|
||||
pub fn baaf(a: W3<i32, u32>, b: W2<W3<i32>>) {}
|
||||
pub fn baag(a: W2<W3<i32>>, b: W2<W3<i32, u32>>) {}
|
||||
pub fn baah(a: W2<W3<i32, u32>>, b: W2<W3<i32>>) {}
|
@ -60,18 +60,14 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
// strict generics matching; W2<i32, u32> doesn't match W2<W3<i32, u32>>,
|
||||
// even though W2<i32> works just fine (ignoring the W3)
|
||||
'query': 'W2<i32>, W2<i32, u32>',
|
||||
'others': [
|
||||
{ 'path': 'generics_match_ambiguity', 'name': 'baag' },
|
||||
{ 'path': 'generics_match_ambiguity', 'name': 'baah' },
|
||||
],
|
||||
'others': [],
|
||||
},
|
||||
{
|
||||
'query': 'W2<i32, u32>, W2<i32>',
|
||||
'others': [
|
||||
{ 'path': 'generics_match_ambiguity', 'name': 'baag' },
|
||||
{ 'path': 'generics_match_ambiguity', 'name': 'baah' },
|
||||
],
|
||||
'others': [],
|
||||
},
|
||||
{
|
||||
'query': 'W2<i32>, W3<i32, u32>',
|
||||
|
@ -1,9 +1,14 @@
|
||||
#![feature(rustdoc_internals)]
|
||||
|
||||
#[doc(search_unbox)]
|
||||
pub struct Wrap<T, U = ()>(pub T, pub U);
|
||||
|
||||
pub fn foo(a: Wrap<i32>, b: Wrap<i32, u32>) {}
|
||||
pub fn bar(a: Wrap<i32, u32>, b: Wrap<i32>) {}
|
||||
|
||||
#[doc(search_unbox)]
|
||||
pub struct W2<T>(pub T);
|
||||
#[doc(search_unbox)]
|
||||
pub struct W3<T, U = ()>(pub T, pub U);
|
||||
|
||||
pub fn baaa(a: W3<i32>, b: W3<i32, u32>) {}
|
||||
@ -14,4 +19,3 @@ pub fn baae(a: W3<i32>, b: W2<W3<i32, u32>>) {}
|
||||
pub fn baaf(a: W3<i32, u32>, b: W2<W3<i32>>) {}
|
||||
pub fn baag(a: W2<W3<i32>>, b: W2<W3<i32, u32>>) {}
|
||||
pub fn baah(a: W2<W3<i32, u32>>, b: W2<W3<i32>>) {}
|
||||
//
|
||||
|
@ -18,9 +18,8 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
// can't put generics out of order
|
||||
'query': '-> Out<Second, First>',
|
||||
'others': [
|
||||
{ 'path': 'generics_nested', 'name': 'bet' },
|
||||
],
|
||||
'others': [],
|
||||
},
|
||||
];
|
||||
|
@ -11,20 +11,17 @@ const EXPECTED = [
|
||||
'query': 'Inside<T> -> Out3<T>',
|
||||
'others': [
|
||||
{ 'path': 'generics_unbox', 'name': 'beta' },
|
||||
{ 'path': 'generics_unbox', 'name': 'gamma' },
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'Inside<T> -> Out4<T>',
|
||||
'others': [
|
||||
{ 'path': 'generics_unbox', 'name': 'beta' },
|
||||
{ 'path': 'generics_unbox', 'name': 'gamma' },
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'Inside<T> -> Out3<U, T>',
|
||||
'others': [
|
||||
{ 'path': 'generics_unbox', 'name': 'beta' },
|
||||
{ 'path': 'generics_unbox', 'name': 'gamma' },
|
||||
],
|
||||
},
|
||||
@ -32,7 +29,6 @@ const EXPECTED = [
|
||||
'query': 'Inside<T> -> Out4<U, T>',
|
||||
'others': [
|
||||
{ 'path': 'generics_unbox', 'name': 'beta' },
|
||||
{ 'path': 'generics_unbox', 'name': 'gamma' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
@ -1,26 +1,34 @@
|
||||
#![feature(rustdoc_internals)]
|
||||
|
||||
#[doc(search_unbox)]
|
||||
pub struct Out<A, B = ()> {
|
||||
a: A,
|
||||
b: B,
|
||||
}
|
||||
|
||||
#[doc(search_unbox)]
|
||||
pub struct Out1<A, const N: usize> {
|
||||
a: [A; N],
|
||||
}
|
||||
|
||||
#[doc(search_unbox)]
|
||||
pub struct Out2<A, const N: usize> {
|
||||
a: [A; N],
|
||||
}
|
||||
|
||||
#[doc(search_unbox)]
|
||||
pub struct Out3<A, B> {
|
||||
a: A,
|
||||
b: B,
|
||||
}
|
||||
|
||||
#[doc(search_unbox)]
|
||||
pub struct Out4<A, B> {
|
||||
a: A,
|
||||
b: B,
|
||||
}
|
||||
|
||||
#[doc(search_unbox)]
|
||||
pub struct Inside<T>(T);
|
||||
|
||||
pub fn alpha<const N: usize, T>(_: Inside<T>) -> Out<Out1<T, N>, Out2<T, N>> {
|
||||
|
@ -30,21 +30,13 @@ const EXPECTED = [
|
||||
'others': [
|
||||
{ 'path': 'generics', 'name': 'P' },
|
||||
],
|
||||
'returned': [
|
||||
{ 'path': 'generics', 'name': 'alef' },
|
||||
],
|
||||
'in_args': [
|
||||
{ 'path': 'generics', 'name': 'alpha' },
|
||||
],
|
||||
'returned': [],
|
||||
'in_args': [],
|
||||
},
|
||||
{
|
||||
'query': 'P',
|
||||
'returned': [
|
||||
{ 'path': 'generics', 'name': 'alef' },
|
||||
],
|
||||
'in_args': [
|
||||
{ 'path': 'generics', 'name': 'alpha' },
|
||||
],
|
||||
'returned': [],
|
||||
'in_args': [],
|
||||
},
|
||||
{
|
||||
'query': '"ExtraCreditStructMulti"<ExtraCreditInnerMulti, ExtraCreditInnerMulti>',
|
||||
|
@ -9,19 +9,19 @@ const EXPECTED = [
|
||||
|
||||
// ML-style higher-order function notation
|
||||
{
|
||||
'query': 'bool, (u32 -> !) -> ()',
|
||||
'query': 'bool, (first<u32> -> !) -> ()',
|
||||
'others': [
|
||||
{"path": "hof", "name": "fn_ptr"},
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'u8, (u32 -> !) -> ()',
|
||||
'query': 'u8, (second<u32> -> !) -> ()',
|
||||
'others': [
|
||||
{"path": "hof", "name": "fn_once"},
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'i8, (u32 -> !) -> ()',
|
||||
'query': 'i8, (third<u32> -> !) -> ()',
|
||||
'others': [
|
||||
{"path": "hof", "name": "fn_mut"},
|
||||
],
|
||||
@ -54,9 +54,6 @@ const EXPECTED = [
|
||||
'query': '(u32 -> !) -> ()',
|
||||
'others': [
|
||||
{"path": "hof", "name": "fn_"},
|
||||
{"path": "hof", "name": "fn_ptr"},
|
||||
{"path": "hof", "name": "fn_mut"},
|
||||
{"path": "hof", "name": "fn_once"},
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -95,30 +92,30 @@ const EXPECTED = [
|
||||
|
||||
// Rust-style higher-order function notation
|
||||
{
|
||||
'query': 'bool, fn(u32) -> ! -> ()',
|
||||
'query': 'bool, fn(first<u32>) -> ! -> ()',
|
||||
'others': [
|
||||
{"path": "hof", "name": "fn_ptr"},
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'u8, fnonce(u32) -> ! -> ()',
|
||||
'query': 'u8, fnonce(second<u32>) -> ! -> ()',
|
||||
'others': [
|
||||
{"path": "hof", "name": "fn_once"},
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'u8, fn(u32) -> ! -> ()',
|
||||
'query': 'u8, fn(second<u32>) -> ! -> ()',
|
||||
// fnonce != fn
|
||||
'others': [],
|
||||
},
|
||||
{
|
||||
'query': 'i8, fnmut(u32) -> ! -> ()',
|
||||
'query': 'i8, fnmut(third<u32>) -> ! -> ()',
|
||||
'others': [
|
||||
{"path": "hof", "name": "fn_mut"},
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'i8, fn(u32) -> ! -> ()',
|
||||
'query': 'i8, fn(third<u32>) -> ! -> ()',
|
||||
// fnmut != fn
|
||||
'others': [],
|
||||
},
|
||||
@ -152,7 +149,7 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'fn(u32) -> ! -> ()',
|
||||
'query': 'fn() -> ! -> ()',
|
||||
'others': [
|
||||
// fn matches primitive:fn and trait:Fn
|
||||
{"path": "hof", "name": "fn_"},
|
||||
@ -160,14 +157,14 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'trait:fn(u32) -> ! -> ()',
|
||||
'query': 'trait:fn() -> ! -> ()',
|
||||
'others': [
|
||||
// fn matches primitive:fn and trait:Fn
|
||||
{"path": "hof", "name": "fn_"},
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'primitive:fn(u32) -> ! -> ()',
|
||||
'query': 'primitive:fn() -> ! -> ()',
|
||||
'others': [
|
||||
// fn matches primitive:fn and trait:Fn
|
||||
{"path": "hof", "name": "fn_ptr"},
|
||||
|
@ -1,9 +1,15 @@
|
||||
// https://github.com/rust-lang/rust/pull/122247
|
||||
// exact-check
|
||||
|
||||
const EXPECTED = {
|
||||
'query': 'canonicalvarinfo, intoiterator -> intoiterator',
|
||||
'others': [
|
||||
{ 'path': 'looks_like_rustc_interner::Interner', 'name': 'mk_canonical_var_infos' },
|
||||
],
|
||||
};
|
||||
const EXPECTED = [
|
||||
{
|
||||
'query': 'canonicalvarinfo, intoiterator -> intoiterator',
|
||||
'others': [],
|
||||
},
|
||||
{
|
||||
'query': '[canonicalvarinfo], interner<tys=intoiterator> -> intoiterator',
|
||||
'others': [
|
||||
{ 'path': 'looks_like_rustc_interner::Interner', 'name': 'mk_canonical_var_infos' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
@ -33,9 +33,8 @@ const EXPECTED = [
|
||||
},
|
||||
{
|
||||
'query': '-> Result<i32, u32, bool>',
|
||||
'others': [
|
||||
{ 'path': 'nested_unboxed', 'name': 'something' },
|
||||
],
|
||||
// can't put nested generics out of order
|
||||
'others': [],
|
||||
},
|
||||
{
|
||||
'query': '-> Result<Object<i32>, bool>',
|
||||
@ -45,9 +44,7 @@ const EXPECTED = [
|
||||
},
|
||||
{
|
||||
'query': '-> Result<Object<u32>, bool>',
|
||||
'others': [
|
||||
{ 'path': 'nested_unboxed', 'name': 'something' },
|
||||
],
|
||||
'others': [],
|
||||
},
|
||||
{
|
||||
'query': '-> Result<Object<i32>, u32, bool>',
|
||||
|
@ -1,3 +1,6 @@
|
||||
#![feature(rustdoc_internals)]
|
||||
|
||||
#[doc(search_unbox)]
|
||||
pub struct Object<T, U>(T, U);
|
||||
|
||||
pub fn something() -> Result<Object<i32, u32>, bool> {
|
||||
|
@ -79,9 +79,8 @@ const EXPECTED = [
|
||||
},
|
||||
{
|
||||
'query': 'reference<ring>, reference<ring> -> ()',
|
||||
'others': [
|
||||
{ 'path': 'reference::Ring', 'name': 'wear' },
|
||||
],
|
||||
// can't leave out the `mut`, because can't reorder like that
|
||||
'others': [],
|
||||
},
|
||||
{
|
||||
'query': 'reference<mut, ring>, reference<ring> -> ()',
|
||||
@ -102,9 +101,8 @@ const EXPECTED = [
|
||||
},
|
||||
{
|
||||
'query': 'reference<middle>, reference<middle> -> ()',
|
||||
'others': [
|
||||
{ 'path': 'reference', 'name': 'show' },
|
||||
],
|
||||
// can't leave out the mut
|
||||
'others': [],
|
||||
},
|
||||
{
|
||||
'query': 'reference<mut, middle>, reference<mut, middle> -> ()',
|
||||
@ -203,9 +201,8 @@ const EXPECTED = [
|
||||
// middle with shorthand
|
||||
{
|
||||
'query': '&middle, &middle -> ()',
|
||||
'others': [
|
||||
{ 'path': 'reference', 'name': 'show' },
|
||||
],
|
||||
// can't leave out the mut
|
||||
'others': [],
|
||||
},
|
||||
{
|
||||
'query': '&mut middle, &mut middle -> ()',
|
||||
|
@ -57,7 +57,7 @@ const EXPECTED = [
|
||||
'in_args': [],
|
||||
},
|
||||
{
|
||||
'query': '(Q, ())',
|
||||
'query': '(Q, R<()>)',
|
||||
'returned': [
|
||||
{ 'path': 'tuple_unit', 'name': 'nest' },
|
||||
],
|
||||
@ -71,7 +71,7 @@ const EXPECTED = [
|
||||
'in_args': [],
|
||||
},
|
||||
{
|
||||
'query': '(u32)',
|
||||
'query': 'R<(u32)>',
|
||||
'returned': [
|
||||
{ 'path': 'tuple_unit', 'name': 'nest' },
|
||||
],
|
||||
|
@ -7,4 +7,7 @@ trait Mine {}
|
||||
#[doc(fake_variadic)] //~ ERROR: `#[doc(fake_variadic)]` is meant for internal use only
|
||||
impl<T> Mine for (T,) {}
|
||||
|
||||
#[doc(search_unbox)] //~ ERROR: `#[doc(search_unbox)]` is meant for internal use only
|
||||
struct Wrap<T> (T);
|
||||
|
||||
fn main() {}
|
||||
|
@ -18,6 +18,16 @@ LL | #[doc(fake_variadic)]
|
||||
= help: add `#![feature(rustdoc_internals)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error[E0658]: `#[doc(search_unbox)]` is meant for internal use only
|
||||
--> $DIR/feature-gate-rustdoc_internals.rs:10:1
|
||||
|
|
||||
LL | #[doc(search_unbox)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #90418 <https://github.com/rust-lang/rust/issues/90418> for more information
|
||||
= help: add `#![feature(rustdoc_internals)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
Loading…
Reference in New Issue
Block a user