diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index ef569b4bef3b3..86f36eedd9007 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -43,7 +43,8 @@ use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection, Pro use rustc_middle::mir::FakeReadCause; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::{ - self, ClosureSizeProfileData, Ty, TyCtxt, TypeckResults, UpvarArgs, UpvarCapture, + self, ClosureSizeProfileData, Ty, TyCtxt, TypeVisitableExt as _, TypeckResults, UpvarArgs, + UpvarCapture, }; use rustc_session::lint; use rustc_span::sym; @@ -191,6 +192,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } }; + let args = self.resolve_vars_if_possible(args); let closure_def_id = closure_def_id.expect_local(); assert_eq!(self.tcx.hir().body_owner_def_id(body.id()), closure_def_id); @@ -361,7 +363,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // For coroutine-closures, we additionally must compute the // `coroutine_captures_by_ref_ty` type, which is used to generate the by-ref // version of the coroutine-closure's output coroutine. - if let UpvarArgs::CoroutineClosure(args) = args { + if let UpvarArgs::CoroutineClosure(args) = args + && !args.references_error() + { let closure_env_region: ty::Region<'_> = ty::Region::new_bound( self.tcx, ty::INNERMOST, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index dd73f0f4a350d..ad64745d579a0 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -771,7 +771,7 @@ impl<'tcx> CoroutineArgs<'tcx> { } } -#[derive(Debug, Copy, Clone, HashStable)] +#[derive(Debug, Copy, Clone, HashStable, TypeFoldable, TypeVisitable)] pub enum UpvarArgs<'tcx> { Closure(GenericArgsRef<'tcx>), Coroutine(GenericArgsRef<'tcx>), diff --git a/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.rs b/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.rs new file mode 100644 index 0000000000000..8fc9924a12fb0 --- /dev/null +++ b/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.rs @@ -0,0 +1,23 @@ +//@ edition: 2021 + +#![feature(async_closure)] + +struct DropMe; + +trait Impossible {} +fn trait_error() {} + +pub fn main() { + let b = DropMe; + let async_closure = async move || { + // Type error here taints the environment. This causes us to fallback all + // variables to `Error`. This means that when we compute the upvars for the + // *outer* coroutine-closure, we don't actually see any upvars since `MemCategorization` + // and `ExprUseVisitor`` will bail early when it sees error. This means + // that our underlying assumption that the parent and child captures are + // compatible ends up being broken, previously leading to an ICE. + trait_error::<()>(); + //~^ ERROR the trait bound `(): Impossible` is not satisfied + let _b = b; + }; +} diff --git a/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.stderr b/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.stderr new file mode 100644 index 0000000000000..b4dc3e268bdaf --- /dev/null +++ b/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `(): Impossible` is not satisfied + --> $DIR/dont-ice-when-body-tainted-by-errors.rs:19:23 + | +LL | trait_error::<()>(); + | ^^ the trait `Impossible` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/dont-ice-when-body-tainted-by-errors.rs:7:1 + | +LL | trait Impossible {} + | ^^^^^^^^^^^^^^^^ +note: required by a bound in `trait_error` + --> $DIR/dont-ice-when-body-tainted-by-errors.rs:8:19 + | +LL | fn trait_error() {} + | ^^^^^^^^^^ required by this bound in `trait_error` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`.