Skip to content

Commit 19eb35e

Browse files
Only compute layout of opaque if coroutine is the cause of an opaque cycle
1 parent 25415d5 commit 19eb35e

File tree

6 files changed

+58
-32
lines changed

6 files changed

+58
-32
lines changed

compiler/rustc_hir_analysis/src/check/check.rs

+26-9
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use rustc_middle::middle::stability::EvalResult;
1818
use rustc_middle::traits::{DefiningAnchor, ObligationCauseCode};
1919
use rustc_middle::ty::fold::BottomUpFolder;
2020
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
21-
use rustc_middle::ty::util::{Discr, IntTypeExt};
21+
use rustc_middle::ty::util::{Discr, InspectCoroutineFields, IntTypeExt};
2222
use rustc_middle::ty::GenericArgKind;
2323
use rustc_middle::ty::{
2424
self, AdtDef, ParamEnv, RegionKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
@@ -235,16 +235,33 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
235235
span: Span,
236236
) -> Result<(), ErrorGuaranteed> {
237237
let args = GenericArgs::identity_for_item(tcx, def_id);
238-
if tcx.try_expand_impl_trait_type(def_id.to_def_id(), args).is_err() {
239-
let reported = opaque_type_cycle_error(tcx, def_id, span);
240-
Err(reported)
241-
} else if let Err(&LayoutError::Cycle(guar)) =
242-
tcx.layout_of(tcx.param_env(def_id).and(Ty::new_opaque(tcx, def_id.to_def_id(), args)))
238+
239+
// First, try to look at any opaque expansion cycles, considering coroutine fields
240+
// (even though these aren't necessarily true errors).
241+
if tcx
242+
.try_expand_impl_trait_type(def_id.to_def_id(), args, InspectCoroutineFields::Yes)
243+
.is_err()
243244
{
244-
Err(guar)
245-
} else {
246-
Ok(())
245+
// Look for true opaque expansion cycles, but ignore coroutines.
246+
// This will give us any true errors. Coroutines are only problematic
247+
// if they cause layout computation errors.
248+
if tcx
249+
.try_expand_impl_trait_type(def_id.to_def_id(), args, InspectCoroutineFields::No)
250+
.is_err()
251+
{
252+
let reported = opaque_type_cycle_error(tcx, def_id, span);
253+
return Err(reported);
254+
}
255+
256+
// And also look for cycle errors in the layout of coroutines.
257+
if let Err(&LayoutError::Cycle(guar)) =
258+
tcx.layout_of(tcx.param_env(def_id).and(Ty::new_opaque(tcx, def_id.to_def_id(), args)))
259+
{
260+
return Err(guar);
261+
}
247262
}
263+
264+
Ok(())
248265
}
249266

250267
/// Check that the concrete type behind `impl Trait` actually implements `Trait`.

compiler/rustc_middle/src/ty/util.rs

+25-1
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,7 @@ impl<'tcx> TyCtxt<'tcx> {
711711
check_recursion: false,
712712
expand_coroutines: false,
713713
tcx: self,
714+
inspect_coroutine_fields: InspectCoroutineFields::No,
714715
};
715716
val.fold_with(&mut visitor)
716717
}
@@ -721,6 +722,7 @@ impl<'tcx> TyCtxt<'tcx> {
721722
self,
722723
def_id: DefId,
723724
args: GenericArgsRef<'tcx>,
725+
inspect_coroutine_fields: InspectCoroutineFields,
724726
) -> Result<Ty<'tcx>, Ty<'tcx>> {
725727
let mut visitor = OpaqueTypeExpander {
726728
seen_opaque_tys: FxHashSet::default(),
@@ -731,6 +733,7 @@ impl<'tcx> TyCtxt<'tcx> {
731733
check_recursion: true,
732734
expand_coroutines: true,
733735
tcx: self,
736+
inspect_coroutine_fields,
734737
};
735738

736739
let expanded_type = visitor.expand_opaque_ty(def_id, args).unwrap();
@@ -816,6 +819,13 @@ struct OpaqueTypeExpander<'tcx> {
816819
/// recursion, and 'false' otherwise to avoid unnecessary work.
817820
check_recursion: bool,
818821
tcx: TyCtxt<'tcx>,
822+
inspect_coroutine_fields: InspectCoroutineFields,
823+
}
824+
825+
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
826+
pub enum InspectCoroutineFields {
827+
No,
828+
Yes,
819829
}
820830

821831
impl<'tcx> OpaqueTypeExpander<'tcx> {
@@ -854,7 +864,20 @@ impl<'tcx> OpaqueTypeExpander<'tcx> {
854864
}
855865
let args = args.fold_with(self);
856866
if !self.check_recursion || self.seen_opaque_tys.insert(def_id) {
857-
let expanded_ty = Ty::new_coroutine_witness(self.tcx, def_id, args);
867+
let expanded_ty = match self.expanded_cache.get(&(def_id, args)) {
868+
Some(expanded_ty) => *expanded_ty,
869+
None => {
870+
if matches!(self.inspect_coroutine_fields, InspectCoroutineFields::Yes) {
871+
for bty in self.tcx.coroutine_hidden_types(def_id) {
872+
let hidden_ty = bty.instantiate(self.tcx, args);
873+
self.fold_ty(hidden_ty);
874+
}
875+
}
876+
let expanded_ty = Ty::new_coroutine_witness(self.tcx, def_id, args);
877+
self.expanded_cache.insert((def_id, args), expanded_ty);
878+
expanded_ty
879+
}
880+
};
858881
if self.check_recursion {
859882
self.seen_opaque_tys.remove(&def_id);
860883
}
@@ -1426,6 +1449,7 @@ pub fn reveal_opaque_types_in_bounds<'tcx>(
14261449
check_recursion: false,
14271450
expand_coroutines: false,
14281451
tcx,
1452+
inspect_coroutine_fields: InspectCoroutineFields::No,
14291453
};
14301454
val.fold_with(&mut visitor)
14311455
}

tests/ui/lifetimes/issue-76168-hr-outlives-3.rs

-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ async fn wrapper<F>(f: F)
77
//~^ ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32`
88
//~| ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32`
99
//~| ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32`
10-
//~| ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32`
1110
where
1211
F:,
1312
for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a,

tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr

+4-19
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | / async fn wrapper<F>(f: F)
55
LL | |
66
LL | |
77
LL | |
8-
... |
8+
LL | | where
99
LL | | F:,
1010
LL | | for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a,
1111
| |______________________________________________________________________________^ expected an `FnOnce(&'a mut i32)` closure, found `i32`
@@ -21,7 +21,7 @@ LL | async fn wrapper<F>(f: F)
2121
= help: the trait `for<'a> FnOnce<(&'a mut i32,)>` is not implemented for `i32`
2222

2323
error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32`
24-
--> $DIR/issue-76168-hr-outlives-3.rs:14:1
24+
--> $DIR/issue-76168-hr-outlives-3.rs:13:1
2525
|
2626
LL | / {
2727
LL | |
@@ -39,28 +39,13 @@ LL | / async fn wrapper<F>(f: F)
3939
LL | |
4040
LL | |
4141
LL | |
42-
... |
42+
LL | | where
4343
LL | | F:,
4444
LL | | for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a,
4545
| |______________________________________________________________________________^ expected an `FnOnce(&'a mut i32)` closure, found `i32`
4646
|
4747
= help: the trait `for<'a> FnOnce<(&'a mut i32,)>` is not implemented for `i32`
4848

49-
error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32`
50-
--> $DIR/issue-76168-hr-outlives-3.rs:6:1
51-
|
52-
LL | / async fn wrapper<F>(f: F)
53-
LL | |
54-
LL | |
55-
LL | |
56-
... |
57-
LL | | F:,
58-
LL | | for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a,
59-
| |______________________________________________________________________________^ expected an `FnOnce(&'a mut i32)` closure, found `i32`
60-
|
61-
= help: the trait `for<'a> FnOnce<(&'a mut i32,)>` is not implemented for `i32`
62-
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
63-
64-
error: aborting due to 5 previous errors
49+
error: aborting due to 4 previous errors
6550

6651
For more information about this error, try `rustc --explain E0277`.

tests/ui/type-alias-impl-trait/indirect-recursion-issue-112047.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// edition: 2021
2+
// build-fail
23

34
#![feature(impl_trait_in_assoc_type)]
45

tests/ui/type-alias-impl-trait/indirect-recursion-issue-112047.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
error[E0733]: recursion in an async block requires boxing
2-
--> $DIR/indirect-recursion-issue-112047.rs:21:9
2+
--> $DIR/indirect-recursion-issue-112047.rs:22:9
33
|
44
LL | async move { recur(self).await; }
55
| ^^^^^^^^^^^^^-----------------^^^
66
| |
77
| recursive call here
88
|
99
note: which leads to this async fn
10-
--> $DIR/indirect-recursion-issue-112047.rs:13:1
10+
--> $DIR/indirect-recursion-issue-112047.rs:14:1
1111
|
1212
LL | async fn recur(t: impl Recur) {
1313
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

0 commit comments

Comments
 (0)