Skip to content

Commit d1b781b

Browse files
committed
[very broken] Fixup resolve() in late pass
mentioning rust-lang#83761
1 parent f727dca commit d1b781b

File tree

3 files changed

+59
-129
lines changed

3 files changed

+59
-129
lines changed

src/librustdoc/passes/collect_intra_doc_links.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,14 @@ crate enum EarlyResult {
7777
crate struct UnresolvedLink {
7878
/// The resolution for all path segments excluding the last.
7979
///
80-
/// For example, in `[a::b::c]`, it will hold the Res for `a::b`.
80+
/// For example, in `[a::b::c]`, it will hold the Res for `a::b` and the `Symbol` for `c`.
8181
/// This is used for `resolve_associated_item`.
82-
ty_res: Option<Res>,
82+
ty_res: Option<(Res, Symbol)>,
8383
/// The resolution for all path segments excluding the last two.
8484
///
85-
/// For example, in `[a::b::c]`, it will hold the Res for `a`.
85+
/// For example, in `[a::b::c]`, it will hold the Res for `a`, and the `Symbol`s for `b` and `c`.
8686
/// This is used for `variant_field`.
87-
variant_res: Option<Res>,
87+
variant_res: Option<(Res, Symbol, Symbol)>,
8888
/* TODO */
8989
}
9090

src/librustdoc/passes/collect_intra_doc_links/early.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ impl IntraLinkCrateLoader {
110110
// error instead and special case *only* modules with `#[doc(primitive)]`, not all
111111
// primitives.
112112
let ty_res = resolve_primitive(&path_root, TypeNS)
113-
.or_else(|| self.resolve_path(&path_root, TypeNS, module_id));
113+
.or_else(|| self.resolve_path(&path_root, TypeNS, module_id))
114+
.map(|res| (res, item_name));
114115
let variant_res = if ns == Namespace::ValueNS {
115116
self.variant_res(path_str, module_id)
116117
} else {
@@ -121,7 +122,7 @@ impl IntraLinkCrateLoader {
121122
})
122123
}
123124

124-
fn variant_res(&self, path_str: &str, module_id: DefId) -> Option<Res> {
125+
fn variant_res(&self, path_str: &str, module_id: DefId) -> Option<(Res, Symbol, Symbol)> {
125126
debug!("looking for enum variant {}", path_str);
126127
let mut split = path_str.rsplitn(3, "::");
127128
let (variant_field_str, variant_field_name) = split
@@ -131,15 +132,15 @@ impl IntraLinkCrateLoader {
131132
// we're not sure this is a variant at all, so use the full string
132133
// If there's no second component, the link looks like `[path]`.
133134
// So there's no partial res and we should say the whole link failed to resolve.
134-
let variant_str = split.next()?;
135-
let variant_name = Symbol::intern(variant_str);
135+
let variant_name = Symbol::intern(split.next()?);
136136
let path = split.next()?.to_owned();
137-
self
137+
let variant_res = self
138138
.enter_resolver(|resolver| {
139139
resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id)
140140
})
141141
.and_then(|(_, res)| res.try_into())
142-
.ok()
142+
.ok()?;
143+
Some((variant_res, variant_name, variant_field_name))
143144
}
144145
}
145146

src/librustdoc/passes/collect_intra_doc_links/late.rs

Lines changed: 48 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -34,42 +34,12 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
3434
/// [enum struct variant]: hir::VariantData::Struct
3535
fn variant_field(
3636
&self,
37-
path_str: &'path str,
38-
module_id: DefId,
39-
) -> Result<(Res, Option<String>), ErrorKind<'path>> {
37+
(variant_res, variant_name, variant_field_name): (Res, Symbol, Symbol),
38+
module_id: DefId,
39+
) -> Result<(Res, String), ErrorKind<'path>> {
4040
let tcx = self.cx.tcx;
41-
let no_res = || ResolutionFailure::NotResolved {
42-
module_id,
43-
partial_res: None,
44-
unresolved: path_str.into(),
45-
};
4641

