Don't give misleading errors for f::A, where f is in the value namespace

This commit is contained in:
Joshua Nelson 2020-08-21 00:23:23 -04:00
parent f4e6ebd11a
commit 002d3a922c
3 changed files with 54 additions and 20 deletions

View file

@ -57,6 +57,9 @@ 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),
/// `String` is the base name of the path (not necessarily the whole link)
NotInScope(Cow<'a, str>),
/// this is a primitive type without an impls (no associated methods)
@ -90,7 +93,8 @@ impl ResolutionFailure<'a> {
| NoPrimitiveImpl(res, _)
| NotAnEnum(res)
| NotAVariant(res, _)
| WrongNamespace(res, _) => Some(*res),
| WrongNamespace(res, _)
| CannotHaveAssociatedItems(res, _) => Some(*res),
NotInScope(_) | NoParentItem | Dummy => None,
}
}
@ -360,21 +364,39 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
}));
}
let (_, ty_res) = cx
let ty_res = cx
.enter_resolver(|resolver| {
// only types can have associated items
resolver.resolve_str_path_error(DUMMY_SP, &path_root, TypeNS, module_id)
})
.map_err(|_| {
ErrorKind::Resolve(ResolutionFailure::NotInScope(path_root.clone().into()))
})?;
if let Res::Err = ty_res {
return if ns == Namespace::ValueNS {
self.variant_field(path_str, current_item, module_id)
} else {
Err(ErrorKind::Resolve(ResolutionFailure::NotInScope(path_root.into())))
};
}
.map(|(_, res)| res);
let ty_res = match ty_res {
Err(()) | Ok(Res::Err) => {
return if ns == Namespace::ValueNS {
self.variant_field(path_str, current_item, module_id)
} else {
// See if it only broke because of the namespace.
let kind = cx.enter_resolver(|resolver| {
for &ns in &[MacroNS, ValueNS] {
match resolver
.resolve_str_path_error(DUMMY_SP, &path_root, ns, module_id)
{
Ok((_, Res::Err)) | Err(()) => {}
Ok((_, res)) => {
let res = res.map_id(|_| panic!("unexpected node_id"));
return ResolutionFailure::CannotHaveAssociatedItems(
res, ns,
);
}
}
}
ResolutionFailure::NotInScope(path_root.into())
});
Err(ErrorKind::Resolve(kind))
};
}
Ok(res) => res,
};
let ty_res = ty_res.map_id(|_| panic!("unexpected node_id"));
let res = match ty_res {
Res::Def(
@ -1006,14 +1028,12 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
Ok(res) => (res, extra_fragment),
Err(mut kind) => {
// `macro_resolve` only looks in the macro namespace. Try to give a better error if possible.
//if kind.res().is_none() {
for &ns in &[TypeNS, ValueNS] {
if let Some(res) = check_full_res(self, ns) {
kind = ResolutionFailure::WrongNamespace(res, MacroNS);
break;
}
}
//}
resolution_failure(
cx,
&item,
@ -1456,6 +1476,20 @@ fn resolution_failure(
diag.note(&note);
}
}
ResolutionFailure::CannotHaveAssociatedItems(res, _) => {
let (item, _) = item(res);
diag.note(&format!("this link partially resolves to {}", item));
if let Res::Def(kind, def_id) = res {
let name = cx.tcx.item_name(def_id);
let note = format!(
"`{}` is {} {}, not a module or type, and cannot have associated items",
name,
kind.article(),
kind.descr(def_id)
);
diag.note(&note);
}
}
// TODO: is there ever a case where this happens?
ResolutionFailure::NotAnEnum(res) => {
let (item, comma) = item(res);

View file

@ -7,14 +7,14 @@
// FIXME: this could say which path was the first to not be found (in this case, `path`)
/// [path::to::nonexistent::module]
//~^ ERROR unresolved link
//~| NOTE no item named `path::to::nonexistent` is in scope
//~| NOTE no item named `path::to` is in scope
//~| HELP to escape
// TODO: why does this say `f` and not `f::A`??
/// [f::A]
//~^ ERROR unresolved link
//~| NOTE no item named `f` is in scope
//~| HELP to escape
//~| NOTE this link partially resolves
//~| NOTE `f` is a function, not a module
/// [S::A]
//~^ ERROR unresolved link

View file

@ -9,7 +9,7 @@ note: the lint level is defined here
|
LL | #![deny(broken_intra_doc_links)]
| ^^^^^^^^^^^^^^^^^^^^^^
= note: no item named `path::to::nonexistent` is in scope
= note: no item named `path::to` is in scope
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
error: unresolved link to `f::A`
@ -18,8 +18,8 @@ error: unresolved link to `f::A`
LL | /// [f::A]
| ^^^^
|
= note: no item named `f` is in scope
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
= note: this link partially resolves to the function `f`
= note: `f` is a function, not a module or type, and cannot have associated items
error: unresolved link to `S::A`
--> $DIR/intra-link-errors.rs:19:6