}
impl ResolutionFailure<'a> {
+ // A partial or full resolution
fn res(&self) -> Option<Res> {
use ResolutionFailure::*;
match self {
NotInScope(_) | NoParentItem | Dummy => None,
}
}
+
+ // This resolved fully (not just partially) but is erroneous for some other reason
+ fn full_res(&self) -> Option<Res> {
+ match self {
+ Self::WrongNamespace(res, _) => Some(*res),
+ _ => None,
+ }
+ }
}
enum AnchorFailure {
/// This is used to store the kind of associated items,
/// because `clean` and the disambiguator code expect them to be different.
/// See the code for associated items on inherent impls for details.
- kind_side_channel: Cell<Option<DefKind>>,
+ kind_side_channel: Cell<Option<(DefKind, DefId)>>,
}
impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
) -> Result<(Res, Option<String>), ErrorKind<'path>> {
let cx = self.cx;
+ debug!("looking for enum variant {}", path_str);
let mut split = path_str.rsplitn(3, "::");
let variant_field_name = split
.next()
debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns);
let result = match result {
Ok((_, Res::Err)) => Err(()),
- _ => result.map_err(|_| ()),
+ x => x,
};
if let Ok((_, res)) = result {
) => {
debug!("looking for associated item named {} for item {:?}", item_name, did);
// Checks if item_name belongs to `impl SomeItem`
- let kind = cx
+ let assoc_item = cx
.tcx
.inherent_impls(did)
.iter()
imp,
)
})
- .map(|item| item.kind)
+ .map(|item| (item.kind, item.def_id))
// There should only ever be one associated item that matches from any inherent impl
.next()
// Check if item_name belongs to `impl SomeTrait for SomeItem`
kind
});
- if let Some(kind) = kind {
+ if let Some((kind, id)) = assoc_item {
let out = match kind {
ty::AssocKind::Fn => "method",
ty::AssocKind::Const => "associatedconstant",
// HACK(jynelson): `clean` expects the type, not 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.
- self.kind_side_channel.set(Some(kind.as_def_kind()));
+ self.kind_side_channel.set(Some((kind.as_def_kind(), id)));
Ok((ty_res, Some(format!("{}.{}", out, item_name))))
})
} else if ns == Namespace::ValueNS {
+ debug!("looking for variants or fields named {} for {:?}", item_name, did);
match cx.tcx.type_of(did).kind() {
ty::Adt(def, _) => {
let field = if def.is_enum() {
item_name: Symbol,
ns: Namespace,
cx: &DocContext<'_>,
-) -> Option<ty::AssocKind> {
+) -> Option<(ty::AssocKind, DefId)> {
let ty = cx.tcx.type_of(did);
// First consider automatic impls: `impl From<T> for T`
let implicit_impls = crate::clean::get_auto_trait_and_blanket_impls(cx, ty, did);
// but provided methods come directly from `tcx`.
// Fortunately, we don't need the whole method, we just need to know
// what kind of associated item it is.
- Some((assoc.def_id, kind))
+ Some((kind, assoc.def_id))
});
let assoc = items.next();
debug_assert_eq!(items.count(), 0);
ns,
trait_,
)
- .map(|assoc| (assoc.def_id, assoc.kind))
+ .map(|assoc| (assoc.kind, assoc.def_id))
}
}
_ => panic!("get_impls returned something that wasn't an impl"),
cx.tcx
.associated_items(trait_)
.find_by_name_and_namespace(cx.tcx, Ident::with_dummy_span(item_name), ns, trait_)
- .map(|assoc| (assoc.def_id, assoc.kind))
+ .map(|assoc| (assoc.kind, assoc.def_id))
}));
}
// FIXME: warn about ambiguity
debug!("the candidates were {:?}", candidates);
- candidates.pop().map(|(_, kind)| kind)
+ candidates.pop()
}
/// Given a type, return all traits in scope in `module` implemented by that type.
}
}
+ // used for reporting better errors
+ let check_full_res = |this: &mut Self, ns| {
+ let res =
+ match this.resolve(path_str, ns, ¤t_item, base_node, &extra_fragment)
+ {
+ Ok(res) => {
+ debug!(
+ "check_full_res: saw res for {} in {:?} ns: {:?}",
+ path_str, ns, res.0
+ );
+ Some(res.0)
+ }
+ Err(ErrorKind::Resolve(kind)) => kind.full_res(),
+ // TODO: add `Res` to AnchorFailure
+ Err(ErrorKind::AnchorFailure(_)) => None,
+ };
+ this.kind_side_channel.take().map(|(kind, id)| Res::Def(kind, id)).or(res)
+ };
+
match disambiguator.map(Disambiguator::ns) {
Some(ns @ (ValueNS | TypeNS)) => {
match self.resolve(path_str, ns, ¤t_item, base_node, &extra_fragment)
{
Ok(res) => res,
- Err(ErrorKind::Resolve(kind)) => {
+ Err(ErrorKind::Resolve(mut kind)) => {
+ // We only looked in one namespace. Try to give a better error if possible.
+ // TODO: handle MacroNS too
+ if kind.full_res().is_none() {
+ let other_ns = if ns == ValueNS { TypeNS } else { ValueNS };
+ if let Some(res) = check_full_res(self, other_ns) {
+ // recall that this stores the _expected_ namespace
+ kind = ResolutionFailure::WrongNamespace(res, ns);
+ }
+ }
resolution_failure(
cx,
&item,
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] {
- match self.resolve(
- path_str,
- ns,
- ¤t_item,
- base_node,
- &extra_fragment,
- ) {
- Ok(res) => {
- kind = ResolutionFailure::WrongNamespace(res.0, MacroNS)
- }
- // This will show up in the other namespace, no need to handle it here
- Err(ErrorKind::Resolve(
- ResolutionFailure::WrongNamespace(..),
- )) => {}
- Err(ErrorKind::AnchorFailure(_)) => {}
- Err(ErrorKind::Resolve(inner_kind)) => {
- if let Some(res) = inner_kind.res() {
- kind =
- ResolutionFailure::WrongNamespace(res, MacroNS);
- }
- }
+ if let Some(res) = check_full_res(self, ns) {
+ kind = ResolutionFailure::WrongNamespace(res, MacroNS);
+ break;
}
}
+ //}
resolution_failure(
cx,
&item,
// Disallow e.g. linking to enums with `struct@`
if let Res::Def(kind, _) = res {
debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator);
- match (self.kind_side_channel.take().unwrap_or(kind), disambiguator) {
+ match (self.kind_side_channel.take().map(|(kind, _)| kind).unwrap_or(kind), disambiguator) {
| (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const)))
// NOTE: this allows 'method' to mean both normal functions and associated functions
// This can't cause ambiguity because both are in the same namespace.