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
16 changed files with 145 additions and 76 deletions
|
@ -377,10 +377,18 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
|
||||||
external_providers.lint_mod = |_, _| {};
|
external_providers.lint_mod = |_, _| {};
|
||||||
//let old_typeck = local_providers.typeck_tables_of;
|
//let old_typeck = local_providers.typeck_tables_of;
|
||||||
local_providers.typeck_tables_of = move |tcx, def_id| {
|
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 hir = tcx.hir();
|
||||||
let body = hir.body(hir.body_owned_by(hir.as_local_hir_id(def_id)));
|
let body = hir.body(hir.body_owned_by(hir.as_local_hir_id(def_id)));
|
||||||
debug!("visiting body for {:?}", 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)
|
rustc_typeck::check::typeck_tables_of(tcx, def_id)
|
||||||
//DEFAULT_TYPECK.with(|typeck| typeck(tcx, def_id))
|
//DEFAULT_TYPECK.with(|typeck| typeck(tcx, def_id))
|
||||||
};
|
};
|
||||||
|
@ -600,22 +608,24 @@ thread_local!(static DEFAULT_TYPECK: for<'tcx> fn(rustc_middle::ty::TyCtxt<'tcx>
|
||||||
/// the name resolution pass may find errors that are never emitted.
|
/// the name resolution pass may find errors that are never emitted.
|
||||||
/// If typeck is called after this happens, then we'll get an ICE:
|
/// 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.
|
/// 'Res::Error found but not reported'. To avoid this, emit the errors now.
|
||||||
struct EmitIgnoredResolutionErrors<'a> {
|
struct EmitIgnoredResolutionErrors<'a, 'hir> {
|
||||||
session: &'a Session,
|
session: &'a Session,
|
||||||
|
hir_map: Map<'hir>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> EmitIgnoredResolutionErrors<'a> {
|
impl<'a, 'hir> EmitIgnoredResolutionErrors<'a, 'hir> {
|
||||||
fn new(session: &'a Session) -> Self {
|
fn new(session: &'a Session, hir_map: Map<'hir>) -> Self {
|
||||||
Self { session }
|
Self { session, hir_map }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Visitor<'a> for EmitIgnoredResolutionErrors<'_> {
|
impl<'hir> Visitor<'hir> for EmitIgnoredResolutionErrors<'_, 'hir> {
|
||||||
type Map = Map<'a>;
|
type Map = Map<'hir>;
|
||||||
|
|
||||||
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
|
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
|
// We need to recurse into nested closures,
|
||||||
NestedVisitorMap::None
|
// 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) {
|
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…
Add table
Add a link
Reference in a new issue