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:
Joshua Nelson 2020-07-09 09:13:59 -04:00
parent 768d6a4950
commit a93bcc9a7b
16 changed files with 145 additions and 76 deletions

View File

@ -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) {

View File

@ -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
}

View File

@ -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`.

View 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.

View 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
}

View 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`.

View 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
}

View 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`.

View File

@ -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
}

View File

@ -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`.

View 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
}

View 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`.

View 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::nested::closure())()
//~^ ERROR failed to resolve
}

View File

@ -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`.

View 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
}

View 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`.