Perform most diagnostic lookups in resolution_failure
Previously, these were spread throughout the codebase. This had two drawbacks: 1. It caused the fast path to be slower: even if a link resolved, rustdoc would still perform various lookups for the error diagnostic. 2. It was inconsistent and didn't always give all diagnostics (https://github.com/rust-lang/rust/issues/76925) Now, diagnostics only perform expensive lookups in the error case. Additionally, the error handling is much more consistent, both in wording and behavior. - Remove `CannotHaveAssociatedItems`, `NotInScope`, `NoAssocItem`, and `NotAVariant` in favor of the more general `NotResolved` `resolution_failure` will now look up which of the four above categories is relevant, instead of requiring the rest of the code to be consistent and accurate in which it picked. - Remove unnecessary lookups throughout the intra-doc link pass. These are now done by `resolution_failure`. + Remove unnecessary `extra_fragment` argument to `variant_field()`; it was only used to do lookups on failure. + Remove various lookups related to associated items + Remove distinction between 'not in scope' and 'no associated item' - Don't perform unnecessary copies - Remove unused variables and code - Update tests - Note why looking at other namespaces is still necessary - 'has no inner item' -> 'contains no item' bless tests
This commit is contained in:
parent
cbc5e4d4d5
commit
dd7b8c85a6
9 changed files with 263 additions and 253 deletions
|
@ -60,14 +60,6 @@ impl<'a> From<ResolutionFailure<'a>> for ErrorKind<'a> {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum ResolutionFailure<'a> {
|
enum ResolutionFailure<'a> {
|
||||||
/// This resolved, but with the wrong namespace.
|
|
||||||
/// `Namespace` is the expected namespace (as opposed to the actual).
|
|
||||||
WrongNamespace(Res, Namespace),
|
|
||||||
/// This has a partial resolution, but is not in the TypeNS and so cannot
|
|
||||||
/// have associated items or fields.
|
|
||||||
CannotHaveAssociatedItems(Res, Namespace),
|
|
||||||
/// `name` is the base name of the path (not necessarily the whole link)
|
|
||||||
NotInScope { module_id: DefId, name: Cow<'a, str> },
|
|
||||||
/// this is a primitive type without an impls (no associated methods)
|
/// this is a primitive type without an impls (no associated methods)
|
||||||
/// when will this actually happen?
|
/// when will this actually happen?
|
||||||
/// the `Res` is the primitive it resolved to
|
/// the `Res` is the primitive it resolved to
|
||||||
|
@ -75,33 +67,19 @@ enum ResolutionFailure<'a> {
|
||||||
/// `[u8::not_found]`
|
/// `[u8::not_found]`
|
||||||
/// the `Res` is the primitive it resolved to
|
/// the `Res` is the primitive it resolved to
|
||||||
NoPrimitiveAssocItem { res: Res, prim_name: &'a str, assoc_item: Symbol },
|
NoPrimitiveAssocItem { res: Res, prim_name: &'a str, assoc_item: Symbol },
|
||||||
/// `[S::not_found]`
|
/// This resolved, but with the wrong namespace.
|
||||||
/// the `String` is the associated item that wasn't found
|
/// `Namespace` is the expected namespace (as opposed to the actual).
|
||||||
NoAssocItem(Res, Symbol),
|
WrongNamespace(Res, Namespace),
|
||||||
|
/// The link failed to resolve. `resolution_failure` should look to see if there's
|
||||||
|
/// a more helpful error that can be given.
|
||||||
|
NotResolved { module_id: DefId, partial_res: Option<Res>, unresolved: Cow<'a, str> },
|
||||||
/// should not ever happen
|
/// should not ever happen
|
||||||
NoParentItem,
|
NoParentItem,
|
||||||
/// this could be an enum variant, but the last path fragment wasn't resolved.
|
|
||||||
/// the `String` is the variant that didn't exist
|
|
||||||
NotAVariant(Res, Symbol),
|
|
||||||
/// used to communicate that this should be ignored, but shouldn't be reported to the user
|
/// used to communicate that this should be ignored, but shouldn't be reported to the user
|
||||||
Dummy,
|
Dummy,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResolutionFailure<'a> {
|
impl ResolutionFailure<'a> {
|
||||||
// A partial or full resolution
|
|
||||||
fn res(&self) -> Option<Res> {
|
|
||||||
use ResolutionFailure::*;
|
|
||||||
match self {
|
|
||||||
NoPrimitiveAssocItem { res, .. }
|
|
||||||
| NoAssocItem(res, _)
|
|
||||||
| NoPrimitiveImpl(res, _)
|
|
||||||
| NotAVariant(res, _)
|
|
||||||
| WrongNamespace(res, _)
|
|
||||||
| CannotHaveAssociatedItems(res, _) => Some(*res),
|
|
||||||
NotInScope { .. } | NoParentItem | Dummy => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This resolved fully (not just partially) but is erroneous for some other reason
|
// This resolved fully (not just partially) but is erroneous for some other reason
|
||||||
fn full_res(&self) -> Option<Res> {
|
fn full_res(&self) -> Option<Res> {
|
||||||
match self {
|
match self {
|
||||||
|
@ -136,22 +114,25 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
||||||
path_str: &'path str,
|
path_str: &'path str,
|
||||||
current_item: &Option<String>,
|
current_item: &Option<String>,
|
||||||
module_id: DefId,
|
module_id: DefId,
|
||||||
extra_fragment: &Option<String>,
|
|
||||||
) -> Result<(Res, Option<String>), ErrorKind<'path>> {
|
) -> Result<(Res, Option<String>), ErrorKind<'path>> {
|
||||||
let cx = self.cx;
|
let cx = self.cx;
|
||||||
|
let no_res = || ResolutionFailure::NotResolved {
|
||||||
|
module_id,
|
||||||
|
partial_res: None,
|
||||||
|
unresolved: path_str.into(),
|
||||||
|
};
|
||||||
|
|
||||||
debug!("looking for enum variant {}", path_str);
|
debug!("looking for enum variant {}", path_str);
|
||||||
let mut split = path_str.rsplitn(3, "::");
|
let mut split = path_str.rsplitn(3, "::");
|
||||||
let variant_field_name = split
|
let (variant_field_str, variant_field_name) = split
|
||||||
.next()
|
.next()
|
||||||
.map(|f| Symbol::intern(f))
|
.map(|f| (f, Symbol::intern(f)))
|
||||||
.expect("fold_item should ensure link is non-empty");
|
.expect("fold_item should ensure link is non-empty");
|
||||||
let variant_name =
|
let (variant_str, variant_name) =
|
||||||
// we're not sure this is a variant at all, so use the full string
|
// we're not sure this is a variant at all, so use the full string
|
||||||
split.next().map(|f| Symbol::intern(f)).ok_or_else(|| ResolutionFailure::NotInScope {
|
// If there's no second component, the link looks like `[path]`.
|
||||||
module_id,
|
// So there's no partial res and we should say the whole link failed to resolve.
|
||||||
name: path_str.into(),
|
split.next().map(|f| (f, Symbol::intern(f))).ok_or_else(no_res)?;
|
||||||
})?;
|
|
||||||
let path = split
|
let path = split
|
||||||
.next()
|
.next()
|
||||||
.map(|f| {
|
.map(|f| {
|
||||||
|
@ -162,10 +143,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
f.to_owned()
|
f.to_owned()
|
||||||
})
|
})
|
||||||
.ok_or_else(|| ResolutionFailure::NotInScope {
|
// If there's no third component, we saw `[a::b]` before and it failed to resolve.
|
||||||
module_id,
|
// So there's no partial res.
|
||||||
name: variant_name.to_string().into(),
|
.ok_or_else(no_res)?;
|
||||||
})?;
|
|
||||||
let ty_res = cx
|
let ty_res = cx
|
||||||
.enter_resolver(|resolver| {
|
.enter_resolver(|resolver| {
|
||||||
resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id)
|
resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id)
|
||||||
|
@ -173,7 +153,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
||||||
.map(|(_, res)| res)
|
.map(|(_, res)| res)
|
||||||
.unwrap_or(Res::Err);
|
.unwrap_or(Res::Err);
|
||||||
if let Res::Err = ty_res {
|
if let Res::Err = ty_res {
|
||||||
return Err(ResolutionFailure::NotInScope { module_id, name: path.into() }.into());
|
return Err(no_res().into());
|
||||||
}
|
}
|
||||||
let ty_res = ty_res.map_id(|_| panic!("unexpected node_id"));
|
let ty_res = ty_res.map_id(|_| panic!("unexpected node_id"));
|
||||||
match ty_res {
|
match ty_res {
|
||||||
|
@ -196,38 +176,27 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
||||||
ty_res,
|
ty_res,
|
||||||
Some(format!(
|
Some(format!(
|
||||||
"variant.{}.field.{}",
|
"variant.{}.field.{}",
|
||||||
variant_name, variant_field_name
|
variant_str, variant_field_name
|
||||||
)),
|
)),
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
Err(ResolutionFailure::NotAVariant(ty_res, variant_field_name).into())
|
Err(ResolutionFailure::NotResolved {
|
||||||
|
module_id,
|
||||||
|
partial_res: Some(Res::Def(DefKind::Enum, def.did)),
|
||||||
|
unresolved: variant_field_str.into(),
|
||||||
|
}
|
||||||
|
.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// `variant_field` looks at 3 different path segments in a row.
|
_ => Err(ResolutionFailure::NotResolved {
|
||||||
// But `NoAssocItem` assumes there are only 2. Check to see if there's
|
module_id,
|
||||||
// an intermediate segment that resolves.
|
partial_res: Some(ty_res),
|
||||||
_ => {
|
unresolved: variant_str.into(),
|
||||||
let intermediate_path = format!("{}::{}", path, variant_name);
|
|
||||||
// NOTE: we have to be careful here, because we're already in `resolve`.
|
|
||||||
// We know this doesn't recurse forever because we use a shorter path each time.
|
|
||||||
// NOTE: this uses `TypeNS` because nothing else has a valid path segment after
|
|
||||||
let kind = if let Some(intermediate) = self.check_full_res(
|
|
||||||
TypeNS,
|
|
||||||
&intermediate_path,
|
|
||||||
module_id,
|
|
||||||
current_item,
|
|
||||||
extra_fragment,
|
|
||||||
) {
|
|
||||||
ResolutionFailure::NoAssocItem(intermediate, variant_field_name)
|
|
||||||
} else {
|
|
||||||
// Even with the shorter path, it didn't resolve, so say that.
|
|
||||||
ResolutionFailure::NoAssocItem(ty_res, variant_name)
|
|
||||||
};
|
|
||||||
Err(kind.into())
|
|
||||||
}
|
}
|
||||||
|
.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,11 +217,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
||||||
false,
|
false,
|
||||||
) {
|
) {
|
||||||
if let SyntaxExtensionKind::LegacyBang { .. } = ext.kind {
|
if let SyntaxExtensionKind::LegacyBang { .. } = ext.kind {
|
||||||
return Some(Ok(res.map_id(|_| panic!("unexpected id"))));
|
return Ok(res.map_id(|_| panic!("unexpected id")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(res) = resolver.all_macros().get(&Symbol::intern(path_str)) {
|
if let Some(res) = resolver.all_macros().get(&Symbol::intern(path_str)) {
|
||||||
return Some(Ok(res.map_id(|_| panic!("unexpected id"))));
|
return Ok(res.map_id(|_| panic!("unexpected id")));
|
||||||
}
|
}
|
||||||
debug!("resolving {} as a macro in the module {:?}", path_str, module_id);
|
debug!("resolving {} as a macro in the module {:?}", path_str, module_id);
|
||||||
if let Ok((_, res)) =
|
if let Ok((_, res)) =
|
||||||
|
@ -261,28 +230,14 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
||||||
// don't resolve builtins like `#[derive]`
|
// don't resolve builtins like `#[derive]`
|
||||||
if let Res::Def(..) = res {
|
if let Res::Def(..) = res {
|
||||||
let res = res.map_id(|_| panic!("unexpected node_id"));
|
let res = res.map_id(|_| panic!("unexpected node_id"));
|
||||||
return Some(Ok(res));
|
return Ok(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
Err(ResolutionFailure::NotResolved {
|
||||||
})
|
module_id,
|
||||||
// This weird control flow is so we don't borrow the resolver more than once at a time
|
partial_res: None,
|
||||||
.unwrap_or_else(|| {
|
unresolved: path_str.into(),
|
||||||
let mut split = path_str.rsplitn(2, "::");
|
})
|
||||||
if let Some((parent, base)) = split.next().and_then(|x| Some((split.next()?, x))) {
|
|
||||||
if let Some(res) = self.check_full_res(TypeNS, parent, module_id, &None, &None) {
|
|
||||||
return Err(if matches!(res, Res::PrimTy(_)) {
|
|
||||||
ResolutionFailure::NoPrimitiveAssocItem {
|
|
||||||
res,
|
|
||||||
prim_name: parent,
|
|
||||||
assoc_item: Symbol::intern(base),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ResolutionFailure::NoAssocItem(res, Symbol::intern(base))
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(ResolutionFailure::NotInScope { module_id, name: path_str.into() })
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,7 +302,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
||||||
// Try looking for methods and associated items.
|
// Try looking for methods and associated items.
|
||||||
let mut split = path_str.rsplitn(2, "::");
|
let mut split = path_str.rsplitn(2, "::");
|
||||||
// this can be an `unwrap()` because we ensure the link is never empty
|
// this can be an `unwrap()` because we ensure the link is never empty
|
||||||
let item_name = Symbol::intern(split.next().unwrap());
|
let (item_str, item_name) = split.next().map(|i| (i, Symbol::intern(i))).unwrap();
|
||||||
let path_root = split
|
let path_root = split
|
||||||
.next()
|
.next()
|
||||||
.map(|f| {
|
.map(|f| {
|
||||||
|
@ -362,7 +317,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
||||||
// So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved.
|
// So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved.
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
debug!("found no `::`, assumming {} was correctly not in scope", item_name);
|
debug!("found no `::`, assumming {} was correctly not in scope", item_name);
|
||||||
ResolutionFailure::NotInScope { module_id, name: item_name.to_string().into() }
|
ResolutionFailure::NotResolved {
|
||||||
|
module_id,
|
||||||
|
partial_res: None,
|
||||||
|
unresolved: item_str.into(),
|
||||||
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
if let Some((path, prim)) = is_primitive(&path_root, TypeNS) {
|
if let Some((path, prim)) = is_primitive(&path_root, TypeNS) {
|
||||||
|
@ -383,7 +342,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
||||||
ty::AssocKind::Const => "associatedconstant",
|
ty::AssocKind::Const => "associatedconstant",
|
||||||
ty::AssocKind::Type => "associatedtype",
|
ty::AssocKind::Type => "associatedtype",
|
||||||
})
|
})
|
||||||
.map(|out| (prim, Some(format!("{}#{}.{}", path, out, item_name))));
|
.map(|out| (prim, Some(format!("{}#{}.{}", path, out, item_str))));
|
||||||
if let Some(link) = link {
|
if let Some(link) = link {
|
||||||
return Ok(link);
|
return Ok(link);
|
||||||
}
|
}
|
||||||
|
@ -411,25 +370,14 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
||||||
let ty_res = match ty_res {
|
let ty_res = match ty_res {
|
||||||
Err(()) | Ok(Res::Err) => {
|
Err(()) | Ok(Res::Err) => {
|
||||||
return if ns == Namespace::ValueNS {
|
return if ns == Namespace::ValueNS {
|
||||||
self.variant_field(path_str, current_item, module_id, extra_fragment)
|
self.variant_field(path_str, current_item, module_id)
|
||||||
} else {
|
} else {
|
||||||
// See if it only broke because of the namespace.
|
Err(ResolutionFailure::NotResolved {
|
||||||
let kind = cx.enter_resolver(|resolver| {
|
module_id,
|
||||||
// NOTE: this doesn't use `check_full_res` because we explicitly want to ignore `TypeNS` (we already checked it)
|
partial_res: None,
|
||||||
for &ns in &[MacroNS, ValueNS] {
|
unresolved: path_root.into(),
|
||||||
match resolver
|
}
|
||||||
.resolve_str_path_error(DUMMY_SP, &path_root, ns, module_id)
|
.into())
|
||||||
{
|
|
||||||
Ok((_, Res::Err)) | Err(()) => {}
|
|
||||||
Ok((_, res)) => {
|
|
||||||
let res = res.map_id(|_| panic!("unexpected node_id"));
|
|
||||||
return ResolutionFailure::CannotHaveAssociatedItems(res, ns);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ResolutionFailure::NotInScope { module_id, name: path_root.into() }
|
|
||||||
});
|
|
||||||
Err(kind.into())
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Ok(res) => res,
|
Ok(res) => res,
|
||||||
|
@ -479,7 +427,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
||||||
// but the disambiguator logic expects the associated item.
|
// but the disambiguator logic expects the associated item.
|
||||||
// Store the kind in a side channel so that only the disambiguator logic looks at it.
|
// Store the kind in a side channel so that only the disambiguator logic looks at it.
|
||||||
self.kind_side_channel.set(Some((kind.as_def_kind(), id)));
|
self.kind_side_channel.set(Some((kind.as_def_kind(), id)));
|
||||||
Ok((ty_res, Some(format!("{}.{}", out, item_name))))
|
Ok((ty_res, Some(format!("{}.{}", out, item_str))))
|
||||||
})
|
})
|
||||||
} else if ns == Namespace::ValueNS {
|
} else if ns == Namespace::ValueNS {
|
||||||
debug!("looking for variants or fields named {} for {:?}", item_name, did);
|
debug!("looking for variants or fields named {} for {:?}", item_name, did);
|
||||||
|
@ -522,7 +470,12 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// We already know this isn't in ValueNS, so no need to check variant_field
|
// We already know this isn't in ValueNS, so no need to check variant_field
|
||||||
return Err(ResolutionFailure::NoAssocItem(ty_res, item_name).into());
|
return Err(ResolutionFailure::NotResolved {
|
||||||
|
module_id,
|
||||||
|
partial_res: Some(ty_res),
|
||||||
|
unresolved: item_str.into(),
|
||||||
|
}
|
||||||
|
.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Res::Def(DefKind::Trait, did) => cx
|
Res::Def(DefKind::Trait, did) => cx
|
||||||
|
@ -546,16 +499,21 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
||||||
Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(ty_res)))
|
Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(ty_res)))
|
||||||
} else {
|
} else {
|
||||||
let res = Res::Def(item.kind.as_def_kind(), item.def_id);
|
let res = Res::Def(item.kind.as_def_kind(), item.def_id);
|
||||||
Ok((res, Some(format!("{}.{}", kind, item_name))))
|
Ok((res, Some(format!("{}.{}", kind, item_str))))
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
res.unwrap_or_else(|| {
|
res.unwrap_or_else(|| {
|
||||||
if ns == Namespace::ValueNS {
|
if ns == Namespace::ValueNS {
|
||||||
self.variant_field(path_str, current_item, module_id, extra_fragment)
|
self.variant_field(path_str, current_item, module_id)
|
||||||
} else {
|
} else {
|
||||||
Err(ResolutionFailure::NoAssocItem(ty_res, item_name).into())
|
Err(ResolutionFailure::NotResolved {
|
||||||
|
module_id,
|
||||||
|
partial_res: Some(ty_res),
|
||||||
|
unresolved: item_str.into(),
|
||||||
|
}
|
||||||
|
.into())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1133,6 +1091,8 @@ impl LinkCollector<'_, '_> {
|
||||||
// We only looked in one namespace. Try to give a better error if possible.
|
// We only looked in one namespace. Try to give a better error if possible.
|
||||||
if kind.full_res().is_none() {
|
if kind.full_res().is_none() {
|
||||||
let other_ns = if ns == ValueNS { TypeNS } else { ValueNS };
|
let other_ns = if ns == ValueNS { TypeNS } else { ValueNS };
|
||||||
|
// FIXME: really it should be `resolution_failure` that does this, not `resolve_with_disambiguator`
|
||||||
|
// See https://github.com/rust-lang/rust/pull/76955#discussion_r493953382 for a good approach
|
||||||
for &new_ns in &[other_ns, MacroNS] {
|
for &new_ns in &[other_ns, MacroNS] {
|
||||||
if let Some(res) = self.check_full_res(
|
if let Some(res) = self.check_full_res(
|
||||||
new_ns,
|
new_ns,
|
||||||
|
@ -1535,7 +1495,6 @@ fn resolution_failure(
|
||||||
dox,
|
dox,
|
||||||
&link_range,
|
&link_range,
|
||||||
|diag, sp| {
|
|diag, sp| {
|
||||||
let in_scope = kinds.iter().any(|kind| kind.res().is_some());
|
|
||||||
let item = |res: Res| {
|
let item = |res: Res| {
|
||||||
format!(
|
format!(
|
||||||
"the {} `{}`",
|
"the {} `{}`",
|
||||||
|
@ -1556,53 +1515,142 @@ fn resolution_failure(
|
||||||
// ignore duplicates
|
// ignore duplicates
|
||||||
let mut variants_seen = SmallVec::<[_; 3]>::new();
|
let mut variants_seen = SmallVec::<[_; 3]>::new();
|
||||||
for mut failure in kinds {
|
for mut failure in kinds {
|
||||||
// Check if _any_ parent of the path gets resolved.
|
|
||||||
// If so, report it and say the first which failed; if not, say the first path segment didn't resolve.
|
|
||||||
if let ResolutionFailure::NotInScope { module_id, name } = &mut failure {
|
|
||||||
let mut current = name.as_ref();
|
|
||||||
loop {
|
|
||||||
current = match current.rsplitn(2, "::").nth(1) {
|
|
||||||
Some(p) => p,
|
|
||||||
None => {
|
|
||||||
*name = current.to_owned().into();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if let Some(res) =
|
|
||||||
collector.check_full_res(TypeNS, ¤t, *module_id, &None, &None)
|
|
||||||
{
|
|
||||||
failure = ResolutionFailure::NoAssocItem(res, Symbol::intern(current));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let variant = std::mem::discriminant(&failure);
|
let variant = std::mem::discriminant(&failure);
|
||||||
if variants_seen.contains(&variant) {
|
if variants_seen.contains(&variant) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
variants_seen.push(variant);
|
variants_seen.push(variant);
|
||||||
let note = match failure {
|
|
||||||
ResolutionFailure::NotInScope { module_id, name, .. } => {
|
if let ResolutionFailure::NotResolved { module_id, partial_res, unresolved } =
|
||||||
if in_scope {
|
&mut failure
|
||||||
continue;
|
{
|
||||||
|
use DefKind::*;
|
||||||
|
|
||||||
|
let module_id = *module_id;
|
||||||
|
// FIXME(jynelson): this might conflict with my `Self` fix in #76467
|
||||||
|
fn split(path: &str) -> Option<(&str, &str)> {
|
||||||
|
let mut splitter = path.rsplitn(2, "::");
|
||||||
|
splitter.next().and_then(|right| splitter.next().map(|left| (left, right)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if _any_ parent of the path gets resolved.
|
||||||
|
// If so, report it and say the first which failed; if not, say the first path segment didn't resolve.
|
||||||
|
let mut name = path_str;
|
||||||
|
'outer: loop {
|
||||||
|
let (start, end) = if let Some(x) = split(name) {
|
||||||
|
x
|
||||||
|
} else {
|
||||||
|
// avoid bug that marked [Quux::Z] as missing Z, not Quux
|
||||||
|
if partial_res.is_none() {
|
||||||
|
*unresolved = name.into();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
name = start;
|
||||||
|
for &ns in &[TypeNS, ValueNS, MacroNS] {
|
||||||
|
if let Some(res) =
|
||||||
|
collector.check_full_res(ns, &start, module_id, &None, &None)
|
||||||
|
{
|
||||||
|
debug!("found partial_res={:?}", res);
|
||||||
|
*partial_res = Some(res);
|
||||||
|
*unresolved = end.into();
|
||||||
|
break 'outer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
*unresolved = end.into();
|
||||||
|
}
|
||||||
|
|
||||||
|
let last_found_module = match *partial_res {
|
||||||
|
Some(Res::Def(DefKind::Mod, id)) => Some(id),
|
||||||
|
None => Some(module_id),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
// See if this was a module: `[path]` or `[std::io::nope]`
|
||||||
|
if let Some(module) = last_found_module {
|
||||||
// NOTE: uses an explicit `continue` so the `note:` will come before the `help:`
|
// NOTE: uses an explicit `continue` so the `note:` will come before the `help:`
|
||||||
let module_name = collector.cx.tcx.item_name(module_id);
|
let module_name = collector.cx.tcx.item_name(module);
|
||||||
let note = format!("no item named `{}` in `{}`", name, module_name);
|
let note = format!(
|
||||||
|
"the module `{}` contains no item named `{}`",
|
||||||
|
module_name, unresolved
|
||||||
|
);
|
||||||
if let Some(span) = sp {
|
if let Some(span) = sp {
|
||||||
diag.span_label(span, ¬e);
|
diag.span_label(span, ¬e);
|
||||||
} else {
|
} else {
|
||||||
diag.note(¬e);
|
diag.note(¬e);
|
||||||
}
|
}
|
||||||
// If the link has `::` in the path, assume it's meant to be an intra-doc link
|
// If the link has `::` in it, assume it was meant to be an intra-doc link.
|
||||||
|
// Otherwise, the `[]` might be unrelated.
|
||||||
|
// FIXME: don't show this for autolinks (`<>`), `()` style links, or reference links
|
||||||
if !path_str.contains("::") {
|
if !path_str.contains("::") {
|
||||||
// Otherwise, the `[]` might be unrelated.
|
|
||||||
// FIXME(https://github.com/raphlinus/pulldown-cmark/issues/373):
|
|
||||||
// don't show this for autolinks (`<>`), `()` style links, or reference links
|
|
||||||
diag.help(r#"to escape `[` and `]` characters, add '\' before them like `\[` or `\]`"#);
|
diag.help(r#"to escape `[` and `]` characters, add '\' before them like `\[` or `\]`"#);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Otherwise, it must be an associated item or variant
|
||||||
|
let res = partial_res.expect("None case was handled by `last_found_module`");
|
||||||
|
let diagnostic_name;
|
||||||
|
let (kind, name) = match res {
|
||||||
|
Res::Def(kind, def_id) => {
|
||||||
|
diagnostic_name = collector.cx.tcx.item_name(def_id).as_str();
|
||||||
|
(Some(kind), &*diagnostic_name)
|
||||||
|
}
|
||||||
|
Res::PrimTy(_) => (None, name),
|
||||||
|
_ => unreachable!("only ADTs and primitives are in scope at module level"),
|
||||||
|
};
|
||||||
|
let path_description = if let Some(kind) = kind {
|
||||||
|
match kind {
|
||||||
|
Mod | ForeignMod => "inner item",
|
||||||
|
Struct => "field or associated item",
|
||||||
|
Enum | Union => "variant or associated item",
|
||||||
|
Variant
|
||||||
|
| Field
|
||||||
|
| Closure
|
||||||
|
| Generator
|
||||||
|
| AssocTy
|
||||||
|
| AssocConst
|
||||||
|
| AssocFn
|
||||||
|
| Fn
|
||||||
|
| Macro(_)
|
||||||
|
| Const
|
||||||
|
| ConstParam
|
||||||
|
| ExternCrate
|
||||||
|
| Use
|
||||||
|
| LifetimeParam
|
||||||
|
| Ctor(_, _)
|
||||||
|
| AnonConst => {
|
||||||
|
let note = assoc_item_not_allowed(res);
|
||||||
|
if let Some(span) = sp {
|
||||||
|
diag.span_label(span, ¬e);
|
||||||
|
} else {
|
||||||
|
diag.note(¬e);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Trait | TyAlias | ForeignTy | OpaqueTy | TraitAlias | TyParam
|
||||||
|
| Static => "associated item",
|
||||||
|
Impl | GlobalAsm => unreachable!("not a path"),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.descr()
|
||||||
|
};
|
||||||
|
let note = format!(
|
||||||
|
"the {} `{}` has no {} named `{}`",
|
||||||
|
res.descr(),
|
||||||
|
name,
|
||||||
|
disambiguator.map_or(path_description, |d| d.descr()),
|
||||||
|
unresolved,
|
||||||
|
);
|
||||||
|
if let Some(span) = sp {
|
||||||
|
diag.span_label(span, ¬e);
|
||||||
|
} else {
|
||||||
|
diag.note(¬e);
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let note = match failure {
|
||||||
|
ResolutionFailure::NotResolved { .. } => unreachable!("handled above"),
|
||||||
ResolutionFailure::Dummy => continue,
|
ResolutionFailure::Dummy => continue,
|
||||||
ResolutionFailure::WrongNamespace(res, expected_ns) => {
|
ResolutionFailure::WrongNamespace(res, expected_ns) => {
|
||||||
if let Res::Def(kind, _) = res {
|
if let Res::Def(kind, _) = res {
|
||||||
|
@ -1637,69 +1685,6 @@ fn resolution_failure(
|
||||||
prim_name, assoc_item
|
prim_name, assoc_item
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ResolutionFailure::NoAssocItem(res, assoc_item) => {
|
|
||||||
use DefKind::*;
|
|
||||||
|
|
||||||
let (kind, def_id) = match res {
|
|
||||||
Res::Def(kind, def_id) => (kind, def_id),
|
|
||||||
x => unreachable!(
|
|
||||||
"primitives are covered above and other `Res` variants aren't possible at module scope: {:?}",
|
|
||||||
x,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
let name = collector.cx.tcx.item_name(def_id);
|
|
||||||
let path_description = if let Some(disambiguator) = disambiguator {
|
|
||||||
disambiguator.descr()
|
|
||||||
} else {
|
|
||||||
match kind {
|
|
||||||
Mod | ForeignMod => "inner item",
|
|
||||||
Struct => "field or associated item",
|
|
||||||
Enum | Union => "variant or associated item",
|
|
||||||
Variant
|
|
||||||
| Field
|
|
||||||
| Closure
|
|
||||||
| Generator
|
|
||||||
| AssocTy
|
|
||||||
| AssocConst
|
|
||||||
| AssocFn
|
|
||||||
| Fn
|
|
||||||
| Macro(_)
|
|
||||||
| Const
|
|
||||||
| ConstParam
|
|
||||||
| ExternCrate
|
|
||||||
| Use
|
|
||||||
| LifetimeParam
|
|
||||||
| Ctor(_, _)
|
|
||||||
| AnonConst => {
|
|
||||||
let note = assoc_item_not_allowed(res);
|
|
||||||
if let Some(span) = sp {
|
|
||||||
diag.span_label(span, ¬e);
|
|
||||||
} else {
|
|
||||||
diag.note(¬e);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Trait | TyAlias | ForeignTy | OpaqueTy | TraitAlias | TyParam
|
|
||||||
| Static => "associated item",
|
|
||||||
Impl | GlobalAsm => unreachable!("not a path"),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
format!(
|
|
||||||
"the {} `{}` has no {} named `{}`",
|
|
||||||
res.descr(),
|
|
||||||
name,
|
|
||||||
path_description,
|
|
||||||
assoc_item
|
|
||||||
)
|
|
||||||
}
|
|
||||||
ResolutionFailure::CannotHaveAssociatedItems(res, _) => {
|
|
||||||
assoc_item_not_allowed(res)
|
|
||||||
}
|
|
||||||
ResolutionFailure::NotAVariant(res, variant) => format!(
|
|
||||||
"this link partially resolves to {}, but there is no variant named {}",
|
|
||||||
item(res),
|
|
||||||
variant
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
if let Some(span) = sp {
|
if let Some(span) = sp {
|
||||||
diag.span_label(span, ¬e);
|
diag.span_label(span, ¬e);
|
||||||
|
|
|
@ -2,7 +2,7 @@ error: unresolved link to `v2`
|
||||||
--> $DIR/deny-intra-link-resolution-failure.rs:3:6
|
--> $DIR/deny-intra-link-resolution-failure.rs:3:6
|
||||||
|
|
|
|
||||||
LL | /// [v2]
|
LL | /// [v2]
|
||||||
| ^^ no item named `v2` in `deny_intra_link_resolution_failure`
|
| ^^ the module `deny_intra_link_resolution_failure` contains no item named `v2`
|
||||||
|
|
|
|
||||||
note: the lint level is defined here
|
note: the lint level is defined here
|
||||||
--> $DIR/deny-intra-link-resolution-failure.rs:1:9
|
--> $DIR/deny-intra-link-resolution-failure.rs:1:9
|
||||||
|
|
|
@ -6,19 +6,23 @@
|
||||||
|
|
||||||
/// [path::to::nonexistent::module]
|
/// [path::to::nonexistent::module]
|
||||||
//~^ ERROR unresolved link
|
//~^ ERROR unresolved link
|
||||||
//~| NOTE no item named `path` in `intra_link_errors`
|
//~| NOTE `intra_link_errors` contains no item named `path`
|
||||||
|
|
||||||
/// [path::to::nonexistent::macro!]
|
/// [path::to::nonexistent::macro!]
|
||||||
//~^ ERROR unresolved link
|
//~^ ERROR unresolved link
|
||||||
//~| NOTE no item named `path` in `intra_link_errors`
|
//~| NOTE `intra_link_errors` contains no item named `path`
|
||||||
|
|
||||||
/// [type@path::to::nonexistent::type]
|
/// [type@path::to::nonexistent::type]
|
||||||
//~^ ERROR unresolved link
|
//~^ ERROR unresolved link
|
||||||
//~| NOTE no item named `path` in `intra_link_errors`
|
//~| NOTE `intra_link_errors` contains no item named `path`
|
||||||
|
|
||||||
/// [std::io::not::here]
|
/// [std::io::not::here]
|
||||||
//~^ ERROR unresolved link
|
//~^ ERROR unresolved link
|
||||||
//~| NOTE the module `io` has no inner item
|
//~| NOTE `io` contains no item named `not`
|
||||||
|
|
||||||
|
/// [type@std::io::not::here]
|
||||||
|
//~^ ERROR unresolved link
|
||||||
|
//~| NOTE `io` contains no item named `not`
|
||||||
|
|
||||||
/// [std::io::Error::x]
|
/// [std::io::Error::x]
|
||||||
//~^ ERROR unresolved link
|
//~^ ERROR unresolved link
|
||||||
|
@ -32,6 +36,10 @@
|
||||||
//~^ ERROR unresolved link
|
//~^ ERROR unresolved link
|
||||||
//~| NOTE `f` is a function, not a module
|
//~| NOTE `f` is a function, not a module
|
||||||
|
|
||||||
|
/// [f::A!]
|
||||||
|
//~^ ERROR unresolved link
|
||||||
|
//~| NOTE `f` is a function, not a module
|
||||||
|
|
||||||
/// [S::A]
|
/// [S::A]
|
||||||
//~^ ERROR unresolved link
|
//~^ ERROR unresolved link
|
||||||
//~| NOTE struct `S` has no field or associated item
|
//~| NOTE struct `S` has no field or associated item
|
||||||
|
|
|
@ -2,7 +2,7 @@ error: unresolved link to `path::to::nonexistent::module`
|
||||||
--> $DIR/intra-link-errors.rs:7:6
|
--> $DIR/intra-link-errors.rs:7:6
|
||||||
|
|
|
|
||||||
LL | /// [path::to::nonexistent::module]
|
LL | /// [path::to::nonexistent::module]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in `intra_link_errors`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the module `intra_link_errors` contains no item named `path`
|
||||||
|
|
|
|
||||||
note: the lint level is defined here
|
note: the lint level is defined here
|
||||||
--> $DIR/intra-link-errors.rs:1:9
|
--> $DIR/intra-link-errors.rs:1:9
|
||||||
|
@ -14,64 +14,79 @@ error: unresolved link to `path::to::nonexistent::macro`
|
||||||
--> $DIR/intra-link-errors.rs:11:6
|
--> $DIR/intra-link-errors.rs:11:6
|
||||||
|
|
|
|
||||||
LL | /// [path::to::nonexistent::macro!]
|
LL | /// [path::to::nonexistent::macro!]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in `intra_link_errors`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the module `intra_link_errors` contains no item named `path`
|
||||||
|
|
||||||
error: unresolved link to `path::to::nonexistent::type`
|
error: unresolved link to `path::to::nonexistent::type`
|
||||||
--> $DIR/intra-link-errors.rs:15:6
|
--> $DIR/intra-link-errors.rs:15:6
|
||||||
|
|
|
|
||||||
LL | /// [type@path::to::nonexistent::type]
|
LL | /// [type@path::to::nonexistent::type]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in `intra_link_errors`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the module `intra_link_errors` contains no item named `path`
|
||||||
|
|
||||||
error: unresolved link to `std::io::not::here`
|
error: unresolved link to `std::io::not::here`
|
||||||
--> $DIR/intra-link-errors.rs:19:6
|
--> $DIR/intra-link-errors.rs:19:6
|
||||||
|
|
|
|
||||||
LL | /// [std::io::not::here]
|
LL | /// [std::io::not::here]
|
||||||
| ^^^^^^^^^^^^^^^^^^ the module `io` has no inner item named `not`
|
| ^^^^^^^^^^^^^^^^^^ the module `io` contains no item named `not`
|
||||||
|
|
||||||
|
error: unresolved link to `std::io::not::here`
|
||||||
|
--> $DIR/intra-link-errors.rs:23:6
|
||||||
|
|
|
||||||
|
LL | /// [type@std::io::not::here]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^ the module `io` contains no item named `not`
|
||||||
|
|
||||||
error: unresolved link to `std::io::Error::x`
|
error: unresolved link to `std::io::Error::x`
|
||||||
--> $DIR/intra-link-errors.rs:23:6
|
--> $DIR/intra-link-errors.rs:27:6
|
||||||
|
|
|
|
||||||
LL | /// [std::io::Error::x]
|
LL | /// [std::io::Error::x]
|
||||||
| ^^^^^^^^^^^^^^^^^ the struct `Error` has no field or associated item named `x`
|
| ^^^^^^^^^^^^^^^^^ the struct `Error` has no field or associated item named `x`
|
||||||
|
|
||||||
error: unresolved link to `std::io::ErrorKind::x`
|
error: unresolved link to `std::io::ErrorKind::x`
|
||||||
--> $DIR/intra-link-errors.rs:27:6
|
--> $DIR/intra-link-errors.rs:31:6
|
||||||
|
|
|
|
||||||
LL | /// [std::io::ErrorKind::x]
|
LL | /// [std::io::ErrorKind::x]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^ the enum `ErrorKind` has no variant or associated item named `x`
|
| ^^^^^^^^^^^^^^^^^^^^^ the enum `ErrorKind` has no variant or associated item named `x`
|
||||||
|
|
||||||
error: unresolved link to `f::A`
|
error: unresolved link to `f::A`
|
||||||
--> $DIR/intra-link-errors.rs:31:6
|
--> $DIR/intra-link-errors.rs:35:6
|
||||||
|
|
|
|
||||||
LL | /// [f::A]
|
LL | /// [f::A]
|
||||||
| ^^^^ `f` is a function, not a module or type, and cannot have associated items
|
| ^^^^ `f` is a function, not a module or type, and cannot have associated items
|
||||||
|
|
||||||
|
error: unresolved link to `f::A`
|
||||||
|
--> $DIR/intra-link-errors.rs:39:6
|
||||||
|
|
|
||||||
|
LL | /// [f::A!]
|
||||||
|
| ^^^^^ `f` is a function, not a module or type, and cannot have associated items
|
||||||
|
|
||||||
error: unresolved link to `S::A`
|
error: unresolved link to `S::A`
|
||||||
--> $DIR/intra-link-errors.rs:35:6
|
--> $DIR/intra-link-errors.rs:43:6
|
||||||
|
|
|
|
||||||
LL | /// [S::A]
|
LL | /// [S::A]
|
||||||
| ^^^^ the struct `S` has no field or associated item named `A`
|
| ^^^^ the struct `S` has no field or associated item named `A`
|
||||||
|
|
||||||
error: unresolved link to `S::fmt`
|
error: unresolved link to `S::fmt`
|
||||||
--> $DIR/intra-link-errors.rs:39:6
|
--> $DIR/intra-link-errors.rs:47:6
|
||||||
|
|
|
|
||||||
LL | /// [S::fmt]
|
LL | /// [S::fmt]
|
||||||
| ^^^^^^ the struct `S` has no field or associated item named `fmt`
|
| ^^^^^^ the struct `S` has no field or associated item named `fmt`
|
||||||
|
|
||||||
error: unresolved link to `E::D`
|
error: unresolved link to `E::D`
|
||||||
--> $DIR/intra-link-errors.rs:43:6
|
--> $DIR/intra-link-errors.rs:51:6
|
||||||
|
|
|
|
||||||
LL | /// [E::D]
|
LL | /// [E::D]
|
||||||
| ^^^^ the enum `E` has no variant or associated item named `D`
|
| ^^^^ the enum `E` has no variant or associated item named `D`
|
||||||
|
|
||||||
error: unresolved link to `u8::not_found`
|
error: unresolved link to `u8::not_found`
|
||||||
--> $DIR/intra-link-errors.rs:47:6
|
--> $DIR/intra-link-errors.rs:55:6
|
||||||
|
|
|
|
||||||
LL | /// [u8::not_found]
|
LL | /// [u8::not_found]
|
||||||
| ^^^^^^^^^^^^^ the builtin type `u8` does not have an associated item named `not_found`
|
| ^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| the builtin type `u8` does not have an associated item named `not_found`
|
||||||
|
| the builtin type `u8` has no builtin type named `not_found`
|
||||||
|
|
||||||
error: unresolved link to `S`
|
error: unresolved link to `S`
|
||||||
--> $DIR/intra-link-errors.rs:51:6
|
--> $DIR/intra-link-errors.rs:59:6
|
||||||
|
|
|
|
||||||
LL | /// [S!]
|
LL | /// [S!]
|
||||||
| ^^
|
| ^^
|
||||||
|
@ -80,7 +95,7 @@ LL | /// [S!]
|
||||||
| help: to link to the struct, prefix with `struct@`: `struct@S`
|
| help: to link to the struct, prefix with `struct@`: `struct@S`
|
||||||
|
|
||||||
error: unresolved link to `T::g`
|
error: unresolved link to `T::g`
|
||||||
--> $DIR/intra-link-errors.rs:69:6
|
--> $DIR/intra-link-errors.rs:77:6
|
||||||
|
|
|
|
||||||
LL | /// [type@T::g]
|
LL | /// [type@T::g]
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
@ -89,13 +104,13 @@ LL | /// [type@T::g]
|
||||||
| help: to link to the associated function, add parentheses: `T::g()`
|
| help: to link to the associated function, add parentheses: `T::g()`
|
||||||
|
|
||||||
error: unresolved link to `T::h`
|
error: unresolved link to `T::h`
|
||||||
--> $DIR/intra-link-errors.rs:74:6
|
--> $DIR/intra-link-errors.rs:82:6
|
||||||
|
|
|
|
||||||
LL | /// [T::h!]
|
LL | /// [T::h!]
|
||||||
| ^^^^^ the trait `T` has no macro named `h`
|
| ^^^^^ the trait `T` has no macro named `h`
|
||||||
|
|
||||||
error: unresolved link to `S::h`
|
error: unresolved link to `S::h`
|
||||||
--> $DIR/intra-link-errors.rs:61:6
|
--> $DIR/intra-link-errors.rs:69:6
|
||||||
|
|
|
|
||||||
LL | /// [type@S::h]
|
LL | /// [type@S::h]
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
@ -104,7 +119,7 @@ LL | /// [type@S::h]
|
||||||
| help: to link to the associated function, add parentheses: `S::h()`
|
| help: to link to the associated function, add parentheses: `S::h()`
|
||||||
|
|
||||||
error: unresolved link to `m`
|
error: unresolved link to `m`
|
||||||
--> $DIR/intra-link-errors.rs:81:6
|
--> $DIR/intra-link-errors.rs:89:6
|
||||||
|
|
|
|
||||||
LL | /// [m()]
|
LL | /// [m()]
|
||||||
| ^^^
|
| ^^^
|
||||||
|
@ -112,5 +127,5 @@ LL | /// [m()]
|
||||||
| this link resolves to the macro `m`, which is not in the value namespace
|
| this link resolves to the macro `m`, which is not in the value namespace
|
||||||
| help: to link to the macro, add an exclamation mark: `m!`
|
| help: to link to the macro, add an exclamation mark: `m!`
|
||||||
|
|
||||||
error: aborting due to 16 previous errors
|
error: aborting due to 18 previous errors
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ error: unresolved link to `i`
|
||||||
--> $DIR/intra-link-span-ice-55723.rs:9:10
|
--> $DIR/intra-link-span-ice-55723.rs:9:10
|
||||||
|
|
|
|
||||||
LL | /// (arr[i])
|
LL | /// (arr[i])
|
||||||
| ^ no item named `i` in `intra_link_span_ice_55723`
|
| ^ the module `intra_link_span_ice_55723` contains no item named `i`
|
||||||
|
|
|
|
||||||
note: the lint level is defined here
|
note: the lint level is defined here
|
||||||
--> $DIR/intra-link-span-ice-55723.rs:1:9
|
--> $DIR/intra-link-span-ice-55723.rs:1:9
|
||||||
|
|
|
@ -2,7 +2,7 @@ warning: unresolved link to `error`
|
||||||
--> $DIR/intra-links-warning-crlf.rs:7:6
|
--> $DIR/intra-links-warning-crlf.rs:7:6
|
||||||
|
|
|
|
||||||
LL | /// [error]
|
LL | /// [error]
|
||||||
| ^^^^^ no item named `error` in `intra_links_warning_crlf`
|
| ^^^^^ the module `intra_links_warning_crlf` contains no item named `error`
|
||||||
|
|
|
|
||||||
= note: `#[warn(broken_intra_doc_links)]` on by default
|
= note: `#[warn(broken_intra_doc_links)]` on by default
|
||||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||||
|
@ -11,7 +11,7 @@ warning: unresolved link to `error1`
|
||||||
--> $DIR/intra-links-warning-crlf.rs:12:11
|
--> $DIR/intra-links-warning-crlf.rs:12:11
|
||||||
|
|
|
|
||||||
LL | /// docs [error1]
|
LL | /// docs [error1]
|
||||||
| ^^^^^^ no item named `error1` in `intra_links_warning_crlf`
|
| ^^^^^^ the module `intra_links_warning_crlf` contains no item named `error1`
|
||||||
|
|
|
|
||||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ warning: unresolved link to `error2`
|
||||||
--> $DIR/intra-links-warning-crlf.rs:15:11
|
--> $DIR/intra-links-warning-crlf.rs:15:11
|
||||||
|
|
|
|
||||||
LL | /// docs [error2]
|
LL | /// docs [error2]
|
||||||
| ^^^^^^ no item named `error2` in `intra_links_warning_crlf`
|
| ^^^^^^ the module `intra_links_warning_crlf` contains no item named `error2`
|
||||||
|
|
|
|
||||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ warning: unresolved link to `error`
|
||||||
--> $DIR/intra-links-warning-crlf.rs:23:20
|
--> $DIR/intra-links-warning-crlf.rs:23:20
|
||||||
|
|
|
|
||||||
LL | * It also has an [error].
|
LL | * It also has an [error].
|
||||||
| ^^^^^ no item named `error` in `intra_links_warning_crlf`
|
| ^^^^^ the module `intra_links_warning_crlf` contains no item named `error`
|
||||||
|
|
|
|
||||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||||
|
|
||||||
|
|
|
@ -10,37 +10,37 @@ warning: unresolved link to `Bar::foo`
|
||||||
--> $DIR/intra-links-warning.rs:3:35
|
--> $DIR/intra-links-warning.rs:3:35
|
||||||
|
|
|
|
||||||
LL | //! Test with [Foo::baz], [Bar::foo], ...
|
LL | //! Test with [Foo::baz], [Bar::foo], ...
|
||||||
| ^^^^^^^^ no item named `Bar` in `intra_links_warning`
|
| ^^^^^^^^ the module `intra_links_warning` contains no item named `Bar`
|
||||||
|
|
||||||
warning: unresolved link to `Uniooon::X`
|
warning: unresolved link to `Uniooon::X`
|
||||||
--> $DIR/intra-links-warning.rs:6:13
|
--> $DIR/intra-links-warning.rs:6:13
|
||||||
|
|
|
|
||||||
LL | //! , [Uniooon::X] and [Qux::Z].
|
LL | //! , [Uniooon::X] and [Qux::Z].
|
||||||
| ^^^^^^^^^^ no item named `Uniooon` in `intra_links_warning`
|
| ^^^^^^^^^^ the module `intra_links_warning` contains no item named `Uniooon`
|
||||||
|
|
||||||
warning: unresolved link to `Qux::Z`
|
warning: unresolved link to `Qux::Z`
|
||||||
--> $DIR/intra-links-warning.rs:6:30
|
--> $DIR/intra-links-warning.rs:6:30
|
||||||
|
|
|
|
||||||
LL | //! , [Uniooon::X] and [Qux::Z].
|
LL | //! , [Uniooon::X] and [Qux::Z].
|
||||||
| ^^^^^^ no item named `Qux` in `intra_links_warning`
|
| ^^^^^^ the module `intra_links_warning` contains no item named `Qux`
|
||||||
|
|
||||||
warning: unresolved link to `Uniooon::X`
|
warning: unresolved link to `Uniooon::X`
|
||||||
--> $DIR/intra-links-warning.rs:10:14
|
--> $DIR/intra-links-warning.rs:10:14
|
||||||
|
|
|
|
||||||
LL | //! , [Uniooon::X] and [Qux::Z].
|
LL | //! , [Uniooon::X] and [Qux::Z].
|
||||||
| ^^^^^^^^^^ no item named `Uniooon` in `intra_links_warning`
|
| ^^^^^^^^^^ the module `intra_links_warning` contains no item named `Uniooon`
|
||||||
|
|
||||||
warning: unresolved link to `Qux::Z`
|
warning: unresolved link to `Qux::Z`
|
||||||
--> $DIR/intra-links-warning.rs:10:31
|
--> $DIR/intra-links-warning.rs:10:31
|
||||||
|
|
|
|
||||||
LL | //! , [Uniooon::X] and [Qux::Z].
|
LL | //! , [Uniooon::X] and [Qux::Z].
|
||||||
| ^^^^^^ no item named `Qux` in `intra_links_warning`
|
| ^^^^^^ the module `intra_links_warning` contains no item named `Qux`
|
||||||
|
|
||||||
warning: unresolved link to `Qux:Y`
|
warning: unresolved link to `Qux:Y`
|
||||||
--> $DIR/intra-links-warning.rs:14:13
|
--> $DIR/intra-links-warning.rs:14:13
|
||||||
|
|
|
|
||||||
LL | /// [Qux:Y]
|
LL | /// [Qux:Y]
|
||||||
| ^^^^^ no item named `Qux:Y` in `intra_links_warning`
|
| ^^^^^ the module `intra_links_warning` contains no item named `Qux:Y`
|
||||||
|
|
|
|
||||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ warning: unresolved link to `error`
|
||||||
--> $DIR/intra-links-warning.rs:58:30
|
--> $DIR/intra-links-warning.rs:58:30
|
||||||
|
|
|
|
||||||
LL | * time to introduce a link [error]*/
|
LL | * time to introduce a link [error]*/
|
||||||
| ^^^^^ no item named `error` in `intra_links_warning`
|
| ^^^^^ the module `intra_links_warning` contains no item named `error`
|
||||||
|
|
|
|
||||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ warning: unresolved link to `error`
|
||||||
--> $DIR/intra-links-warning.rs:64:30
|
--> $DIR/intra-links-warning.rs:64:30
|
||||||
|
|
|
|
||||||
LL | * time to introduce a link [error]
|
LL | * time to introduce a link [error]
|
||||||
| ^^^^^ no item named `error` in `intra_links_warning`
|
| ^^^^^ the module `intra_links_warning` contains no item named `error`
|
||||||
|
|
|
|
||||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ LL | #[doc = "single line [error]"]
|
||||||
|
|
||||||
single line [error]
|
single line [error]
|
||||||
^^^^^
|
^^^^^
|
||||||
= note: no item named `error` in `intra_links_warning`
|
= note: the module `intra_links_warning` contains no item named `error`
|
||||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||||
|
|
||||||
warning: unresolved link to `error`
|
warning: unresolved link to `error`
|
||||||
|
@ -83,7 +83,7 @@ LL | #[doc = "single line with \"escaping\" [error]"]
|
||||||
|
|
||||||
single line with "escaping" [error]
|
single line with "escaping" [error]
|
||||||
^^^^^
|
^^^^^
|
||||||
= note: no item named `error` in `intra_links_warning`
|
= note: the module `intra_links_warning` contains no item named `error`
|
||||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||||
|
|
||||||
warning: unresolved link to `error`
|
warning: unresolved link to `error`
|
||||||
|
@ -98,14 +98,14 @@ LL | | /// [error]
|
||||||
|
|
||||||
[error]
|
[error]
|
||||||
^^^^^
|
^^^^^
|
||||||
= note: no item named `error` in `intra_links_warning`
|
= note: the module `intra_links_warning` contains no item named `error`
|
||||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||||
|
|
||||||
warning: unresolved link to `error1`
|
warning: unresolved link to `error1`
|
||||||
--> $DIR/intra-links-warning.rs:80:11
|
--> $DIR/intra-links-warning.rs:80:11
|
||||||
|
|
|
|
||||||
LL | /// docs [error1]
|
LL | /// docs [error1]
|
||||||
| ^^^^^^ no item named `error1` in `intra_links_warning`
|
| ^^^^^^ the module `intra_links_warning` contains no item named `error1`
|
||||||
|
|
|
|
||||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ warning: unresolved link to `error2`
|
||||||
--> $DIR/intra-links-warning.rs:82:11
|
--> $DIR/intra-links-warning.rs:82:11
|
||||||
|
|
|
|
||||||
LL | /// docs [error2]
|
LL | /// docs [error2]
|
||||||
| ^^^^^^ no item named `error2` in `intra_links_warning`
|
| ^^^^^^ the module `intra_links_warning` contains no item named `error2`
|
||||||
|
|
|
|
||||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||||
|
|
||||||
|
@ -121,7 +121,7 @@ warning: unresolved link to `BarA`
|
||||||
--> $DIR/intra-links-warning.rs:21:10
|
--> $DIR/intra-links-warning.rs:21:10
|
||||||
|
|
|
|
||||||
LL | /// bar [BarA] bar
|
LL | /// bar [BarA] bar
|
||||||
| ^^^^ no item named `BarA` in `intra_links_warning`
|
| ^^^^ the module `intra_links_warning` contains no item named `BarA`
|
||||||
|
|
|
|
||||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ warning: unresolved link to `BarB`
|
||||||
--> $DIR/intra-links-warning.rs:27:9
|
--> $DIR/intra-links-warning.rs:27:9
|
||||||
|
|
|
|
||||||
LL | * bar [BarB] bar
|
LL | * bar [BarB] bar
|
||||||
| ^^^^ no item named `BarB` in `intra_links_warning`
|
| ^^^^ the module `intra_links_warning` contains no item named `BarB`
|
||||||
|
|
|
|
||||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ warning: unresolved link to `BarC`
|
||||||
--> $DIR/intra-links-warning.rs:34:6
|
--> $DIR/intra-links-warning.rs:34:6
|
||||||
|
|
|
|
||||||
LL | bar [BarC] bar
|
LL | bar [BarC] bar
|
||||||
| ^^^^ no item named `BarC` in `intra_links_warning`
|
| ^^^^ the module `intra_links_warning` contains no item named `BarC`
|
||||||
|
|
|
|
||||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||||
|
|
||||||
|
@ -151,7 +151,7 @@ LL | #[doc = "Foo\nbar [BarD] bar\nbaz"]
|
||||||
|
|
||||||
bar [BarD] bar
|
bar [BarD] bar
|
||||||
^^^^
|
^^^^
|
||||||
= note: no item named `BarD` in `intra_links_warning`
|
= note: the module `intra_links_warning` contains no item named `BarD`
|
||||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||||
|
|
||||||
warning: unresolved link to `BarF`
|
warning: unresolved link to `BarF`
|
||||||
|
@ -167,7 +167,7 @@ LL | f!("Foo\nbar [BarF] bar\nbaz");
|
||||||
|
|
||||||
bar [BarF] bar
|
bar [BarF] bar
|
||||||
^^^^
|
^^^^
|
||||||
= note: no item named `BarF` in `intra_links_warning`
|
= note: the module `intra_links_warning` contains no item named `BarF`
|
||||||
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
|
||||||
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ error: unresolved link to `error`
|
||||||
--> $DIR/lint-group.rs:9:29
|
--> $DIR/lint-group.rs:9:29
|
||||||
|
|
|
|
||||||
LL | /// what up, let's make an [error]
|
LL | /// what up, let's make an [error]
|
||||||
| ^^^^^ no item named `error` in `lint_group`
|
| ^^^^^ the module `lint_group` contains no item named `error`
|
||||||
|
|
|
|
||||||
note: the lint level is defined here
|
note: the lint level is defined here
|
||||||
--> $DIR/lint-group.rs:7:9
|
--> $DIR/lint-group.rs:7:9
|
||||||
|
|
|
@ -3,8 +3,10 @@
|
||||||
|
|
||||||
/// [`std::collections::BTreeMap::into_iter`]
|
/// [`std::collections::BTreeMap::into_iter`]
|
||||||
/// [`String::from`] is ambiguous as to which `From` impl
|
/// [`String::from`] is ambiguous as to which `From` impl
|
||||||
|
/// [type@Vec::into_iter] uses a disambiguator
|
||||||
// @has 'intra_link_associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/collections/btree/map/struct.BTreeMap.html#method.into_iter"]' 'std::collections::BTreeMap::into_iter'
|
// @has 'intra_link_associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/collections/btree/map/struct.BTreeMap.html#method.into_iter"]' 'std::collections::BTreeMap::into_iter'
|
||||||
// @has 'intra_link_associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/string/struct.String.html#method.from"]' 'String::from'
|
// @has 'intra_link_associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/string/struct.String.html#method.from"]' 'String::from'
|
||||||
|
// @has 'intra_link_associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.into_iter"]' 'Vec::into_iter'
|
||||||
pub fn foo() {}
|
pub fn foo() {}
|
||||||
|
|
||||||
/// Link to [MyStruct], [link from struct][MyStruct::method], [MyStruct::clone], [MyStruct::Input]
|
/// Link to [MyStruct], [link from struct][MyStruct::method], [MyStruct::clone], [MyStruct::Input]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue