Skip to content

Commit c23f045

Browse files
authored
Rollup merge of #73566 - jyn514:name-resolve-first, r=eddyb
Don't run `everybody_loops` for rustdoc; instead ignore resolution errors r? @eddyb cc @petrochenkov, @GuillaumeGomez, @Manishearth, @ecstatic-morse, @marmeladema ~~Blocked on #73743 Merged. ~~Blocked on crater run.~~ Crater popped up some ICEs ([now fixed](#73566 (comment))). See [crater run](https://crater-reports.s3.amazonaws.com/pr-73566/index.html), [ICEs](#73566 (comment)). ~~Blocked on #74070 so that we don't make typeck_tables_of public when it shouldn't be.~~ Merged. Closes #71820, closes #71104, closes #65863. ## What is the motivation for this change? As seen from a lengthy trail of PRs and issues (#73532, #73103, #71820, #71104), `everybody_loops` is causing bugs in rustdoc. The main issue is that it does not preserve the validity of the `DefId` tree, meaning that operations on DefIds may unexpectedly fail when called later. This is blocking intra-doc links (see #73101). This PR starts by removing `everybody_loops`, fixing #71104 and #71820. However, that brings back the bugs seen originally in #43348: Since libstd documents items for all platforms, the function bodies sometimes do not type check. Here are the errors from documenting `libstd` with `everybody_loops` disabled and no other changes: ```rust error[E0433]: failed to resolve: could not find `handle` in `sys` --> src/libstd/sys/windows/ext/process.rs:13:27 | 13 | let handle = sys::handle::Handle::new(handle as *mut _); | ^^^^^^ could not find `handle` in `sys` error[E0425]: cannot find function `symlink_inner` in module `sys::fs` --> src/libstd/sys/windows/ext/fs.rs:544:14 | 544 | sys::fs::symlink_inner(src.as_ref(), dst.as_ref(), false) | ^^^^^^^^^^^^^ not found in `sys::fs` error[E0425]: cannot find function `symlink_inner` in module `sys::fs` --> src/libstd/sys/windows/ext/fs.rs:564:14 | 564 | sys::fs::symlink_inner(src.as_ref(), dst.as_ref(), true) | ^^^^^^^^^^^^^ not found in `sys::fs` ``` ## Why does this need changes to `rustc_resolve`? Normally, this could be avoided by simply not calling the `typeck_item_bodies` pass. However, the errors above happen before type checking, in name resolution itself. Since name resolution is intermingled with macro expansion, and rustdoc needs expansion to happen before it knows all items to be documented, there needs to be someway to ignore _resolution_ errors in function bodies. An alternative solution suggested by @petrochenkov was to not run `everybody_loops` on anything containing a nested `DefId`. This would solve some of the immediate issues, but isn't bullet-proof: the following functions still could not be documented if the items in the body failed to resolve: - Functions containing a nested `DefId` (#71104) - ~~Functions returning `impl Trait` (#43878 These ended up not resolving anyway with this PR. - ~~`const fn`, because `loop {}` in `const fn` is unstable (#43636 `const_loop` was just stabilized. This also isn't exactly what rustdoc wants, which is to avoid looking at function bodies in the first place. ## What changes were made? The hack implemented in this PR is to add an option to ignore all resolution errors in function bodies. This is enabled only for rustdoc. Since resolution errors are ignored, the MIR generated will be invalid, as can be seen in the following ICE: ```rust error: internal compiler error: broken MIR in DefId(0:11 ~ doc_cfg[8787]::uses_target_feature[0]) ("return type"): bad type [type error] --> /home/joshua/src/rust/src/test/rustdoc/doc-cfg.rs:51:1 | 51 | / pub unsafe fn uses_target_feature() { 52 | | content::should::be::irrelevant(); 53 | | } | |_^ ``` Fortunately, rustdoc does not need to access MIR in order to generate documentation. Therefore this also removes the call to `analyze()` in `rustdoc::run_core`. This has the side effect of not generating all lints by default. Most lints are safe to ignore (does rustdoc really need to run liveness analysis?) but `missing_docs` in particular is disabled when it should not be. Re-running `missing_docs` specifically does not help, because it causes the typechecking pass to be run, bringing back the errors from #24658: ``` error[E0599]: no method named `into_handle` found for struct `sys::unix::pipe::AnonPipe` in the current scope --> src/libstd/sys/windows/ext/process.rs:71:27 | 71 | self.into_inner().into_handle().into_raw() as *mut _ | ^^^^^^^^^^^ method not found in `sys::unix::pipe::AnonPipe` | ``` Because of #73743, we only run typeck on demand. So this only causes an issue for functions returning `impl Trait`, which were already special cased by `ReplaceFunctionWithBody`. However, it now considers `async fn f() -> T` to be considered `impl Future<Output = T>`, where before it was considered to have a concrete `T` type. ## How will this affect future changes to rustdoc? - Any new changes to rustdoc will not be able to perform type checking without bringing back resolution errors in function bodies. + As a corollary, any new lints cannot require or perform type checking. In some cases this may require refactoring other parts of the compiler to perform type-checking only on-demand, see for example #73743. + As a corollary, rustdoc can never again call `tcx.analysis()` unless this PR is reverted altogether. ## Current status - ~~I am not yet sure how to bring back `missing_docs` without running typeck. @eddyb suggested allowing lints to opt-out of type-checking, which would probably be another rabbit hole.~~ The opt-out was implemented in #73743. However, of the rustc lints, now _only_ missing_docs is run and no other lints: #73566 (comment). We need a team decision on whether that's an acceptable tradeoff. Note that all rustdoc lints are still run (`intra_doc_link_resolution_failure`, etc). **UPDATE**: This was deemed acceptable in #73566 (comment) - ~~The implementation of optional errors in `rustc_resolve` is very brute force, it should probably be moved from `LateResolver` to `Resolver` to avoid duplicating the logic in many places.~~ I'm mostly happy with it now. - This no longer allows errors in `async fn f() -> T`. This caused breakage in 50 crates out of a full crater run, all of which (that I looked at) didn't compile when run with rustc directly. In other words, it used to be that they could not be compiled but could still be documented; now they can't be documented either. This needs a decision from the rustdoc team on whether this is acceptable breakage. **UPDATE**: This was deemed acceptable in #73566 (comment) - ~~This makes `fn typeck_tables_of` in `rustc_typeck` public. This is not desired behavior, but needs the changes from #74070 in order to be fixed.~~ Reverted.
2 parents 6ee1b62 + 631b2b9 commit c23f045

27 files changed

+505
-37
lines changed

src/librustc_interface/passes.rs

-6
Original file line numberDiff line numberDiff line change
@@ -354,13 +354,7 @@ fn configure_and_expand_inner<'a>(
354354
)
355355
});
356356

357-
// If we're actually rustdoc then there's no need to actually compile
358-
// anything, so switch everything to just looping
359-
let mut should_loop = sess.opts.actually_rustdoc;
360357
if let Some(PpMode::PpmSource(PpSourceMode::PpmEveryBodyLoops)) = sess.opts.pretty {
361-
should_loop |= true;
362-
}
363-
if should_loop {
364358
log::debug!("replacing bodies with loop {{}}");
365359
util::ReplaceBodyWithLoop::new(&mut resolver).visit_crate(&mut krate);
366360
}

src/librustc_resolve/late.rs

+74-25
Original file line numberDiff line numberDiff line change
@@ -394,13 +394,23 @@ struct LateResolutionVisitor<'a, 'b, 'ast> {
394394

395395
/// Fields used to add information to diagnostic errors.
396396
diagnostic_metadata: DiagnosticMetadata<'ast>,
397+
398+
/// State used to know whether to ignore resolution errors for function bodies.
399+
///
400+
/// In particular, rustdoc uses this to avoid giving errors for `cfg()` items.
401+
/// In most cases this will be `None`, in which case errors will always be reported.
402+
/// If it is `Some(_)`, then it will be updated when entering a nested function or trait body.
403+
in_func_body: bool,
397404
}
398405

399406
/// Walks the whole crate in DFS order, visiting each item, resolving names as it goes.
400407
impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
401408
fn visit_item(&mut self, item: &'ast Item) {
402409
let prev = replace(&mut self.diagnostic_metadata.current_item, Some(item));
410+
// Always report errors in items we just entered.
411+
let old_ignore = replace(&mut self.in_func_body, false);
403412
self.resolve_item(item);
413+
self.in_func_body = old_ignore;
404414
self.diagnostic_metadata.current_item = prev;
405415
}
406416
fn visit_arm(&mut self, arm: &'ast Arm) {
@@ -497,13 +507,17 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
497507

498508
visit::walk_fn_ret_ty(this, &declaration.output);
499509

510+
// Ignore errors in function bodies if this is rustdoc
511+
// Be sure not to set this until the function signature has been resolved.
512+
let previous_state = replace(&mut this.in_func_body, true);
500513
// Resolve the function body, potentially inside the body of an async closure
501514
match fn_kind {
502515
FnKind::Fn(.., body) => walk_list!(this, visit_block, body),
503516
FnKind::Closure(_, body) => this.visit_expr(body),
504517
};
505518

506519
debug!("(resolving function) leaving function");
520+
this.in_func_body = previous_state;
507521
})
508522
});
509523
self.diagnostic_metadata.current_function = previous_value;
@@ -644,6 +658,8 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
644658
label_ribs: Vec::new(),
645659
current_trait_ref: None,
646660
diagnostic_metadata: DiagnosticMetadata::default(),
661+
// errors at module scope should always be reported
662+
in_func_body: false,
647663
}
648664
}
649665

@@ -757,7 +773,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
757773
return if self.is_label_valid_from_rib(i) {
758774
Some(*id)
759775
} else {
760-
self.r.report_error(
776+
self.report_error(
761777
original_span,
762778
ResolutionError::UnreachableLabel {
763779
name: label.name,
@@ -775,7 +791,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
775791
suggestion = suggestion.or_else(|| self.suggestion_for_label_in_rib(i, label));
776792
}
777793

778-
self.r.report_error(
794+
self.report_error(
779795
original_span,
780796
ResolutionError::UndeclaredLabel { name: label.name, suggestion },
781797
);
@@ -833,7 +849,11 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
833849
};
834850
let report_error = |this: &Self, ns| {
835851
let what = if ns == TypeNS { "type parameters" } else { "local variables" };
836-
this.r.session.span_err(ident.span, &format!("imports cannot refer to {}", what));
852+
if this.should_report_errs() {
853+
this.r
854+
.session
855+
.span_err(ident.span, &format!("imports cannot refer to {}", what));
856+
}
837857
};
838858

839859
for &ns in nss {
@@ -1008,7 +1028,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
10081028
if seen_bindings.contains_key(&ident) {
10091029
let span = seen_bindings.get(&ident).unwrap();
10101030
let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, *span);
1011-
self.r.report_error(param.ident.span, err);
1031+
self.report_error(param.ident.span, err);
10121032
}
10131033
seen_bindings.entry(ident).or_insert(param.ident.span);
10141034

@@ -1274,7 +1294,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
12741294
.is_err()
12751295
{
12761296
let path = &self.current_trait_ref.as_ref().unwrap().1.path;
1277-
self.r.report_error(span, err(ident.name, &path_names_to_string(path)));
1297+
self.report_error(span, err(ident.name, &path_names_to_string(path)));
12781298
}
12791299
}
12801300
}
@@ -1289,6 +1309,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
12891309
}
12901310

12911311
fn resolve_local(&mut self, local: &'ast Local) {
1312+
debug!("resolving local ({:?})", local);
12921313
// Resolve the type.
12931314
walk_list!(self, visit_ty, &local.ty);
12941315

@@ -1390,7 +1411,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
13901411
if inconsistent_vars.contains_key(name) {
13911412
v.could_be_path = false;
13921413
}
1393-
self.r.report_error(
1414+
self.report_error(
13941415
*v.origin.iter().next().unwrap(),
13951416
ResolutionError::VariableNotBoundInPattern(v),
13961417
);
@@ -1400,7 +1421,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
14001421
let mut inconsistent_vars = inconsistent_vars.iter().collect::<Vec<_>>();
14011422
inconsistent_vars.sort();
14021423
for (name, v) in inconsistent_vars {
1403-
self.r.report_error(v.0, ResolutionError::VariableBoundWithDifferentMode(*name, v.1));
1424+
self.report_error(v.0, ResolutionError::VariableBoundWithDifferentMode(*name, v.1));
14041425
}
14051426

14061427
// 5) Finally bubble up all the binding maps.
@@ -1550,7 +1571,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
15501571
// `Variant(a, a)`:
15511572
_ => IdentifierBoundMoreThanOnceInSamePattern,
15521573
};
1553-
self.r.report_error(ident.span, error(ident.name));
1574+
self.report_error(ident.span, error(ident.name));
15541575
}
15551576

15561577
// Record as bound if it's valid:
@@ -1624,7 +1645,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
16241645
// to something unusable as a pattern (e.g., constructor function),
16251646
// but we still conservatively report an error, see
16261647
// issues/33118#issuecomment-233962221 for one reason why.
1627-
self.r.report_error(
1648+
self.report_error(
16281649
ident.span,
16291650
ResolutionError::BindingShadowsSomethingUnacceptable(
16301651
pat_src.descr(),
@@ -1677,18 +1698,27 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
16771698
source: PathSource<'ast>,
16781699
crate_lint: CrateLint,
16791700
) -> PartialRes {
1701+
log::debug!("smart_resolve_path_fragment(id={:?},qself={:?},path={:?}", id, qself, path);
16801702
let ns = source.namespace();
16811703
let is_expected = &|res| source.is_expected(res);
16821704

16831705
let report_errors = |this: &mut Self, res: Option<Res>| {
1684-
let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res);
1685-
1686-
let def_id = this.parent_scope.module.normal_ancestor_id;
1687-
let instead = res.is_some();
1688-
let suggestion =
1689-
if res.is_none() { this.report_missing_type_error(path) } else { None };
1690-
1691-
this.r.use_injections.push(UseError { err, candidates, def_id, instead, suggestion });
1706+
if this.should_report_errs() {
1707+
let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res);
1708+
1709+
let def_id = this.parent_scope.module.normal_ancestor_id;
1710+
let instead = res.is_some();
1711+
let suggestion =
1712+
if res.is_none() { this.report_missing_type_error(path) } else { None };
1713+
1714+
this.r.use_injections.push(UseError {
1715+
err,
1716+
candidates,
1717+
def_id,
1718+
instead,
1719+
suggestion,
1720+
});
1721+
}
16921722

16931723
PartialRes::new(Res::Err)
16941724
};
@@ -1746,13 +1776,17 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
17461776

17471777
let def_id = this.parent_scope.module.normal_ancestor_id;
17481778

1749-
this.r.use_injections.push(UseError {
1750-
err,
1751-
candidates,
1752-
def_id,
1753-
instead: false,
1754-
suggestion: None,
1755-
});
1779+
if this.should_report_errs() {
1780+
this.r.use_injections.push(UseError {
1781+
err,
1782+
candidates,
1783+
def_id,
1784+
instead: false,
1785+
suggestion: None,
1786+
});
1787+
} else {
1788+
err.cancel();
1789+
}
17561790

17571791
// We don't return `Some(parent_err)` here, because the error will
17581792
// be already printed as part of the `use` injections
@@ -1809,7 +1843,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
18091843

18101844
Err(err) => {
18111845
if let Some(err) = report_errors_for_call(self, err) {
1812-
self.r.report_error(err.span, err.node);
1846+
self.report_error(err.span, err.node);
18131847
}
18141848

18151849
PartialRes::new(Res::Err)
@@ -1843,6 +1877,21 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
18431877
if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false }
18441878
}
18451879

