mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Auto merge of #128673 - matthiaskrgr:rollup-gtvpkm7, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #128026 (std:🧵 available_parallelism implementation for vxWorks proposal.) - #128471 (rustdoc: Fix handling of `Self` type in search index and refactor its representation) - #128607 (Use `object` in `run-make/symbols-visibility`) - #128609 (Remove unnecessary constants from flt2dec dragon) - #128611 (run-make: Remove cygpath) - #128619 (Correct the const stabilization of `<[T]>::last_chunk`) - #128630 (docs(resolve): more explain about `target`) - #128660 (tests: more crashes) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
4d48a6be74
@ -48,6 +48,7 @@ pub(crate) enum ImportKind<'a> {
|
|||||||
/// `source` in `use prefix::source as target`.
|
/// `source` in `use prefix::source as target`.
|
||||||
source: Ident,
|
source: Ident,
|
||||||
/// `target` in `use prefix::source as target`.
|
/// `target` in `use prefix::source as target`.
|
||||||
|
/// It will directly use `source` when the format is `use prefix::source`.
|
||||||
target: Ident,
|
target: Ident,
|
||||||
/// Bindings to which `source` refers to.
|
/// Bindings to which `source` refers to.
|
||||||
source_bindings: PerNS<Cell<Result<NameBinding<'a>, Determinacy>>>,
|
source_bindings: PerNS<Cell<Result<NameBinding<'a>, Determinacy>>>,
|
||||||
|
@ -12,48 +12,51 @@ use crate::num::flt2dec::{round_up, Decoded, MAX_SIG_DIGITS};
|
|||||||
|
|
||||||
static POW10: [Digit; 10] =
|
static POW10: [Digit; 10] =
|
||||||
[1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000];
|
[1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000];
|
||||||
static TWOPOW10: [Digit; 10] =
|
// precalculated arrays of `Digit`s for 5^(2^n).
|
||||||
[2, 20, 200, 2000, 20000, 200000, 2000000, 20000000, 200000000, 2000000000];
|
static POW5TO16: [Digit; 2] = [0x86f26fc1, 0x23];
|
||||||
|
static POW5TO32: [Digit; 3] = [0x85acef81, 0x2d6d415b, 0x4ee];
|
||||||
// precalculated arrays of `Digit`s for 10^(2^n)
|
static POW5TO64: [Digit; 5] = [0xbf6a1f01, 0x6e38ed64, 0xdaa797ed, 0xe93ff9f4, 0x184f03];
|
||||||
static POW10TO16: [Digit; 2] = [0x6fc10000, 0x2386f2];
|
static POW5TO128: [Digit; 10] = [
|
||||||
static POW10TO32: [Digit; 4] = [0, 0x85acef81, 0x2d6d415b, 0x4ee];
|
0x2e953e01, 0x3df9909, 0xf1538fd, 0x2374e42f, 0xd3cff5ec, 0xc404dc08, 0xbccdb0da, 0xa6337f19,
|
||||||
static POW10TO64: [Digit; 7] = [0, 0, 0xbf6a1f01, 0x6e38ed64, 0xdaa797ed, 0xe93ff9f4, 0x184f03];
|
0xe91f2603, 0x24e,
|
||||||
static POW10TO128: [Digit; 14] = [
|
|
||||||
0, 0, 0, 0, 0x2e953e01, 0x3df9909, 0xf1538fd, 0x2374e42f, 0xd3cff5ec, 0xc404dc08, 0xbccdb0da,
|
|
||||||
0xa6337f19, 0xe91f2603, 0x24e,
|
|
||||||
];
|
];
|
||||||
static POW10TO256: [Digit; 27] = [
|
static POW5TO256: [Digit; 19] = [
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0x982e7c01, 0xbed3875b, 0xd8d99f72, 0x12152f87, 0x6bde50c6, 0xcf4a6e70,
|
0x982e7c01, 0xbed3875b, 0xd8d99f72, 0x12152f87, 0x6bde50c6, 0xcf4a6e70, 0xd595d80f, 0x26b2716e,
|
||||||
0xd595d80f, 0x26b2716e, 0xadc666b0, 0x1d153624, 0x3c42d35a, 0x63ff540e, 0xcc5573c0, 0x65f9ef17,
|
0xadc666b0, 0x1d153624, 0x3c42d35a, 0x63ff540e, 0xcc5573c0, 0x65f9ef17, 0x55bc28f2, 0x80dcc7f7,
|
||||||
0x55bc28f2, 0x80dcc7f7, 0xf46eeddc, 0x5fdcefce, 0x553f7,
|
0xf46eeddc, 0x5fdcefce, 0x553f7,
|
||||||
];
|
];
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn mul_pow10(x: &mut Big, n: usize) -> &mut Big {
|
pub fn mul_pow10(x: &mut Big, n: usize) -> &mut Big {
|
||||||
debug_assert!(n < 512);
|
debug_assert!(n < 512);
|
||||||
|
// Save ourself the left shift for the smallest cases.
|
||||||
|
if n < 8 {
|
||||||
|
return x.mul_small(POW10[n & 7]);
|
||||||
|
}
|
||||||
|
// Multiply by the powers of 5 and shift the 2s in at the end.
|
||||||
|
// This keeps the intermediate products smaller and faster.
|
||||||
if n & 7 != 0 {
|
if n & 7 != 0 {
|
||||||
x.mul_small(POW10[n & 7]);
|
x.mul_small(POW10[n & 7] >> (n & 7));
|
||||||
}
|
}
|
||||||
if n & 8 != 0 {
|
if n & 8 != 0 {
|
||||||
x.mul_small(POW10[8]);
|
x.mul_small(POW10[8] >> 8);
|
||||||
}
|
}
|
||||||
if n & 16 != 0 {
|
if n & 16 != 0 {
|
||||||
x.mul_digits(&POW10TO16);
|
x.mul_digits(&POW5TO16);
|
||||||
}
|
}
|
||||||
if n & 32 != 0 {
|
if n & 32 != 0 {
|
||||||
x.mul_digits(&POW10TO32);
|
x.mul_digits(&POW5TO32);
|
||||||
}
|
}
|
||||||
if n & 64 != 0 {
|
if n & 64 != 0 {
|
||||||
x.mul_digits(&POW10TO64);
|
x.mul_digits(&POW5TO64);
|
||||||
}
|
}
|
||||||
if n & 128 != 0 {
|
if n & 128 != 0 {
|
||||||
x.mul_digits(&POW10TO128);
|
x.mul_digits(&POW5TO128);
|
||||||
}
|
}
|
||||||
if n & 256 != 0 {
|
if n & 256 != 0 {
|
||||||
x.mul_digits(&POW10TO256);
|
x.mul_digits(&POW5TO256);
|
||||||
}
|
}
|
||||||
x
|
x.mul_pow2(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn div_2pow10(x: &mut Big, mut n: usize) -> &mut Big {
|
fn div_2pow10(x: &mut Big, mut n: usize) -> &mut Big {
|
||||||
@ -62,7 +65,7 @@ fn div_2pow10(x: &mut Big, mut n: usize) -> &mut Big {
|
|||||||
x.div_rem_small(POW10[largest]);
|
x.div_rem_small(POW10[largest]);
|
||||||
n -= largest;
|
n -= largest;
|
||||||
}
|
}
|
||||||
x.div_rem_small(TWOPOW10[n]);
|
x.div_rem_small(POW10[n] << 1);
|
||||||
x
|
x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -522,7 +522,7 @@ impl<T> [T] {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "slice_first_last_chunk", since = "1.77.0")]
|
#[stable(feature = "slice_first_last_chunk", since = "1.77.0")]
|
||||||
#[rustc_const_stable(feature = "slice_first_last_chunk", since = "1.77.0")]
|
#[rustc_const_stable(feature = "const_slice_last_chunk", since = "1.80.0")]
|
||||||
pub const fn last_chunk<const N: usize>(&self) -> Option<&[T; N]> {
|
pub const fn last_chunk<const N: usize>(&self) -> Option<&[T; N]> {
|
||||||
if self.len() < N {
|
if self.len() < N {
|
||||||
None
|
None
|
||||||
|
@ -455,8 +455,18 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
|
|||||||
|
|
||||||
Ok(NonZero::new_unchecked(sinfo.cpu_count as usize))
|
Ok(NonZero::new_unchecked(sinfo.cpu_count as usize))
|
||||||
}
|
}
|
||||||
|
} else if #[cfg(target_os = "vxworks")] {
|
||||||
|
// Note: there is also `vxCpuConfiguredGet`, closer to _SC_NPROCESSORS_CONF
|
||||||
|
// expectations than the actual cores availability.
|
||||||
|
extern "C" {
|
||||||
|
fn vxCpuEnabledGet() -> libc::cpuset_t;
|
||||||
|
}
|
||||||
|
|
||||||
|
// always fetches a valid bitmask
|
||||||
|
let set = unsafe { vxCpuEnabledGet() };
|
||||||
|
Ok(NonZero::new_unchecked(set.count_ones() as usize))
|
||||||
} else {
|
} else {
|
||||||
// FIXME: implement on vxWorks, Redox, l4re
|
// FIXME: implement on Redox, l4re
|
||||||
Err(io::const_io_error!(io::ErrorKind::Unsupported, "Getting the number of hardware threads is not supported on the target platform"))
|
Err(io::const_io_error!(io::ErrorKind::Unsupported, "Getting the number of hardware threads is not supported on the target platform"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ use rustc_middle::ty::fast_reject::SimplifiedType;
|
|||||||
use rustc_middle::ty::{self, TyCtxt};
|
use rustc_middle::ty::{self, TyCtxt};
|
||||||
use rustc_span::def_id::LOCAL_CRATE;
|
use rustc_span::def_id::LOCAL_CRATE;
|
||||||
use rustc_span::hygiene::MacroKind;
|
use rustc_span::hygiene::MacroKind;
|
||||||
use rustc_span::symbol::{kw, sym, Symbol};
|
use rustc_span::symbol::{sym, Symbol};
|
||||||
use thin_vec::{thin_vec, ThinVec};
|
use thin_vec::{thin_vec, ThinVec};
|
||||||
use {rustc_ast as ast, rustc_hir as hir};
|
use {rustc_ast as ast, rustc_hir as hir};
|
||||||
|
|
||||||
@ -792,11 +792,7 @@ fn build_macro(
|
|||||||
fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean::Generics {
|
fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean::Generics {
|
||||||
for pred in &mut g.where_predicates {
|
for pred in &mut g.where_predicates {
|
||||||
match *pred {
|
match *pred {
|
||||||
clean::WherePredicate::BoundPredicate {
|
clean::WherePredicate::BoundPredicate { ty: clean::SelfTy, ref mut bounds, .. } => {
|
||||||
ty: clean::Generic(ref s),
|
|
||||||
ref mut bounds,
|
|
||||||
..
|
|
||||||
} if *s == kw::SelfUpper => {
|
|
||||||
bounds.retain(|bound| match bound {
|
bounds.retain(|bound| match bound {
|
||||||
clean::GenericBound::TraitBound(clean::PolyTrait { trait_, .. }, _) => {
|
clean::GenericBound::TraitBound(clean::PolyTrait { trait_, .. }, _) => {
|
||||||
trait_.def_id() != trait_did
|
trait_.def_id() != trait_did
|
||||||
@ -812,13 +808,13 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean:
|
|||||||
clean::WherePredicate::BoundPredicate {
|
clean::WherePredicate::BoundPredicate {
|
||||||
ty:
|
ty:
|
||||||
clean::QPath(box clean::QPathData {
|
clean::QPath(box clean::QPathData {
|
||||||
self_type: clean::Generic(ref s),
|
self_type: clean::Generic(_),
|
||||||
trait_: Some(trait_),
|
trait_: Some(trait_),
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
bounds,
|
bounds,
|
||||||
..
|
..
|
||||||
} => !(bounds.is_empty() || *s == kw::SelfUpper && trait_.def_id() == trait_did),
|
} => !bounds.is_empty() && trait_.def_id() != trait_did,
|
||||||
_ => true,
|
_ => true,
|
||||||
});
|
});
|
||||||
g
|
g
|
||||||
@ -832,9 +828,7 @@ fn separate_supertrait_bounds(
|
|||||||
) -> (clean::Generics, Vec<clean::GenericBound>) {
|
) -> (clean::Generics, Vec<clean::GenericBound>) {
|
||||||
let mut ty_bounds = Vec::new();
|
let mut ty_bounds = Vec::new();
|
||||||
g.where_predicates.retain(|pred| match *pred {
|
g.where_predicates.retain(|pred| match *pred {
|
||||||
clean::WherePredicate::BoundPredicate { ty: clean::Generic(ref s), ref bounds, .. }
|
clean::WherePredicate::BoundPredicate { ty: clean::SelfTy, ref bounds, .. } => {
|
||||||
if *s == kw::SelfUpper =>
|
|
||||||
{
|
|
||||||
ty_bounds.extend(bounds.iter().cloned());
|
ty_bounds.extend(bounds.iter().cloned());
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -1351,11 +1351,11 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
|
|||||||
let self_arg_ty =
|
let self_arg_ty =
|
||||||
tcx.fn_sig(assoc_item.def_id).instantiate_identity().input(0).skip_binder();
|
tcx.fn_sig(assoc_item.def_id).instantiate_identity().input(0).skip_binder();
|
||||||
if self_arg_ty == self_ty {
|
if self_arg_ty == self_ty {
|
||||||
item.decl.inputs.values[0].type_ = Generic(kw::SelfUpper);
|
item.decl.inputs.values[0].type_ = SelfTy;
|
||||||
} else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() {
|
} else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() {
|
||||||
if ty == self_ty {
|
if ty == self_ty {
|
||||||
match item.decl.inputs.values[0].type_ {
|
match item.decl.inputs.values[0].type_ {
|
||||||
BorrowedRef { ref mut type_, .. } => **type_ = Generic(kw::SelfUpper),
|
BorrowedRef { ref mut type_, .. } => **type_ = SelfTy,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1439,9 +1439,8 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
|
|||||||
if trait_.def_id() != assoc_item.container_id(tcx) {
|
if trait_.def_id() != assoc_item.container_id(tcx) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
match *self_type {
|
if *self_type != SelfTy {
|
||||||
Generic(ref s) if *s == kw::SelfUpper => {}
|
return true;
|
||||||
_ => return true,
|
|
||||||
}
|
}
|
||||||
match &assoc.args {
|
match &assoc.args {
|
||||||
GenericArgs::AngleBracketed { args, constraints } => {
|
GenericArgs::AngleBracketed { args, constraints } => {
|
||||||
@ -2228,6 +2227,8 @@ pub(crate) fn clean_middle_ty<'tcx>(
|
|||||||
ty::Param(ref p) => {
|
ty::Param(ref p) => {
|
||||||
if let Some(bounds) = cx.impl_trait_bounds.remove(&p.index.into()) {
|
if let Some(bounds) = cx.impl_trait_bounds.remove(&p.index.into()) {
|
||||||
ImplTrait(bounds)
|
ImplTrait(bounds)
|
||||||
|
} else if p.name == kw::SelfUpper {
|
||||||
|
SelfTy
|
||||||
} else {
|
} else {
|
||||||
Generic(p.name)
|
Generic(p.name)
|
||||||
}
|
}
|
||||||
|
@ -145,7 +145,6 @@ pub(crate) fn sized_bounds(cx: &mut DocContext<'_>, generics: &mut clean::Generi
|
|||||||
// should be handled when cleaning associated types.
|
// should be handled when cleaning associated types.
|
||||||
generics.where_predicates.retain(|pred| {
|
generics.where_predicates.retain(|pred| {
|
||||||
if let WP::BoundPredicate { ty: clean::Generic(param), bounds, .. } = pred
|
if let WP::BoundPredicate { ty: clean::Generic(param), bounds, .. } = pred
|
||||||
&& *param != rustc_span::symbol::kw::SelfUpper
|
|
||||||
&& bounds.iter().any(|b| b.is_sized_bound(cx))
|
&& bounds.iter().any(|b| b.is_sized_bound(cx))
|
||||||
{
|
{
|
||||||
sized_params.insert(*param);
|
sized_params.insert(*param);
|
||||||
|
@ -34,10 +34,9 @@ use thin_vec::ThinVec;
|
|||||||
use {rustc_ast as ast, rustc_hir as hir};
|
use {rustc_ast as ast, rustc_hir as hir};
|
||||||
|
|
||||||
pub(crate) use self::ItemKind::*;
|
pub(crate) use self::ItemKind::*;
|
||||||
pub(crate) use self::SelfTy::*;
|
|
||||||
pub(crate) use self::Type::{
|
pub(crate) use self::Type::{
|
||||||
Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath,
|
Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath,
|
||||||
RawPointer, Slice, Tuple,
|
RawPointer, SelfTy, Slice, Tuple,
|
||||||
};
|
};
|
||||||
use crate::clean::cfg::Cfg;
|
use crate::clean::cfg::Cfg;
|
||||||
use crate::clean::clean_middle_path;
|
use crate::clean::clean_middle_path;
|
||||||
@ -1384,8 +1383,8 @@ pub(crate) struct FnDecl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FnDecl {
|
impl FnDecl {
|
||||||
pub(crate) fn self_type(&self) -> Option<SelfTy> {
|
pub(crate) fn receiver_type(&self) -> Option<&Type> {
|
||||||
self.inputs.values.get(0).and_then(|v| v.to_self())
|
self.inputs.values.get(0).and_then(|v| v.to_receiver())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1403,27 +1402,9 @@ pub(crate) struct Argument {
|
|||||||
pub(crate) is_const: bool,
|
pub(crate) is_const: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
|
||||||
pub(crate) enum SelfTy {
|
|
||||||
SelfValue,
|
|
||||||
SelfBorrowed(Option<Lifetime>, Mutability),
|
|
||||||
SelfExplicit(Type),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Argument {
|
impl Argument {
|
||||||
pub(crate) fn to_self(&self) -> Option<SelfTy> {
|
pub(crate) fn to_receiver(&self) -> Option<&Type> {
|
||||||
if self.name != kw::SelfLower {
|
if self.name == kw::SelfLower { Some(&self.type_) } else { None }
|
||||||
return None;
|
|
||||||
}
|
|
||||||
if self.type_.is_self_type() {
|
|
||||||
return Some(SelfValue);
|
|
||||||
}
|
|
||||||
match self.type_ {
|
|
||||||
BorrowedRef { ref lifetime, mutability, ref type_ } if type_.is_self_type() => {
|
|
||||||
Some(SelfBorrowed(lifetime.clone(), mutability))
|
|
||||||
}
|
|
||||||
_ => Some(SelfExplicit(self.type_.clone())),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1477,6 +1458,8 @@ pub(crate) enum Type {
|
|||||||
DynTrait(Vec<PolyTrait>, Option<Lifetime>),
|
DynTrait(Vec<PolyTrait>, Option<Lifetime>),
|
||||||
/// A type parameter.
|
/// A type parameter.
|
||||||
Generic(Symbol),
|
Generic(Symbol),
|
||||||
|
/// The `Self` type.
|
||||||
|
SelfTy,
|
||||||
/// A primitive (aka, builtin) type.
|
/// A primitive (aka, builtin) type.
|
||||||
Primitive(PrimitiveType),
|
Primitive(PrimitiveType),
|
||||||
/// A function pointer: `extern "ABI" fn(...) -> ...`
|
/// A function pointer: `extern "ABI" fn(...) -> ...`
|
||||||
@ -1571,6 +1554,8 @@ impl Type {
|
|||||||
// If both sides are generic, this returns true.
|
// If both sides are generic, this returns true.
|
||||||
(_, Type::Generic(_)) => true,
|
(_, Type::Generic(_)) => true,
|
||||||
(Type::Generic(_), _) => false,
|
(Type::Generic(_), _) => false,
|
||||||
|
// `Self` only matches itself.
|
||||||
|
(Type::SelfTy, Type::SelfTy) => true,
|
||||||
// Paths account for both the path itself and its generics.
|
// Paths account for both the path itself and its generics.
|
||||||
(Type::Path { path: a }, Type::Path { path: b }) => {
|
(Type::Path { path: a }, Type::Path { path: b }) => {
|
||||||
a.def_id() == b.def_id()
|
a.def_id() == b.def_id()
|
||||||
@ -1642,7 +1627,7 @@ impl Type {
|
|||||||
|
|
||||||
pub(crate) fn is_self_type(&self) -> bool {
|
pub(crate) fn is_self_type(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
Generic(name) => name == kw::SelfUpper,
|
SelfTy => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1700,7 +1685,7 @@ impl Type {
|
|||||||
Type::Pat(..) => PrimitiveType::Pat,
|
Type::Pat(..) => PrimitiveType::Pat,
|
||||||
RawPointer(..) => PrimitiveType::RawPointer,
|
RawPointer(..) => PrimitiveType::RawPointer,
|
||||||
QPath(box QPathData { ref self_type, .. }) => return self_type.def_id(cache),
|
QPath(box QPathData { ref self_type, .. }) => return self_type.def_id(cache),
|
||||||
Generic(_) | Infer | ImplTrait(_) => return None,
|
Generic(_) | SelfTy | Infer | ImplTrait(_) => return None,
|
||||||
};
|
};
|
||||||
Primitive(t).def_id(cache)
|
Primitive(t).def_id(cache)
|
||||||
}
|
}
|
||||||
|
@ -468,7 +468,7 @@ pub(crate) fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type {
|
|||||||
match path.res {
|
match path.res {
|
||||||
Res::PrimTy(p) => Primitive(PrimitiveType::from(p)),
|
Res::PrimTy(p) => Primitive(PrimitiveType::from(p)),
|
||||||
Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } if path.segments.len() == 1 => {
|
Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } if path.segments.len() == 1 => {
|
||||||
Generic(kw::SelfUpper)
|
Type::SelfTy
|
||||||
}
|
}
|
||||||
Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => Generic(path.segments[0].name),
|
Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => Generic(path.segments[0].name),
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -1006,6 +1006,7 @@ fn fmt_type<'cx>(
|
|||||||
|
|
||||||
match *t {
|
match *t {
|
||||||
clean::Generic(name) => f.write_str(name.as_str()),
|
clean::Generic(name) => f.write_str(name.as_str()),
|
||||||
|
clean::SelfTy => f.write_str("Self"),
|
||||||
clean::Type::Path { ref path } => {
|
clean::Type::Path { ref path } => {
|
||||||
// Paths like `T::Output` and `Self::Output` should be rendered with all segments.
|
// Paths like `T::Output` and `Self::Output` should be rendered with all segments.
|
||||||
let did = path.def_id();
|
let did = path.def_id();
|
||||||
@ -1452,29 +1453,22 @@ impl clean::FnDecl {
|
|||||||
|
|
||||||
let last_input_index = self.inputs.values.len().checked_sub(1);
|
let last_input_index = self.inputs.values.len().checked_sub(1);
|
||||||
for (i, input) in self.inputs.values.iter().enumerate() {
|
for (i, input) in self.inputs.values.iter().enumerate() {
|
||||||
if let Some(selfty) = input.to_self() {
|
if let Some(selfty) = input.to_receiver() {
|
||||||
match selfty {
|
match selfty {
|
||||||
clean::SelfValue => {
|
clean::SelfTy => {
|
||||||
write!(f, "self")?;
|
write!(f, "self")?;
|
||||||
}
|
}
|
||||||
clean::SelfBorrowed(Some(ref lt), mutability) => {
|
clean::BorrowedRef { lifetime, mutability, type_: box clean::SelfTy } => {
|
||||||
write!(
|
write!(f, "{amp}")?;
|
||||||
f,
|
match lifetime {
|
||||||
"{amp}{lifetime} {mutability}self",
|
Some(lt) => write!(f, "{lt} ", lt = lt.print())?,
|
||||||
lifetime = lt.print(),
|
None => {}
|
||||||
mutability = mutability.print_with_space(),
|
}
|
||||||
)?;
|
write!(f, "{mutability}self", mutability = mutability.print_with_space())?;
|
||||||
}
|
}
|
||||||
clean::SelfBorrowed(None, mutability) => {
|
_ => {
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"{amp}{mutability}self",
|
|
||||||
mutability = mutability.print_with_space(),
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
clean::SelfExplicit(ref typ) => {
|
|
||||||
write!(f, "self: ")?;
|
write!(f, "self: ")?;
|
||||||
typ.print(cx).fmt(f)?;
|
selfty.print(cx).fmt(f)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -58,7 +58,7 @@ use serde::{Serialize, Serializer};
|
|||||||
|
|
||||||
pub(crate) use self::context::*;
|
pub(crate) use self::context::*;
|
||||||
pub(crate) use self::span_map::{collect_spans_and_sources, LinkFromSrc};
|
pub(crate) use self::span_map::{collect_spans_and_sources, LinkFromSrc};
|
||||||
use crate::clean::{self, ItemId, RenderedLink, SelfTy};
|
use crate::clean::{self, ItemId, RenderedLink};
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::formats::cache::Cache;
|
use crate::formats::cache::Cache;
|
||||||
use crate::formats::item_type::ItemType;
|
use crate::formats::item_type::ItemType;
|
||||||
@ -1372,21 +1372,20 @@ fn render_deref_methods(
|
|||||||
|
|
||||||
fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> bool {
|
fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> bool {
|
||||||
let self_type_opt = match *item.kind {
|
let self_type_opt = match *item.kind {
|
||||||
clean::MethodItem(ref method, _) => method.decl.self_type(),
|
clean::MethodItem(ref method, _) => method.decl.receiver_type(),
|
||||||
clean::TyMethodItem(ref method) => method.decl.self_type(),
|
clean::TyMethodItem(ref method) => method.decl.receiver_type(),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(self_ty) = self_type_opt {
|
if let Some(self_ty) = self_type_opt {
|
||||||
let (by_mut_ref, by_box, by_value) = match self_ty {
|
let (by_mut_ref, by_box, by_value) = match *self_ty {
|
||||||
SelfTy::SelfBorrowed(_, mutability)
|
clean::Type::BorrowedRef { mutability, .. } => {
|
||||||
| SelfTy::SelfExplicit(clean::BorrowedRef { mutability, .. }) => {
|
|
||||||
(mutability == Mutability::Mut, false, false)
|
(mutability == Mutability::Mut, false, false)
|
||||||
}
|
}
|
||||||
SelfTy::SelfExplicit(clean::Type::Path { path }) => {
|
clean::Type::Path { ref path } => {
|
||||||
(false, Some(path.def_id()) == tcx.lang_items().owned_box(), false)
|
(false, Some(path.def_id()) == tcx.lang_items().owned_box(), false)
|
||||||
}
|
}
|
||||||
SelfTy::SelfValue => (false, false, true),
|
clean::Type::SelfTy => (false, false, true),
|
||||||
_ => (false, false, false),
|
_ => (false, false, false),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -797,7 +797,11 @@ fn get_index_type_id(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Not supported yet
|
// Not supported yet
|
||||||
clean::Type::Pat(..) | clean::Generic(_) | clean::ImplTrait(_) | clean::Infer => None,
|
clean::Type::Pat(..)
|
||||||
|
| clean::Generic(_)
|
||||||
|
| clean::SelfTy
|
||||||
|
| clean::ImplTrait(_)
|
||||||
|
| clean::Infer => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -850,15 +854,70 @@ fn simplify_fn_type<'tcx, 'a>(
|
|||||||
|
|
||||||
// If this argument is a type parameter and not a trait bound or a type, we need to look
|
// If this argument is a type parameter and not a trait bound or a type, we need to look
|
||||||
// for its bounds.
|
// for its bounds.
|
||||||
if let Type::Generic(arg_s) = *arg {
|
match *arg {
|
||||||
// First we check if the bounds are in a `where` predicate...
|
Type::Generic(arg_s) => {
|
||||||
let mut type_bounds = Vec::new();
|
// First we check if the bounds are in a `where` predicate...
|
||||||
for where_pred in generics.where_predicates.iter().filter(|g| match g {
|
let mut type_bounds = Vec::new();
|
||||||
WherePredicate::BoundPredicate { ty: Type::Generic(ty_s), .. } => *ty_s == arg_s,
|
for where_pred in generics.where_predicates.iter().filter(|g| match g {
|
||||||
_ => false,
|
WherePredicate::BoundPredicate { ty, .. } => *ty == *arg,
|
||||||
}) {
|
_ => false,
|
||||||
let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]);
|
}) {
|
||||||
for bound in bounds.iter() {
|
let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]);
|
||||||
|
for bound in bounds.iter() {
|
||||||
|
if let Some(path) = bound.get_trait_path() {
|
||||||
|
let ty = Type::Path { path };
|
||||||
|
simplify_fn_type(
|
||||||
|
self_,
|
||||||
|
generics,
|
||||||
|
&ty,
|
||||||
|
tcx,
|
||||||
|
recurse + 1,
|
||||||
|
&mut type_bounds,
|
||||||
|
rgen,
|
||||||
|
is_return,
|
||||||
|
cache,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Otherwise we check if the trait bounds are "inlined" like `T: Option<u32>`...
|
||||||
|
if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) {
|
||||||
|
for bound in bound.get_bounds().unwrap_or(&[]) {
|
||||||
|
if let Some(path) = bound.get_trait_path() {
|
||||||
|
let ty = Type::Path { path };
|
||||||
|
simplify_fn_type(
|
||||||
|
self_,
|
||||||
|
generics,
|
||||||
|
&ty,
|
||||||
|
tcx,
|
||||||
|
recurse + 1,
|
||||||
|
&mut type_bounds,
|
||||||
|
rgen,
|
||||||
|
is_return,
|
||||||
|
cache,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some((idx, _)) = rgen.get(&SimplifiedParam::Symbol(arg_s)) {
|
||||||
|
res.push(RenderType {
|
||||||
|
id: Some(RenderTypeId::Index(*idx)),
|
||||||
|
generics: None,
|
||||||
|
bindings: None,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
let idx = -isize::try_from(rgen.len() + 1).unwrap();
|
||||||
|
rgen.insert(SimplifiedParam::Symbol(arg_s), (idx, type_bounds));
|
||||||
|
res.push(RenderType {
|
||||||
|
id: Some(RenderTypeId::Index(idx)),
|
||||||
|
generics: None,
|
||||||
|
bindings: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Type::ImplTrait(ref bounds) => {
|
||||||
|
let mut type_bounds = Vec::new();
|
||||||
|
for bound in bounds {
|
||||||
if let Some(path) = bound.get_trait_path() {
|
if let Some(path) = bound.get_trait_path() {
|
||||||
let ty = Type::Path { path };
|
let ty = Type::Path { path };
|
||||||
simplify_fn_type(
|
simplify_fn_type(
|
||||||
@ -874,103 +933,22 @@ fn simplify_fn_type<'tcx, 'a>(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if is_return && !type_bounds.is_empty() {
|
||||||
// Otherwise we check if the trait bounds are "inlined" like `T: Option<u32>`...
|
// In return position, `impl Trait` is a unique thing.
|
||||||
if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) {
|
res.push(RenderType { id: None, generics: Some(type_bounds), bindings: None });
|
||||||
for bound in bound.get_bounds().unwrap_or(&[]) {
|
} else {
|
||||||
if let Some(path) = bound.get_trait_path() {
|
// In parameter position, `impl Trait` is the same as an unnamed generic parameter.
|
||||||
let ty = Type::Path { path };
|
let idx = -isize::try_from(rgen.len() + 1).unwrap();
|
||||||
simplify_fn_type(
|
rgen.insert(SimplifiedParam::Anonymous(idx), (idx, type_bounds));
|
||||||
self_,
|
res.push(RenderType {
|
||||||
generics,
|
id: Some(RenderTypeId::Index(idx)),
|
||||||
&ty,
|
generics: None,
|
||||||
tcx,
|
bindings: None,
|
||||||
recurse + 1,
|
});
|
||||||
&mut type_bounds,
|
|
||||||
rgen,
|
|
||||||
is_return,
|
|
||||||
cache,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some((idx, _)) = rgen.get(&SimplifiedParam::Symbol(arg_s)) {
|
Type::Slice(ref ty) => {
|
||||||
res.push(RenderType {
|
let mut ty_generics = Vec::new();
|
||||||
id: Some(RenderTypeId::Index(*idx)),
|
|
||||||
generics: None,
|
|
||||||
bindings: None,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
let idx = -isize::try_from(rgen.len() + 1).unwrap();
|
|
||||||
rgen.insert(SimplifiedParam::Symbol(arg_s), (idx, type_bounds));
|
|
||||||
res.push(RenderType {
|
|
||||||
id: Some(RenderTypeId::Index(idx)),
|
|
||||||
generics: None,
|
|
||||||
bindings: None,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if let Type::ImplTrait(ref bounds) = *arg {
|
|
||||||
let mut type_bounds = Vec::new();
|
|
||||||
for bound in bounds {
|
|
||||||
if let Some(path) = bound.get_trait_path() {
|
|
||||||
let ty = Type::Path { path };
|
|
||||||
simplify_fn_type(
|
|
||||||
self_,
|
|
||||||
generics,
|
|
||||||
&ty,
|
|
||||||
tcx,
|
|
||||||
recurse + 1,
|
|
||||||
&mut type_bounds,
|
|
||||||
rgen,
|
|
||||||
is_return,
|
|
||||||
cache,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if is_return && !type_bounds.is_empty() {
|
|
||||||
// In parameter position, `impl Trait` is a unique thing.
|
|
||||||
res.push(RenderType { id: None, generics: Some(type_bounds), bindings: None });
|
|
||||||
} else {
|
|
||||||
// In parameter position, `impl Trait` is the same as an unnamed generic parameter.
|
|
||||||
let idx = -isize::try_from(rgen.len() + 1).unwrap();
|
|
||||||
rgen.insert(SimplifiedParam::Anonymous(idx), (idx, type_bounds));
|
|
||||||
res.push(RenderType {
|
|
||||||
id: Some(RenderTypeId::Index(idx)),
|
|
||||||
generics: None,
|
|
||||||
bindings: None,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if let Type::Slice(ref ty) = *arg {
|
|
||||||
let mut ty_generics = Vec::new();
|
|
||||||
simplify_fn_type(
|
|
||||||
self_,
|
|
||||||
generics,
|
|
||||||
&ty,
|
|
||||||
tcx,
|
|
||||||
recurse + 1,
|
|
||||||
&mut ty_generics,
|
|
||||||
rgen,
|
|
||||||
is_return,
|
|
||||||
cache,
|
|
||||||
);
|
|
||||||
res.push(get_index_type(arg, ty_generics, rgen));
|
|
||||||
} else if let Type::Array(ref ty, _) = *arg {
|
|
||||||
let mut ty_generics = Vec::new();
|
|
||||||
simplify_fn_type(
|
|
||||||
self_,
|
|
||||||
generics,
|
|
||||||
&ty,
|
|
||||||
tcx,
|
|
||||||
recurse + 1,
|
|
||||||
&mut ty_generics,
|
|
||||||
rgen,
|
|
||||||
is_return,
|
|
||||||
cache,
|
|
||||||
);
|
|
||||||
res.push(get_index_type(arg, ty_generics, rgen));
|
|
||||||
} else if let Type::Tuple(ref tys) = *arg {
|
|
||||||
let mut ty_generics = Vec::new();
|
|
||||||
for ty in tys {
|
|
||||||
simplify_fn_type(
|
simplify_fn_type(
|
||||||
self_,
|
self_,
|
||||||
generics,
|
generics,
|
||||||
@ -982,15 +960,14 @@ fn simplify_fn_type<'tcx, 'a>(
|
|||||||
is_return,
|
is_return,
|
||||||
cache,
|
cache,
|
||||||
);
|
);
|
||||||
|
res.push(get_index_type(arg, ty_generics, rgen));
|
||||||
}
|
}
|
||||||
res.push(get_index_type(arg, ty_generics, rgen));
|
Type::Array(ref ty, _) => {
|
||||||
} else if let Type::BareFunction(ref bf) = *arg {
|
let mut ty_generics = Vec::new();
|
||||||
let mut ty_generics = Vec::new();
|
|
||||||
for ty in bf.decl.inputs.values.iter().map(|arg| &arg.type_) {
|
|
||||||
simplify_fn_type(
|
simplify_fn_type(
|
||||||
self_,
|
self_,
|
||||||
generics,
|
generics,
|
||||||
ty,
|
&ty,
|
||||||
tcx,
|
tcx,
|
||||||
recurse + 1,
|
recurse + 1,
|
||||||
&mut ty_generics,
|
&mut ty_generics,
|
||||||
@ -998,62 +975,11 @@ fn simplify_fn_type<'tcx, 'a>(
|
|||||||
is_return,
|
is_return,
|
||||||
cache,
|
cache,
|
||||||
);
|
);
|
||||||
|
res.push(get_index_type(arg, ty_generics, rgen));
|
||||||
}
|
}
|
||||||
// The search index, for simplicity's sake, represents fn pointers and closures
|
Type::Tuple(ref tys) => {
|
||||||
// the same way: as a tuple for the parameters, and an associated type for the
|
let mut ty_generics = Vec::new();
|
||||||
// return type.
|
for ty in tys {
|
||||||
let mut ty_output = Vec::new();
|
|
||||||
simplify_fn_type(
|
|
||||||
self_,
|
|
||||||
generics,
|
|
||||||
&bf.decl.output,
|
|
||||||
tcx,
|
|
||||||
recurse + 1,
|
|
||||||
&mut ty_output,
|
|
||||||
rgen,
|
|
||||||
is_return,
|
|
||||||
cache,
|
|
||||||
);
|
|
||||||
let ty_bindings = vec![(RenderTypeId::AssociatedType(sym::Output), ty_output)];
|
|
||||||
res.push(RenderType {
|
|
||||||
id: get_index_type_id(&arg, rgen),
|
|
||||||
bindings: Some(ty_bindings),
|
|
||||||
generics: Some(ty_generics),
|
|
||||||
});
|
|
||||||
} else if let Type::BorrowedRef { lifetime: _, mutability, ref type_ } = *arg {
|
|
||||||
let mut ty_generics = Vec::new();
|
|
||||||
if mutability.is_mut() {
|
|
||||||
ty_generics.push(RenderType {
|
|
||||||
id: Some(RenderTypeId::Mut),
|
|
||||||
generics: None,
|
|
||||||
bindings: None,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
simplify_fn_type(
|
|
||||||
self_,
|
|
||||||
generics,
|
|
||||||
&type_,
|
|
||||||
tcx,
|
|
||||||
recurse + 1,
|
|
||||||
&mut ty_generics,
|
|
||||||
rgen,
|
|
||||||
is_return,
|
|
||||||
cache,
|
|
||||||
);
|
|
||||||
res.push(get_index_type(arg, ty_generics, rgen));
|
|
||||||
} else {
|
|
||||||
// This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
|
|
||||||
// looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't.
|
|
||||||
//
|
|
||||||
// So in here, we can add it directly and look for its own type parameters (so for `Option`,
|
|
||||||
// we will look for them but not for `T`).
|
|
||||||
let mut ty_generics = Vec::new();
|
|
||||||
let mut ty_constraints = Vec::new();
|
|
||||||
if let Some(arg_generics) = arg.generic_args() {
|
|
||||||
for ty in arg_generics.into_iter().filter_map(|param| match param {
|
|
||||||
clean::GenericArg::Type(ty) => Some(ty),
|
|
||||||
_ => None,
|
|
||||||
}) {
|
|
||||||
simplify_fn_type(
|
simplify_fn_type(
|
||||||
self_,
|
self_,
|
||||||
generics,
|
generics,
|
||||||
@ -1066,94 +992,181 @@ fn simplify_fn_type<'tcx, 'a>(
|
|||||||
cache,
|
cache,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
for constraint in arg_generics.constraints() {
|
res.push(get_index_type(arg, ty_generics, rgen));
|
||||||
simplify_fn_constraint(
|
}
|
||||||
|
Type::BareFunction(ref bf) => {
|
||||||
|
let mut ty_generics = Vec::new();
|
||||||
|
for ty in bf.decl.inputs.values.iter().map(|arg| &arg.type_) {
|
||||||
|
simplify_fn_type(
|
||||||
self_,
|
self_,
|
||||||
generics,
|
generics,
|
||||||
&constraint,
|
ty,
|
||||||
tcx,
|
tcx,
|
||||||
recurse + 1,
|
recurse + 1,
|
||||||
&mut ty_constraints,
|
&mut ty_generics,
|
||||||
rgen,
|
rgen,
|
||||||
is_return,
|
is_return,
|
||||||
cache,
|
cache,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// The search index, for simplicity's sake, represents fn pointers and closures
|
||||||
|
// the same way: as a tuple for the parameters, and an associated type for the
|
||||||
|
// return type.
|
||||||
|
let mut ty_output = Vec::new();
|
||||||
|
simplify_fn_type(
|
||||||
|
self_,
|
||||||
|
generics,
|
||||||
|
&bf.decl.output,
|
||||||
|
tcx,
|
||||||
|
recurse + 1,
|
||||||
|
&mut ty_output,
|
||||||
|
rgen,
|
||||||
|
is_return,
|
||||||
|
cache,
|
||||||
|
);
|
||||||
|
let ty_bindings = vec![(RenderTypeId::AssociatedType(sym::Output), ty_output)];
|
||||||
|
res.push(RenderType {
|
||||||
|
id: get_index_type_id(&arg, rgen),
|
||||||
|
bindings: Some(ty_bindings),
|
||||||
|
generics: Some(ty_generics),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
// Every trait associated type on self gets assigned to a type parameter index
|
Type::BorrowedRef { lifetime: _, mutability, ref type_ } => {
|
||||||
// this same one is used later for any appearances of these types
|
let mut ty_generics = Vec::new();
|
||||||
//
|
if mutability.is_mut() {
|
||||||
// for example, Iterator::next is:
|
ty_generics.push(RenderType {
|
||||||
//
|
id: Some(RenderTypeId::Mut),
|
||||||
// trait Iterator {
|
generics: None,
|
||||||
// fn next(&mut self) -> Option<Self::Item>
|
bindings: None,
|
||||||
// }
|
});
|
||||||
//
|
}
|
||||||
// Self is technically just Iterator, but we want to pretend it's more like this:
|
simplify_fn_type(
|
||||||
//
|
self_,
|
||||||
// fn next<T>(self: Iterator<Item=T>) -> Option<T>
|
generics,
|
||||||
if is_self
|
&type_,
|
||||||
&& let Type::Path { path } = arg
|
tcx,
|
||||||
&& let def_id = path.def_id()
|
recurse + 1,
|
||||||
&& let Some(trait_) = cache.traits.get(&def_id)
|
&mut ty_generics,
|
||||||
&& trait_.items.iter().any(|at| at.is_ty_associated_type())
|
rgen,
|
||||||
{
|
is_return,
|
||||||
for assoc_ty in &trait_.items {
|
cache,
|
||||||
if let clean::ItemKind::TyAssocTypeItem(_generics, bounds) = &*assoc_ty.kind
|
);
|
||||||
&& let Some(name) = assoc_ty.name
|
res.push(get_index_type(arg, ty_generics, rgen));
|
||||||
{
|
}
|
||||||
let idx = -isize::try_from(rgen.len() + 1).unwrap();
|
_ => {
|
||||||
let (idx, stored_bounds) = rgen
|
// This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
|
||||||
.entry(SimplifiedParam::AssociatedType(def_id, name))
|
// looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't.
|
||||||
.or_insert_with(|| (idx, Vec::new()));
|
//
|
||||||
let idx = *idx;
|
// So in here, we can add it directly and look for its own type parameters (so for `Option`,
|
||||||
if stored_bounds.is_empty() {
|
// we will look for them but not for `T`).
|
||||||
// Can't just pass stored_bounds to simplify_fn_type,
|
let mut ty_generics = Vec::new();
|
||||||
// because it also accepts rgen as a parameter.
|
let mut ty_constraints = Vec::new();
|
||||||
// Instead, have it fill in this local, then copy it into the map afterward.
|
if let Some(arg_generics) = arg.generic_args() {
|
||||||
let mut type_bounds = Vec::new();
|
for ty in arg_generics.into_iter().filter_map(|param| match param {
|
||||||
for bound in bounds {
|
clean::GenericArg::Type(ty) => Some(ty),
|
||||||
if let Some(path) = bound.get_trait_path() {
|
_ => None,
|
||||||
let ty = Type::Path { path };
|
}) {
|
||||||
simplify_fn_type(
|
simplify_fn_type(
|
||||||
self_,
|
self_,
|
||||||
generics,
|
generics,
|
||||||
&ty,
|
&ty,
|
||||||
tcx,
|
tcx,
|
||||||
recurse + 1,
|
recurse + 1,
|
||||||
&mut type_bounds,
|
&mut ty_generics,
|
||||||
rgen,
|
rgen,
|
||||||
is_return,
|
is_return,
|
||||||
cache,
|
cache,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
for constraint in arg_generics.constraints() {
|
||||||
let stored_bounds = &mut rgen
|
simplify_fn_constraint(
|
||||||
.get_mut(&SimplifiedParam::AssociatedType(def_id, name))
|
self_,
|
||||||
.unwrap()
|
generics,
|
||||||
.1;
|
&constraint,
|
||||||
if stored_bounds.is_empty() {
|
tcx,
|
||||||
*stored_bounds = type_bounds;
|
recurse + 1,
|
||||||
}
|
&mut ty_constraints,
|
||||||
}
|
rgen,
|
||||||
ty_constraints.push((
|
is_return,
|
||||||
RenderTypeId::AssociatedType(name),
|
cache,
|
||||||
vec![RenderType {
|
);
|
||||||
id: Some(RenderTypeId::Index(idx)),
|
|
||||||
generics: None,
|
|
||||||
bindings: None,
|
|
||||||
}],
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
// Every trait associated type on self gets assigned to a type parameter index
|
||||||
let id = get_index_type_id(&arg, rgen);
|
// this same one is used later for any appearances of these types
|
||||||
if id.is_some() || !ty_generics.is_empty() {
|
//
|
||||||
res.push(RenderType {
|
// for example, Iterator::next is:
|
||||||
id,
|
//
|
||||||
bindings: if ty_constraints.is_empty() { None } else { Some(ty_constraints) },
|
// trait Iterator {
|
||||||
generics: if ty_generics.is_empty() { None } else { Some(ty_generics) },
|
// fn next(&mut self) -> Option<Self::Item>
|
||||||
});
|
// }
|
||||||
|
//
|
||||||
|
// Self is technically just Iterator, but we want to pretend it's more like this:
|
||||||
|
//
|
||||||
|
// fn next<T>(self: Iterator<Item=T>) -> Option<T>
|
||||||
|
if is_self
|
||||||
|
&& let Type::Path { path } = arg
|
||||||
|
&& let def_id = path.def_id()
|
||||||
|
&& let Some(trait_) = cache.traits.get(&def_id)
|
||||||
|
&& trait_.items.iter().any(|at| at.is_ty_associated_type())
|
||||||
|
{
|
||||||
|
for assoc_ty in &trait_.items {
|
||||||
|
if let clean::ItemKind::TyAssocTypeItem(_generics, bounds) = &*assoc_ty.kind
|
||||||
|
&& let Some(name) = assoc_ty.name
|
||||||
|
{
|
||||||
|
let idx = -isize::try_from(rgen.len() + 1).unwrap();
|
||||||
|
let (idx, stored_bounds) = rgen
|
||||||
|
.entry(SimplifiedParam::AssociatedType(def_id, name))
|
||||||
|
.or_insert_with(|| (idx, Vec::new()));
|
||||||
|
let idx = *idx;
|
||||||
|
if stored_bounds.is_empty() {
|
||||||
|
// Can't just pass stored_bounds to simplify_fn_type,
|
||||||
|
// because it also accepts rgen as a parameter.
|
||||||
|
// Instead, have it fill in this local, then copy it into the map afterward.
|
||||||
|
let mut type_bounds = Vec::new();
|
||||||
|
for bound in bounds {
|
||||||
|
if let Some(path) = bound.get_trait_path() {
|
||||||
|
let ty = Type::Path { path };
|
||||||
|
simplify_fn_type(
|
||||||
|
self_,
|
||||||
|
generics,
|
||||||
|
&ty,
|
||||||
|
tcx,
|
||||||
|
recurse + 1,
|
||||||
|
&mut type_bounds,
|
||||||
|
rgen,
|
||||||
|
is_return,
|
||||||
|
cache,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let stored_bounds = &mut rgen
|
||||||
|
.get_mut(&SimplifiedParam::AssociatedType(def_id, name))
|
||||||
|
.unwrap()
|
||||||
|
.1;
|
||||||
|
if stored_bounds.is_empty() {
|
||||||
|
*stored_bounds = type_bounds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ty_constraints.push((
|
||||||
|
RenderTypeId::AssociatedType(name),
|
||||||
|
vec![RenderType {
|
||||||
|
id: Some(RenderTypeId::Index(idx)),
|
||||||
|
generics: None,
|
||||||
|
bindings: None,
|
||||||
|
}],
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let id = get_index_type_id(&arg, rgen);
|
||||||
|
if id.is_some() || !ty_generics.is_empty() {
|
||||||
|
res.push(RenderType {
|
||||||
|
id,
|
||||||
|
bindings: if ty_constraints.is_empty() { None } else { Some(ty_constraints) },
|
||||||
|
generics: if ty_generics.is_empty() { None } else { Some(ty_generics) },
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -578,7 +578,7 @@ impl FromWithTcx<clean::Type> for Type {
|
|||||||
fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
|
fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
|
||||||
use clean::Type::{
|
use clean::Type::{
|
||||||
Array, BareFunction, BorrowedRef, Generic, ImplTrait, Infer, Primitive, QPath,
|
Array, BareFunction, BorrowedRef, Generic, ImplTrait, Infer, Primitive, QPath,
|
||||||
RawPointer, Slice, Tuple,
|
RawPointer, SelfTy, Slice, Tuple,
|
||||||
};
|
};
|
||||||
|
|
||||||
match ty {
|
match ty {
|
||||||
@ -588,6 +588,8 @@ impl FromWithTcx<clean::Type> for Type {
|
|||||||
traits: bounds.into_tcx(tcx),
|
traits: bounds.into_tcx(tcx),
|
||||||
}),
|
}),
|
||||||
Generic(s) => Type::Generic(s.to_string()),
|
Generic(s) => Type::Generic(s.to_string()),
|
||||||
|
// FIXME: add dedicated variant to json Type?
|
||||||
|
SelfTy => Type::Generic("Self".to_owned()),
|
||||||
Primitive(p) => Type::Primitive(p.as_sym().to_string()),
|
Primitive(p) => Type::Primitive(p.as_sym().to_string()),
|
||||||
BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))),
|
BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))),
|
||||||
Tuple(t) => Type::Tuple(t.into_tcx(tcx)),
|
Tuple(t) => Type::Tuple(t.into_tcx(tcx)),
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use super::cygpath::get_windows_path;
|
|
||||||
use crate::artifact_names::{dynamic_lib_name, static_lib_name};
|
use crate::artifact_names::{dynamic_lib_name, static_lib_name};
|
||||||
use crate::external_deps::cc::{cc, cxx};
|
use crate::external_deps::cc::{cc, cxx};
|
||||||
use crate::external_deps::llvm::llvm_ar;
|
use crate::external_deps::llvm::llvm_ar;
|
||||||
@ -44,8 +43,7 @@ pub fn build_native_dynamic_lib(lib_name: &str) -> PathBuf {
|
|||||||
};
|
};
|
||||||
let obj_file = if is_msvc() { format!("{lib_name}.obj") } else { format!("{lib_name}.o") };
|
let obj_file = if is_msvc() { format!("{lib_name}.obj") } else { format!("{lib_name}.o") };
|
||||||
if is_msvc() {
|
if is_msvc() {
|
||||||
let mut out_arg = "-out:".to_owned();
|
let out_arg = format!("-out:{lib_path}");
|
||||||
out_arg.push_str(&get_windows_path(&lib_path));
|
|
||||||
cc().input(&obj_file).args(&["-link", "-dll", &out_arg]).run();
|
cc().input(&obj_file).args(&["-link", "-dll", &out_arg]).run();
|
||||||
} else if is_darwin() {
|
} else if is_darwin() {
|
||||||
cc().out_exe(&lib_path).input(&obj_file).args(&["-dynamiclib", "-Wl,-dylib"]).run();
|
cc().out_exe(&lib_path).input(&obj_file).args(&["-dynamiclib", "-Wl,-dylib"]).run();
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
// FIXME(jieyouxu): can we get rid of the `cygpath` external dependency?
|
|
||||||
use super::cygpath::get_windows_path;
|
|
||||||
use crate::command::Command;
|
use crate::command::Command;
|
||||||
use crate::{env_var, is_msvc, is_windows, uname};
|
use crate::{env_var, is_msvc, is_windows, uname};
|
||||||
|
|
||||||
@ -97,12 +95,12 @@ impl Cc {
|
|||||||
|
|
||||||
if is_msvc() {
|
if is_msvc() {
|
||||||
path.set_extension("exe");
|
path.set_extension("exe");
|
||||||
let fe_path = get_windows_path(&path);
|
let fe_path = path.clone();
|
||||||
path.set_extension("");
|
path.set_extension("");
|
||||||
path.set_extension("obj");
|
path.set_extension("obj");
|
||||||
let fo_path = get_windows_path(path);
|
let fo_path = path;
|
||||||
self.cmd.arg(format!("-Fe:{fe_path}"));
|
self.cmd.arg(format!("-Fe:{}", fe_path.to_str().unwrap()));
|
||||||
self.cmd.arg(format!("-Fo:{fo_path}"));
|
self.cmd.arg(format!("-Fo:{}", fo_path.to_str().unwrap()));
|
||||||
} else {
|
} else {
|
||||||
self.cmd.arg("-o");
|
self.cmd.arg("-o");
|
||||||
self.cmd.arg(name);
|
self.cmd.arg(name);
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
use std::panic;
|
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
use crate::command::Command;
|
|
||||||
use crate::util::handle_failed_output;
|
|
||||||
|
|
||||||
/// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is
|
|
||||||
/// available on the platform!
|
|
||||||
///
|
|
||||||
/// # FIXME
|
|
||||||
///
|
|
||||||
/// FIXME(jieyouxu): we should consider not depending on `cygpath`.
|
|
||||||
///
|
|
||||||
/// > The cygpath program is a utility that converts Windows native filenames to Cygwin POSIX-style
|
|
||||||
/// > pathnames and vice versa.
|
|
||||||
/// >
|
|
||||||
/// > [irrelevant entries omitted...]
|
|
||||||
/// >
|
|
||||||
/// > `-w, --windows print Windows form of NAMEs (C:\WINNT)`
|
|
||||||
/// >
|
|
||||||
/// > -- *from [cygpath documentation](https://cygwin.com/cygwin-ug-net/cygpath.html)*.
|
|
||||||
#[track_caller]
|
|
||||||
#[must_use]
|
|
||||||
pub fn get_windows_path<P: AsRef<Path>>(path: P) -> String {
|
|
||||||
let caller = panic::Location::caller();
|
|
||||||
let mut cygpath = Command::new("cygpath");
|
|
||||||
cygpath.arg("-w");
|
|
||||||
cygpath.arg(path.as_ref());
|
|
||||||
let output = cygpath.run();
|
|
||||||
if !output.status().success() {
|
|
||||||
handle_failed_output(&cygpath, output, caller.line());
|
|
||||||
}
|
|
||||||
// cygpath -w can attach a newline
|
|
||||||
output.stdout_utf8().trim().to_string()
|
|
||||||
}
|
|
@ -9,6 +9,3 @@ pub mod llvm;
|
|||||||
pub mod python;
|
pub mod python;
|
||||||
pub mod rustc;
|
pub mod rustc;
|
||||||
pub mod rustdoc;
|
pub mod rustdoc;
|
||||||
|
|
||||||
// Library-internal external dependency.
|
|
||||||
mod cygpath;
|
|
||||||
|
14
tests/crashes/128094.rs
Normal file
14
tests/crashes/128094.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
//@ known-bug: rust-lang/rust#128094
|
||||||
|
//@ compile-flags: -Zmir-opt-level=5 --edition=2018
|
||||||
|
|
||||||
|
pub enum Request {
|
||||||
|
TestSome(T),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn handle_event(event: Request) {
|
||||||
|
async move {
|
||||||
|
static instance: Request = Request { bar: 17 };
|
||||||
|
&instance
|
||||||
|
}
|
||||||
|
.await;
|
||||||
|
}
|
13
tests/crashes/128176.rs
Normal file
13
tests/crashes/128176.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
//@ known-bug: rust-lang/rust#128176
|
||||||
|
|
||||||
|
#![feature(generic_const_exprs)]
|
||||||
|
#![feature(object_safe_for_dispatch)]
|
||||||
|
trait X {
|
||||||
|
type Y<const N: i16>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const _: () = {
|
||||||
|
fn f2<'a>(arg: Box<dyn X<Y<1> = &'a ()>>) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main() {}
|
7
tests/crashes/128190.rs
Normal file
7
tests/crashes/128190.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
//@ known-bug: rust-lang/rust#128190
|
||||||
|
|
||||||
|
fn a(&self) {
|
||||||
|
15
|
||||||
|
}
|
||||||
|
|
||||||
|
reuse a as b { struct S; }
|
5
tests/crashes/128327.rs
Normal file
5
tests/crashes/128327.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
//@ known-bug: rust-lang/rust#128327
|
||||||
|
|
||||||
|
use std::ops::Deref;
|
||||||
|
struct Apple((Apple, <&'static [f64] as Deref>::Target(Banana ? Citron)));
|
||||||
|
fn main(){}
|
13
tests/crashes/128346.rs
Normal file
13
tests/crashes/128346.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
//@ known-bug: rust-lang/rust#128346
|
||||||
|
|
||||||
|
macro_rules! one_rep {
|
||||||
|
( $($a:ident)* ) => {
|
||||||
|
A(
|
||||||
|
const ${concat($a, Z)}: i32 = 3;
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
one_rep!(A B C);
|
||||||
|
}
|
16
tests/crashes/128621-2.rs
Normal file
16
tests/crashes/128621-2.rs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
//@ known-bug: rust-lang/rust#128621
|
||||||
|
|
||||||
|
#![feature(ptr_metadata)]
|
||||||
|
use std::{ops::FnMut, ptr::Pointee};
|
||||||
|
|
||||||
|
pub type EmplacerFn<'a, T> = dyn for<'b> FnMut(<T as Pointee>::Metadata) + 'a;
|
||||||
|
|
||||||
|
pub struct Emplacer<'a, T>(EmplacerFn<'a, T>);
|
||||||
|
|
||||||
|
impl<'a, T> Emplacer<'a, T> {
|
||||||
|
pub unsafe fn from_fn<'b>(emplacer_fn: &'b mut EmplacerFn<'a, T>) -> &'b mut Self {
|
||||||
|
unsafe { &mut *((emplacer_fn as *mut EmplacerFn<'a, T>) as *mut Self) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {}
|
19
tests/crashes/128621.rs
Normal file
19
tests/crashes/128621.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
//@ known-bug: rust-lang/rust#128621
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
type Associated;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Trait for i32 {
|
||||||
|
type Associated = i64;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Generic<T> {}
|
||||||
|
|
||||||
|
type TraitObject = dyn Generic<<i32 as Trait>::Associated>;
|
||||||
|
|
||||||
|
struct Wrap(TraitObject);
|
||||||
|
|
||||||
|
fn cast(x: *mut TraitObject) {
|
||||||
|
x as *mut Wrap;
|
||||||
|
}
|
@ -4,12 +4,8 @@
|
|||||||
// are exported, and that generics are only shown if explicitely requested.
|
// are exported, and that generics are only shown if explicitely requested.
|
||||||
// See https://github.com/rust-lang/rust/issues/37530
|
// See https://github.com/rust-lang/rust/issues/37530
|
||||||
|
|
||||||
//@ ignore-windows-msvc
|
use run_make_support::object::read::Object;
|
||||||
|
use run_make_support::{bin_name, dynamic_lib_name, is_msvc, object, regex, rfs, rustc};
|
||||||
//FIXME(Oneirical): This currently uses llvm-nm for symbol detection. However,
|
|
||||||
// the custom Rust-based solution of #128314 may prove to be an interesting alternative.
|
|
||||||
|
|
||||||
use run_make_support::{bin_name, dynamic_lib_name, is_darwin, is_windows, llvm_nm, regex, rustc};
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let cdylib_name = dynamic_lib_name("a_cdylib");
|
let cdylib_name = dynamic_lib_name("a_cdylib");
|
||||||
@ -64,16 +60,15 @@ fn main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// FIXME(nbdd0121): This is broken in MinGW, see https://github.com/rust-lang/rust/pull/95604#issuecomment-1101564032
|
// FIXME(nbdd0121): This is broken in MinGW, see https://github.com/rust-lang/rust/pull/95604#issuecomment-1101564032
|
||||||
// if is_windows() {
|
if is_msvc() {
|
||||||
// // Check that an executable does not export any dynamic symbols
|
// Check that an executable does not export any dynamic symbols
|
||||||
// symbols_check(&exe_name, SymbolCheckType::StrSymbol("public_c_function_from_rlib")
|
symbols_check(&exe_name, SymbolCheckType::StrSymbol("public_c_function_from_rlib"), false);
|
||||||
//, false);
|
symbols_check(
|
||||||
// symbols_check(
|
&exe_name,
|
||||||
// &exe_name,
|
SymbolCheckType::StrSymbol("public_rust_function_from_exe"),
|
||||||
// SymbolCheckType::StrSymbol("public_rust_function_from_exe"),
|
false,
|
||||||
// false,
|
);
|
||||||
// );
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
// Check the combined case, where we generate a cdylib and an rlib in the same
|
// Check the combined case, where we generate a cdylib and an rlib in the same
|
||||||
// compilation session:
|
// compilation session:
|
||||||
@ -131,44 +126,37 @@ fn main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// FIXME(nbdd0121): This is broken in MinGW, see https://github.com/rust-lang/rust/pull/95604#issuecomment-1101564032
|
// FIXME(nbdd0121): This is broken in MinGW, see https://github.com/rust-lang/rust/pull/95604#issuecomment-1101564032
|
||||||
// if is_windows() {
|
if is_msvc() {
|
||||||
// // Check that an executable does not export any dynamic symbols
|
// Check that an executable does not export any dynamic symbols
|
||||||
// symbols_check(&exe_name, SymbolCheckType::StrSymbol("public_c_function_from_rlib")
|
symbols_check(&exe_name, SymbolCheckType::StrSymbol("public_c_function_from_rlib"), false);
|
||||||
//, false);
|
symbols_check(
|
||||||
// symbols_check(
|
&exe_name,
|
||||||
// &exe_name,
|
SymbolCheckType::StrSymbol("public_rust_function_from_exe"),
|
||||||
// SymbolCheckType::StrSymbol("public_rust_function_from_exe"),
|
false,
|
||||||
// false,
|
);
|
||||||
// );
|
}
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn symbols_check(path: &str, symbol_check_type: SymbolCheckType, exists_once: bool) {
|
fn symbols_check(path: &str, symbol_check_type: SymbolCheckType, exists_once: bool) {
|
||||||
let mut nm = llvm_nm();
|
let binary_data = rfs::read(path);
|
||||||
if is_windows() {
|
let file = object::File::parse(&*binary_data).unwrap();
|
||||||
nm.arg("--extern-only");
|
let mut found: u64 = 0;
|
||||||
} else if is_darwin() {
|
for export in file.exports().unwrap() {
|
||||||
nm.arg("--extern-only").arg("--defined-only");
|
let name = std::str::from_utf8(export.name()).unwrap();
|
||||||
} else {
|
if has_symbol(name, symbol_check_type) {
|
||||||
nm.arg("--dynamic");
|
found += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let out = nm.input(path).run().stdout_utf8();
|
assert_eq!(found, exists_once as u64);
|
||||||
assert_eq!(
|
|
||||||
out.lines()
|
|
||||||
.filter(|&line| !line.contains("__imp_") && has_symbol(line, symbol_check_type))
|
|
||||||
.count()
|
|
||||||
== 1,
|
|
||||||
exists_once
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_symbol(line: &str, symbol_check_type: SymbolCheckType) -> bool {
|
fn has_symbol(name: &str, symbol_check_type: SymbolCheckType) -> bool {
|
||||||
if let SymbolCheckType::StrSymbol(expected) = symbol_check_type {
|
if let SymbolCheckType::StrSymbol(expected) = symbol_check_type {
|
||||||
line.contains(expected)
|
name.contains(expected)
|
||||||
} else {
|
} else {
|
||||||
let regex = regex::Regex::new(r#"_ZN.*h.*E\|_R[a-zA-Z0-9_]+"#).unwrap();
|
let regex = regex::Regex::new(r#"_ZN.*h.*E\|_R[a-zA-Z0-9_]+"#).unwrap();
|
||||||
regex.is_match(line)
|
regex.is_match(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
22
tests/rustdoc-js/self-is-not-generic.js
Normal file
22
tests/rustdoc-js/self-is-not-generic.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// exact-check
|
||||||
|
|
||||||
|
const EXPECTED = [
|
||||||
|
{
|
||||||
|
'query': 'A -> A',
|
||||||
|
'others': [
|
||||||
|
{ 'path': 'self_is_not_generic::Thing', 'name': 'from' }
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'query': 'A -> B',
|
||||||
|
'others': [
|
||||||
|
{ 'path': 'self_is_not_generic::Thing', 'name': 'try_from' }
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'query': 'Combine -> Combine',
|
||||||
|
'others': [
|
||||||
|
{ 'path': 'self_is_not_generic::Combine', 'name': 'combine' }
|
||||||
|
],
|
||||||
|
}
|
||||||
|
];
|
11
tests/rustdoc-js/self-is-not-generic.rs
Normal file
11
tests/rustdoc-js/self-is-not-generic.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
pub trait Combine {
|
||||||
|
fn combine(&self, other: &Self) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Thing;
|
||||||
|
|
||||||
|
impl Combine for Thing {
|
||||||
|
fn combine(&self, other: &Self) -> Self {
|
||||||
|
Self
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user