47-
debug!("looking for enum variant {}", path_str);
48-
let mut split = path_str.rsplitn(3, "::");
49-
let (variant_field_str, variant_field_name) = split
50-
.next()
51-
.map(|f| (f, Symbol::intern(f)))
52-
.expect("fold_item should ensure link is non-empty");
53-
let (variant_str, variant_name) =
54-
// we're not sure this is a variant at all, so use the full string
55-
// If there's no second component, the link looks like `[path]`.
56-
// So there's no partial res and we should say the whole link failed to resolve.
57-
split.next().map(|f| (f, Symbol::intern(f))).ok_or_else(no_res)?;
58-
let path = split
59-
.next()
60-
.map(|f| f.to_owned())
61-
// If there's no third component, we saw `[a::b]` before and it failed to resolve.
62-
// So there's no partial res.
63-
.ok_or_else(no_res)?;
64-
let ty_res = self
65-
.cx
66-
.enter_resolver(|resolver| {
67-
resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id)
68-
})
69-
.and_then(|(_, res)| res.try_into())
70-
.map_err(|()| no_res())?;
71-
72-
match ty_res {
42+
match variant_res {
7343
Res::Def(DefKind::Enum, did) => {
7444
if tcx
7545
.inherent_impls(did)
@@ -85,17 +55,17 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
8555
ty::Adt(def, _) if def.is_enum() => {
8656
if def.all_fields().any(|item| item.ident.name == variant_field_name) {
8757
Ok((
88-
ty_res,
89-
Some(format!(
58+
variant_res,
59+
format!(
9060
"variant.{}.field.{}",
91-
variant_str, variant_field_name
92-
)),
61+
variant_name, variant_field_name
62+
),
9363
))
9464
} else {
9565
Err(ResolutionFailure::NotResolved {
9666
module_id,
9767
partial_res: Some(Res::Def(DefKind::Enum, def.did)),
98-
unresolved: variant_field_str.into(),
68+
unresolved: variant_field_name.into(),
9969
}
10070
.into())
10171
}
@@ -105,8 +75,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
10575
}
10676
_ => Err(ResolutionFailure::NotResolved {
10777
module_id,
108-
partial_res: Some(ty_res),
109-
unresolved: variant_str.into(),
78+
partial_res: Some(variant_res),
79+
unresolved: variant_name.into(),
11080
}
11181
.into()),
11282
}
@@ -183,88 +153,47 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
183153
/// optional URL fragment in the case of variants and methods.
184154
fn resolve<'path>(
185155
&mut self,
186-
path_str: &'path str,
156+
early_result: EarlyResult,
157+
path_str: &'path str,
187158
ns: Namespace,
188159
module_id: DefId,
189160
extra_fragment: &Option<String>,
190161
) -> Result<(Res, Option<String>), ErrorKind<'path>> {
191-
if let Some(res) = self.resolve_path(path_str, ns, module_id) {
192-
match res {
193-
// FIXME(#76467): make this fallthrough to lookup the associated
194-
// item a separate function.
195-
Res::Def(DefKind::AssocFn | DefKind::AssocConst, _) => assert_eq!(ns, ValueNS),
196-
Res::Def(DefKind::AssocTy, _) => assert_eq!(ns, TypeNS),
197-
Res::Def(DefKind::Variant, _) => {
198-
return handle_variant(self.cx, res, extra_fragment);
199-
}
200-
// Not a trait item; just return what we found.
201-
Res::Primitive(ty) => {
202-
if extra_fragment.is_some() {
203-
return Err(ErrorKind::AnchorFailure(
204-
AnchorFailure::RustdocAnchorConflict(res),
205-
));
206-
}
207-
return Ok((res, Some(ty.as_str().to_owned())));
208-
}
209-
_ => return Ok((res, extra_fragment.clone())),
210-
}
211-
}
212-
213-
// Try looking for methods and associated items.
214-
let mut split = path_str.rsplitn(2, "::");
215-
// NB: `split`'s first element is always defined, even if the delimiter was not present.
216-
// NB: `item_str` could be empty when resolving in the root namespace (e.g. `::std`).
217-
let item_str = split.next().unwrap();
218-
let item_name = Symbol::intern(item_str);
219-
let path_root = split
220-
.next()
221-
.map(|f| f.to_owned())
222-
// If there's no `::`, it's not an associated item.
223-
// So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved.
224-
.ok_or_else(|| {
225-
debug!("found no `::`, assumming {} was correctly not in scope", item_name);
226-
ResolutionFailure::NotResolved {
227-
module_id,
228-
partial_res: None,
229-
unresolved: item_str.into(),
230-
}
231-
})?;
232-
233-
// FIXME(#83862): this arbitrarily gives precedence to primitives over modules to support
234-
// links to primitives when `#[doc(primitive)]` is present. It should give an ambiguity
235-
// error instead and special case *only* modules with `#[doc(primitive)]`, not all
236-
// primitives.
237-
resolve_primitive(&path_root, TypeNS)
238-
.or_else(|| self.resolve_path(&path_root, TypeNS, module_id))
239-
.and_then(|ty_res| {
240-
let (res, fragment, side_channel) =
241-
self.resolve_associated_item(ty_res, item_name, ns, module_id)?;
242-
let result = if extra_fragment.is_some() {
243-
let diag_res = side_channel.map_or(res, |(k, r)| Res::Def(k, r));
244-
Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(diag_res)))
245-
} else {
246-
// HACK(jynelson): `clean` expects the type, not the associated item
247-
// but the disambiguator logic expects the associated item.
248-
// Store the kind in a side channel so that only the disambiguator logic looks at it.
249-
if let Some((kind, id)) = side_channel {
250-
self.kind_side_channel.set(Some((kind, id)));
251-
}
252-
Ok((res, Some(fragment)))
253-
};
254-
Some(result)
255-
})
256-
.unwrap_or_else(|| {
257-
if ns == Namespace::ValueNS {
258-
self.variant_field(path_str, module_id)
259-
} else {
260-
Err(ResolutionFailure::NotResolved {
261-
module_id,
262-
partial_res: None,
263-
unresolved: path_root.into(),
264-
}
265-
.into())
266-
}
267-
})
162+
use EarlyResult::*;
163+
let link = match early_result {
164+
// easy cases
165+
Resolved(res, fragment) => return Ok((res, fragment)),
166+
Error(err) => return Err(err),
167+
// the actual work
168+
UnresolvedVariant(res) => return handle_variant(self.cx, res, extra_fragment),
169+
Unresolved(link) => link,
170+
};
171+
172+
if let Some((res, fragment, side_channel)) = link.ty_res.and_then(|(ty_res, item_name)| {
173+
self.resolve_associated_item(ty_res, item_name, ns, module_id)
174+
}) {
175+
if extra_fragment.is_some() {
176+
let diag_res = side_channel.map_or(res, |(k, r)| Res::Def(k, r));
177+
Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(diag_res)))
178+
} else {
179+
// HACK(jynelson): `clean` expects the type, not the associated item
180+
// but the disambiguator logic expects the associated item.
181+
// Store the kind in a side channel so that only the disambiguator logic looks at it.
182+
if let Some((kind, id)) = side_channel {
183+
self.kind_side_channel.set(Some((kind, id)));
184+
}
185+
Ok((res, Some(fragment)))
186+
}
187+
} else if let Some(variant_res) = link.variant_res {
188+
debug_assert_eq!(ns, ValueNS);
189+
self.variant_field(variant_res, module_id).map(|(res, fragment)| (res, Some(fragment)))
190+
} else {
191+
Err(ResolutionFailure::NotResolved {
192+
module_id,
193+
partial_res: None,
194+
unresolved: path_str.into(),
195+
}.into())
196+
}
268197
}
269198

270199
/// Returns:

0 commit comments

Comments
 (0)