1880+
/// A wrapper around [`Resolver::report_error`].
1881+
///
1882+
/// This doesn't emit errors for function bodies if this is rustdoc.
1883+
fn report_error(&self, span: Span, resolution_error: ResolutionError<'_>) {
1884+
if self.should_report_errs() {
1885+
self.r.report_error(span, resolution_error);
1886+
}
1887+
}
1888+
1889+
#[inline]
1890+
/// If we're actually rustdoc then avoid giving a name resolution error for `cfg()` items.
1891+
fn should_report_errs(&self) -> bool {
1892+
!(self.r.session.opts.actually_rustdoc && self.in_func_body)
1893+
}
1894+
18461895
// Resolve in alternative namespaces if resolution in the primary namespace fails.
18471896
fn resolve_qpath_anywhere(
18481897
&mut self,

src/librustdoc/core.rs

+102-6
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,15 @@ use rustc_driver::abort_on_err;
55
use rustc_errors::emitter::{Emitter, EmitterWriter};
66
use rustc_errors::json::JsonEmitter;
77
use rustc_feature::UnstableFeatures;
8-
use rustc_hir::def::Namespace::TypeNS;
8+
use rustc_hir::def::{Namespace::TypeNS, Res};
99
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
1010
use rustc_hir::HirId;
11+
use rustc_hir::{
12+
intravisit::{self, NestedVisitorMap, Visitor},
13+
Path,
14+
};
1115
use rustc_interface::interface;
16+
use rustc_middle::hir::map::Map;
1217
use rustc_middle::middle::cstore::CrateStore;
1318
use rustc_middle::middle::privacy::AccessLevels;
1419
use rustc_middle::ty::{Ty, TyCtxt};
@@ -372,7 +377,35 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
372377
crate_name,
373378
lint_caps,
374379
register_lints: None,
375-
override_queries: None,
380+
override_queries: Some(|_sess, providers, _external_providers| {
381+
// Most lints will require typechecking, so just don't run them.
382+
providers.lint_mod = |_, _| {};
383+
// Prevent `rustc_typeck::check_crate` from calling `typeck_tables_of` on all bodies.
384+
providers.typeck_item_bodies = |_, _| {};
385+
// hack so that `used_trait_imports` won't try to call typeck_tables_of
386+
providers.used_trait_imports = |_, _| {
387+
lazy_static! {
388+
static ref EMPTY_SET: FxHashSet<LocalDefId> = FxHashSet::default();
389+
}
390+
&EMPTY_SET
391+
};
392+
// In case typeck does end up being called, don't ICE in case there were name resolution errors
393+
providers.typeck_tables_of = move |tcx, def_id| {
394+
// Closures' tables come from their outermost function,
395+
// as they are part of the same "inference environment".
396+
// This avoids emitting errors for the parent twice (see similar code in `typeck_tables_of_with_fallback`)
397+
let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()).expect_local();
398+
if outer_def_id != def_id {
399+
return tcx.typeck_tables_of(outer_def_id);
400+
}
401+
402+
let hir = tcx.hir();
403+
let body = hir.body(hir.body_owned_by(hir.as_local_hir_id(def_id)));
404+
debug!("visiting body for {:?}", def_id);
405+
EmitIgnoredResolutionErrors::new(tcx).visit_body(body);
406+
(rustc_interface::DEFAULT_QUERY_PROVIDERS.typeck_tables_of)(tcx, def_id)
407+
};
408+
}),
376409
registry: rustc_driver::diagnostics_registry(),
377410
};
378411

