Instead, report the error.
This emits the errors on-demand, without special-casing `impl Trait`, so
it should catch all ICEs of this kind, including ones that haven't been
found yet.
Since the error is emitted during type-checking there is less info about
the error; see comments in the code for details.
- Add test case for -> impl Trait
- Add test for impl trait with alias
- Move EmitIgnoredResolutionErrors to rustdoc
This makes `fn typeck_item_bodies` public, which is not desired behavior.
That change should be removed once
https://github.com/rust-lang/rust/pull/74070 is merged.
- Don't visit nested closures twice
val.fold_with(&mut FixupFolder { tcx })
}
-fn typeck_tables_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckTables<'tcx> {
+pub fn typeck_tables_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckTables<'tcx> {
let fallback = move || tcx.type_of(def_id.to_def_id());
typeck_tables_of_with_fallback(tcx, def_id, fallback)
}
pub mod expr_use_visitor;
mod astconv;
-mod check;
+pub mod check;
mod check_unused;
mod coherence;
mod collect;
override_queries: Some(|_sess, local_providers, external_providers| {
local_providers.lint_mod = |_, _| {};
external_providers.lint_mod = |_, _| {};
+ //let old_typeck = local_providers.typeck_tables_of;
+ local_providers.typeck_tables_of = move |tcx, def_id| {
+ let hir = tcx.hir();
+ let body = hir.body(hir.body_owned_by(hir.as_local_hir_id(def_id)));
+ debug!("visiting body for {:?}", def_id);
+ EmitIgnoredResolutionErrors::new(&tcx.sess).visit_body(body);
+ rustc_typeck::check::typeck_tables_of(tcx, def_id)
+ //DEFAULT_TYPECK.with(|typeck| typeck(tcx, def_id))
+ };
}),
registry: rustc_driver::diagnostics_registry(),
};
})
}
+use rustc_hir::def::Res;
+use rustc_hir::{
+ intravisit::{NestedVisitorMap, Visitor},
+ Path,
+};
+use rustc_middle::hir::map::Map;
+
+/*
+thread_local!(static DEFAULT_TYPECK: for<'tcx> fn(rustc_middle::ty::TyCtxt<'tcx>, rustc_span::def_id::LocalDefId) -> &'tcx rustc_middle::ty::TypeckTables<'tcx> = {
+ let mut providers = rustc_middle::ty::query::Providers::default();
+ rustc_typeck::provide(&mut providers);
+ providers.typeck_tables_of
+});
+*/
+
+/// Due to https://github.com/rust-lang/rust/pull/73566,
+/// the name resolution pass may find errors that are never emitted.
+/// If typeck is called after this happens, then we'll get an ICE:
+/// 'Res::Error found but not reported'. To avoid this, emit the errors now.
+struct EmitIgnoredResolutionErrors<'a> {
+ session: &'a Session,
+}
+
+impl<'a> EmitIgnoredResolutionErrors<'a> {
+ fn new(session: &'a Session) -> Self {
+ Self { session }
+ }
+}
+
+impl<'a> Visitor<'a> for EmitIgnoredResolutionErrors<'_> {
+ type Map = Map<'a>;
+
+ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+ // If we visit nested bodies, then we will report errors twice for e.g. nested closures
+ NestedVisitorMap::None
+ }
+
+ fn visit_path(&mut self, path: &'v Path<'v>, _id: HirId) {
+ log::debug!("visiting path {:?}", path);
+ if path.res == Res::Err {
+ // We have less context here than in rustc_resolve,
+ // so we can only emit the name and span.
+ // However we can give a hint that rustc_resolve will have more info.
+ // NOTE: this is a very rare case (only 4 out of several hundred thousand crates in a crater run)
+ // NOTE: so it's ok for it to be slow
+ let label = format!(
+ "could not resolve path `{}`",
+ path.segments
+ .iter()
+ .map(|segment| segment.ident.as_str().to_string())
+ .collect::<Vec<_>>()
+ .join("::")
+ );
+ let mut err = rustc_errors::struct_span_err!(
+ self.session,
+ path.span,
+ E0433,
+ "failed to resolve: {}",
+ label
+ );
+ err.span_label(path.span, label);
+ err.note("this error was originally ignored because you are running `rustdoc`");
+ err.note("try running again with `rustc` and you may get a more detailed error");
+ err.emit();
+ }
+ // NOTE: this does _not_ visit the path segments
+ }
+}
+
/// `DefId` or parameter index (`ty::ParamTy.index`) of a synthetic type parameter
/// for `impl Trait` in argument position.
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
32_000_000 // 32MB on other platforms
};
rustc_driver::set_sigpipe_handler();
+ rustc_driver::install_ice_hook();
env_logger::init_from_env("RUSTDOC_LOG");
let res = std::thread::Builder::new()
.stack_size(thread_stack_size)
--- /dev/null
+// edition:2018
+#![feature(type_alias_impl_trait)]
+
+pub trait ValidTrait {}
+type ImplTrait = impl ValidTrait;
+
+/// This returns impl trait
+pub fn g() -> impl ValidTrait {
+ error::_in::impl_trait()
+ //~^ ERROR failed to resolve
+}
+
+/// This returns impl trait, but using a type alias
+pub fn h() -> ImplTrait {
+ error::_in::impl_trait::alias();
+ //~^ ERROR failed to resolve
+ (|| error::_in::impl_trait::alias::nested::closure())()
+ //~^ ERROR failed to resolve
+}
+
+/// This used to work with ResolveBodyWithLoop.
+/// However now that we ignore type checking instead of modifying the function body,
+/// the return type is seen as `impl Future<Output = u32>`, not a `u32`.
+/// So it no longer allows errors in the function body.
+pub async fn a() -> u32 {
+ error::_in::async_fn()
+ //~^ ERROR failed to resolve
+}
--- /dev/null
+error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait`
+ --> $DIR/error-in-impl-trait.rs:9:5
+ |
+LL | error::_in::impl_trait()
+ | ^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait`
+ |
+ = note: this error was originally ignored because you are running `rustdoc`
+ = note: try running again with `rustc` and you may get a more detailed error
+
+error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias`
+ --> $DIR/error-in-impl-trait.rs:15:5
+ |
+LL | error::_in::impl_trait::alias();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias`
+ |
+ = note: this error was originally ignored because you are running `rustdoc`
+ = note: try running again with `rustc` and you may get a more detailed error
+
+error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias::nested::closure`
+ --> $DIR/error-in-impl-trait.rs:17:9
+ |
+LL | (|| error::_in::impl_trait::alias::nested::closure())()
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias::nested::closure`
+ |
+ = note: this error was originally ignored because you are running `rustdoc`
+ = note: try running again with `rustc` and you may get a more detailed error
+
+error[E0433]: failed to resolve: could not resolve path `error::_in::async_fn`
+ --> $DIR/error-in-impl-trait.rs:26:5
+ |
+LL | error::_in::async_fn()
+ | ^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::async_fn`
+ |
+ = note: this error was originally ignored because you are running `rustdoc`
+ = note: try running again with `rustc` and you may get a more detailed error
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0433`.
--- /dev/null
+#![feature(type_alias_impl_trait)]
+
+trait MyTrait {}
+impl MyTrait for i32 {}
+
+// @has impl_trait_alias/type.Foo.html 'Foo'
+/// debug type
+pub type Foo = impl MyTrait;
+
+// @has impl_trait_alias/fn.foo.html 'foo'
+/// debug function
+pub fn foo() -> Foo {
+ 1
+}