Recurse into function bodies, but don't typeck closures
Previously, rustdoc would issue a delay_span_bug ICE on the following code: ```rust pub fn a() -> impl Fn() -> u32 { || content::doesnt::matter() } ``` This wasn't picked up earlier because having `type Alias = impl Trait;` in the same module caused _all closures_ to be typechecked, even if they wouldn't normally. Additionally, if _any_ error was emitted, no delay_span_bug would be emitted. So as part of this commit all of the tests were separated out into different files.
This commit is contained in:
parent
768d6a4950
commit
a93bcc9a7b
@ -377,10 +377,18 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
|
||||
external_providers.lint_mod = |_, _| {};
|
||||
//let old_typeck = local_providers.typeck_tables_of;
|
||||
local_providers.typeck_tables_of = move |tcx, def_id| {
|
||||
// Closures' tables come from their outermost function,
|
||||
// as they are part of the same "inference environment".
|
||||
// This avoids emitting errors for the parent twice (see similar code in `typeck_tables_of_with_fallback`)
|
||||
let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()).expect_local();
|
||||
if outer_def_id != def_id {
|
||||
return tcx.typeck_tables_of(outer_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);
|
||||
EmitIgnoredResolutionErrors::new(&tcx.sess, hir).visit_body(body);
|
||||
rustc_typeck::check::typeck_tables_of(tcx, def_id)
|
||||
//DEFAULT_TYPECK.with(|typeck| typeck(tcx, def_id))
|
||||
};
|
||||
@ -600,22 +608,24 @@ fn report_deprecated_attr(name: &str, diag: &rustc_errors::Handler) {
|
||||
/// 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> {
|
||||
struct EmitIgnoredResolutionErrors<'a, 'hir> {
|
||||
session: &'a Session,
|
||||
hir_map: Map<'hir>,
|
||||
}
|
||||
|
||||
impl<'a> EmitIgnoredResolutionErrors<'a> {
|
||||
fn new(session: &'a Session) -> Self {
|
||||
Self { session }
|
||||
impl<'a, 'hir> EmitIgnoredResolutionErrors<'a, 'hir> {
|
||||
fn new(session: &'a Session, hir_map: Map<'hir>) -> Self {
|
||||
Self { session, hir_map }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Visitor<'a> for EmitIgnoredResolutionErrors<'_> {
|
||||
type Map = Map<'a>;
|
||||
impl<'hir> Visitor<'hir> for EmitIgnoredResolutionErrors<'_, 'hir> {
|
||||
type Map = Map<'hir>;
|
||||
|
||||
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
|
||||
// We need to recurse into nested closures,
|
||||
// since those will fallback to the parent for type checking.
|
||||
NestedVisitorMap::OnlyBodies(self.hir_map)
|
||||
}
|
||||
|
||||
fn visit_path(&mut self, path: &'v Path<'v>, _id: HirId) {
|
||||
|
@ -1,28 +0,0 @@
|
||||
// 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
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
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`.
|
7
src/test/rustdoc-ui/error-in-impl-trait/README.md
Normal file
7
src/test/rustdoc-ui/error-in-impl-trait/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
Each of these needs to be in a separate file,
|
||||
because the `delay_span_bug` ICE in rustdoc won't be triggerred
|
||||
if even a single other error was emitted.
|
||||
|
||||
However, conceptually they are all testing basically the same thing.
|
||||
See https://github.com/rust-lang/rust/pull/73566#issuecomment-653689128
|
||||
for more details.
|
10
src/test/rustdoc-ui/error-in-impl-trait/async.rs
Normal file
10
src/test/rustdoc-ui/error-in-impl-trait/async.rs
Normal file
@ -0,0 +1,10 @@
|
||||
// edition:2018
|
||||
|
||||
/// 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
|
||||
}
|
12
src/test/rustdoc-ui/error-in-impl-trait/async.stderr
Normal file
12
src/test/rustdoc-ui/error-in-impl-trait/async.stderr
Normal file
@ -0,0 +1,12 @@
|
||||
error[E0433]: failed to resolve: could not resolve path `error::_in::async_fn`
|
||||
--> $DIR/async.rs:8: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 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0433`.
|
5
src/test/rustdoc-ui/error-in-impl-trait/closure.rs
Normal file
5
src/test/rustdoc-ui/error-in-impl-trait/closure.rs
Normal file
@ -0,0 +1,5 @@
|
||||
// manually desugared version of an `async fn` (but with a closure instead of a generator)
|
||||
pub fn a() -> impl Fn() -> u32 {
|
||||
|| content::doesnt::matter()
|
||||
//~^ ERROR failed to resolve
|
||||
}
|
12
src/test/rustdoc-ui/error-in-impl-trait/closure.stderr
Normal file
12
src/test/rustdoc-ui/error-in-impl-trait/closure.stderr
Normal file
@ -0,0 +1,12 @@
|
||||
error[E0433]: failed to resolve: could not resolve path `content::doesnt::matter`
|
||||
--> $DIR/closure.rs:3:8
|
||||
|
|
||||
LL | || content::doesnt::matter()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `content::doesnt::matter`
|
||||
|
|
||||
= 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 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0433`.
|
@ -0,0 +1,6 @@
|
||||
pub trait ValidTrait {}
|
||||
/// This returns impl trait
|
||||
pub fn g() -> impl ValidTrait {
|
||||
(|| error::_in::impl_trait::alias::nested::closure())()
|
||||
//~^ ERROR failed to resolve
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias::nested::closure`
|
||||
--> $DIR/impl-keyword-closure.rs:4: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: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0433`.
|
6
src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs
Normal file
6
src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs
Normal file
@ -0,0 +1,6 @@
|
||||
pub trait ValidTrait {}
|
||||
/// This returns impl trait
|
||||
pub fn g() -> impl ValidTrait {
|
||||
error::_in::impl_trait()
|
||||
//~^ ERROR failed to resolve
|
||||
}
|
12
src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.stderr
Normal file
12
src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.stderr
Normal file
@ -0,0 +1,12 @@
|
||||
error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait`
|
||||
--> $DIR/impl-keyword.rs:4: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: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0433`.
|
@ -0,0 +1,10 @@
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
pub trait ValidTrait {}
|
||||
type ImplTrait = impl ValidTrait;
|
||||
|
||||
/// This returns impl trait, but using a type alias
|
||||
pub fn h() -> ImplTrait {
|
||||
(|| error::_in::impl_trait::alias::nested::closure())()
|
||||
//~^ ERROR failed to resolve
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias::nested::closure`
|
||||
--> $DIR/trait-alias-closure.rs:8: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: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0433`.
|
10
src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs
Normal file
10
src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs
Normal file
@ -0,0 +1,10 @@
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
pub trait ValidTrait {}
|
||||
type ImplTrait = impl ValidTrait;
|
||||
|
||||
/// This returns impl trait, but using a type alias
|
||||
pub fn h() -> ImplTrait {
|
||||
error::_in::impl_trait::alias()
|
||||
//~^ ERROR failed to resolve
|
||||
}
|
12
src/test/rustdoc-ui/error-in-impl-trait/trait-alias.stderr
Normal file
12
src/test/rustdoc-ui/error-in-impl-trait/trait-alias.stderr
Normal file
@ -0,0 +1,12 @@
|
||||
error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias`
|
||||
--> $DIR/trait-alias.rs:8: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: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0433`.
|
Loading…
Reference in New Issue
Block a user