@@ -416,10 +449,17 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
416449
let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess).take();
417450

418451
global_ctxt.enter(|tcx| {
419-
tcx.analysis(LOCAL_CRATE).ok();
420-
421-
// Abort if there were any errors so far
422-
sess.abort_if_errors();
452+
// Certain queries assume that some checks were run elsewhere
453+
// (see https://github.com/rust-lang/rust/pull/73566#issuecomment-656954425),
454+
// so type-check everything other than function bodies in this crate before running lints.
455+
// NOTE: this does not call `tcx.analysis()` so that we won't
456+
// typeck function bodies or run the default rustc lints.
457+
// (see `override_queries` in the `config`)
458+
let _ = rustc_typeck::check_crate(tcx);
459+
tcx.sess.abort_if_errors();
460+
sess.time("missing_docs", || {
461+
rustc_lint::check_crate(tcx, rustc_lint::builtin::MissingDoc::new);
462+
});
423463

424464
let access_levels = tcx.privacy_access_levels(LOCAL_CRATE);
425465
// Convert from a HirId set to a DefId set since we don't always have easy access
@@ -570,6 +610,62 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
570610
})
571611
}
572612

613+
/// Due to https://github.com/rust-lang/rust/pull/73566,
614+
/// the name resolution pass may find errors that are never emitted.
615+
/// If typeck is called after this happens, then we'll get an ICE:
616+
/// 'Res::Error found but not reported'. To avoid this, emit the errors now.
617+
struct EmitIgnoredResolutionErrors<'tcx> {
618+
tcx: TyCtxt<'tcx>,
619+
}
620+
621+
impl<'tcx> EmitIgnoredResolutionErrors<'tcx> {
622+
fn new(tcx: TyCtxt<'tcx>) -> Self {
623+
Self { tcx }
624+
}
625+
}
626+
627+
impl<'tcx> Visitor<'tcx> for EmitIgnoredResolutionErrors<'tcx> {
628+
type Map = Map<'tcx>;
629+
630+
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
631+
// We need to recurse into nested closures,
632+
// since those will fallback to the parent for type checking.
633+
NestedVisitorMap::OnlyBodies(self.tcx.hir())
634+
}
635+
636+
fn visit_path(&mut self, path: &'tcx Path<'_>, _id: HirId) {
637+
debug!("visiting path {:?}", path);
638+
if path.res == Res::Err {
639+
// We have less context here than in rustc_resolve,
640+
// so we can only emit the name and span.
641+
// However we can give a hint that rustc_resolve will have more info.
642+
let label = format!(
643+
"could not resolve path `{}`",
644+
path.segments
645+
.iter()
646+
.map(|segment| segment.ident.as_str().to_string())
647+
.collect::<Vec<_>>()
648+
.join("::")
649+
);
650+
let mut err = rustc_errors::struct_span_err!(
651+
self.tcx.sess,
652+
path.span,
653+
E0433,
654+
"failed to resolve: {}",
655+
label
656+
);
657+
err.span_label(path.span, label);
658+
err.note("this error was originally ignored because you are running `rustdoc`");
659+
err.note("try running again with `rustc` or `cargo check` and you may get a more detailed error");
660+
err.emit();
661+
}
662+
// We could have an outer resolution that succeeded,
663+
// but with generic parameters that failed.
664+
// Recurse into the segments so we catch those too.
665+
intravisit::walk_path(self, path);
666+
}
667+
}
668+
573669
/// `DefId` or parameter index (`ty::ParamTy.index`) of a synthetic type parameter
574670
/// for `impl Trait` in argument position.
575671
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]

0 commit comments

Comments
 (0)