Skip to content

Commit e15d6f9

Browse files
authored
Rollup merge of rust-lang#123993 - compiler-errors:coroutine-obl, r=lcnr
Do `check_coroutine_obligations` once per typeck root We only need to do `check_coroutine_obligations` once per typeck root, especially since the new solver can't really (easily) associate which obligations correspond to which coroutines. This requires us to move the checks for sized coroutine fields into `mir_coroutine_witnesses`, but that's fine imo. r? lcnr
2 parents 2d7d480 + a8c9a0b commit e15d6f9

File tree

13 files changed

+148
-112
lines changed

13 files changed

+148
-112
lines changed

compiler/rustc_hir_analysis/src/check/check.rs

+11-36
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,10 @@ use rustc_hir as hir;
1010
use rustc_hir::def::{CtorKind, DefKind};
1111
use rustc_hir::Node;
1212
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
13-
use rustc_infer::traits::{Obligation, TraitEngineExt as _};
13+
use rustc_infer::traits::Obligation;
1414
use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
1515
use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
1616
use rustc_middle::middle::stability::EvalResult;
17-
use rustc_middle::traits::ObligationCauseCode;
1817
use rustc_middle::ty::fold::BottomUpFolder;
1918
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
2019
use rustc_middle::ty::util::{Discr, InspectCoroutineFields, IntTypeExt};
@@ -24,10 +23,10 @@ use rustc_middle::ty::{
2423
};
2524
use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
2625
use rustc_target::abi::FieldIdx;
26+
use rustc_trait_selection::traits;
2727
use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedDirective;
2828
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
2929
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
30-
use rustc_trait_selection::traits::{self, TraitEngine, TraitEngineExt as _};
3130
use rustc_type_ir::fold::TypeFoldable;
3231

3332
use std::cell::LazyCell;
@@ -1715,55 +1714,31 @@ fn opaque_type_cycle_error(
17151714
err.emit()
17161715
}
17171716

1718-
// FIXME(@lcnr): This should not be computed per coroutine, but instead once for
1719-
// each typeck root.
17201717
pub(super) fn check_coroutine_obligations(
17211718
tcx: TyCtxt<'_>,
17221719
def_id: LocalDefId,
17231720
) -> Result<(), ErrorGuaranteed> {
1724-
debug_assert!(tcx.is_coroutine(def_id.to_def_id()));
1721+
debug_assert!(!tcx.is_typeck_child(def_id.to_def_id()));
17251722

1726-
let typeck = tcx.typeck(def_id);
1727-
let param_env = tcx.param_env(typeck.hir_owner.def_id);
1723+
let typeck_results = tcx.typeck(def_id);
1724+
let param_env = tcx.param_env(def_id);
17281725

1729-
let coroutine_interior_predicates = &typeck.coroutine_interior_predicates[&def_id];
1730-
debug!(?coroutine_interior_predicates);
1726+
debug!(?typeck_results.coroutine_stalled_predicates);
17311727

17321728
let infcx = tcx
17331729
.infer_ctxt()
17341730
// typeck writeback gives us predicates with their regions erased.
17351731
// As borrowck already has checked lifetimes, we do not need to do it again.
17361732
.ignoring_regions()
1737-
// Bind opaque types to type checking root, as they should have been checked by borrowck,
1738-
// but may show up in some cases, like when (root) obligations are stalled in the new solver.
1739-
.with_opaque_type_inference(typeck.hir_owner.def_id)
1733+
.with_opaque_type_inference(def_id)
17401734
.build();
17411735

1742-
let mut fulfillment_cx = <dyn TraitEngine<'_>>::new(&infcx);
1743-
for (predicate, cause) in coroutine_interior_predicates {
1744-
let obligation = Obligation::new(tcx, cause.clone(), param_env, *predicate);
1745-
fulfillment_cx.register_predicate_obligation(&infcx, obligation);
1746-
}
1747-
1748-
if (tcx.features().unsized_locals || tcx.features().unsized_fn_params)
1749-
&& let Some(coroutine) = tcx.mir_coroutine_witnesses(def_id)
1750-
{
1751-
for field_ty in coroutine.field_tys.iter() {
1752-
fulfillment_cx.register_bound(
1753-
&infcx,
1754-
param_env,
1755-
field_ty.ty,
1756-
tcx.require_lang_item(hir::LangItem::Sized, Some(field_ty.source_info.span)),
1757-
ObligationCause::new(
1758-
field_ty.source_info.span,
1759-
def_id,
1760-
ObligationCauseCode::SizedCoroutineInterior(def_id),
1761-
),
1762-
);
1763-
}
1736+
let ocx = ObligationCtxt::new(&infcx);
1737+
for (predicate, cause) in &typeck_results.coroutine_stalled_predicates {
1738+
ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, *predicate));
17641739
}
17651740

1766-
let errors = fulfillment_cx.select_all_or_error(&infcx);
1741+
let errors = ocx.select_all_or_error();
17671742
debug!(?errors);
17681743
if !errors.is_empty() {
17691744
return Err(infcx.err_ctxt().report_fulfillment_errors(errors));

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -588,12 +588,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
588588
obligations
589589
.extend(self.fulfillment_cx.borrow_mut().drain_unstalled_obligations(&self.infcx));
590590

591-
let obligations = obligations.into_iter().map(|o| (o.predicate, o.cause)).collect();
592-
debug!(?obligations);
593-
self.typeck_results
594-
.borrow_mut()
595-
.coroutine_interior_predicates
596-
.insert(expr_def_id, obligations);
591+
let obligations = obligations.into_iter().map(|o| (o.predicate, o.cause));
592+
self.typeck_results.borrow_mut().coroutine_stalled_predicates.extend(obligations);
597593
}
598594
}
599595

compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use rustc_hir::{
2323
};
2424
use rustc_hir_analysis::collect::suggest_impl_trait;
2525
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
26-
use rustc_infer::traits::{self};
26+
use rustc_infer::traits;
2727
use rustc_middle::lint::in_external_macro;
2828
use rustc_middle::middle::stability::EvalResult;
2929
use rustc_middle::ty::print::with_no_trimmed_paths;

compiler/rustc_hir_typeck/src/writeback.rs

+4-9
Original file line numberDiff line numberDiff line change
@@ -551,15 +551,10 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
551551
fn visit_coroutine_interior(&mut self) {
552552
let fcx_typeck_results = self.fcx.typeck_results.borrow();
553553
assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
554-
self.tcx().with_stable_hashing_context(move |ref hcx| {
555-
for (&expr_def_id, predicates) in
556-
fcx_typeck_results.coroutine_interior_predicates.to_sorted(hcx, false).into_iter()
557-
{
558-
let predicates =
559-
self.resolve(predicates.clone(), &self.fcx.tcx.def_span(expr_def_id));
560-
self.typeck_results.coroutine_interior_predicates.insert(expr_def_id, predicates);
561-
}
562-
})
554+
for (predicate, cause) in &fcx_typeck_results.coroutine_stalled_predicates {
555+
let (predicate, cause) = self.resolve((*predicate, cause.clone()), &cause.span);
556+
self.typeck_results.coroutine_stalled_predicates.insert((predicate, cause));
557+
}
563558
}
564559

565560
#[instrument(skip(self), level = "debug")]

compiler/rustc_interface/src/passes.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -759,7 +759,9 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
759759
tcx.hir().par_body_owners(|def_id| {
760760
if tcx.is_coroutine(def_id.to_def_id()) {
761761
tcx.ensure().mir_coroutine_witnesses(def_id);
762-
tcx.ensure().check_coroutine_obligations(def_id);
762+
tcx.ensure().check_coroutine_obligations(
763+
tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(),
764+
);
763765
}
764766
});
765767
sess.time("layout_testing", || layout_test::test_layout(tcx));

compiler/rustc_middle/src/ty/typeck_results.rs

+4-7
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,8 @@ use crate::{
77
GenericArgs, GenericArgsRef, Ty, UserArgs,
88
},
99
};
10-
use rustc_data_structures::{
11-
fx::FxIndexMap,
12-
unord::{ExtendUnord, UnordItems, UnordSet},
13-
};
10+
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
11+
use rustc_data_structures::unord::{ExtendUnord, UnordItems, UnordSet};
1412
use rustc_errors::ErrorGuaranteed;
1513
use rustc_hir::{
1614
self as hir,
@@ -201,8 +199,7 @@ pub struct TypeckResults<'tcx> {
201199

202200
/// Stores the predicates that apply on coroutine witness types.
203201
/// formatting modified file tests/ui/coroutine/retain-resume-ref.rs
204-
pub coroutine_interior_predicates:
205-
LocalDefIdMap<Vec<(ty::Predicate<'tcx>, ObligationCause<'tcx>)>>,
202+
pub coroutine_stalled_predicates: FxIndexSet<(ty::Predicate<'tcx>, ObligationCause<'tcx>)>,
206203

207204
/// We sometimes treat byte string literals (which are of type `&[u8; N]`)
208205
/// as `&[u8]`, depending on the pattern in which they are used.
@@ -243,7 +240,7 @@ impl<'tcx> TypeckResults<'tcx> {
243240
closure_min_captures: Default::default(),
244241
closure_fake_reads: Default::default(),
245242
rvalue_scopes: Default::default(),
246-
coroutine_interior_predicates: Default::default(),
243+
coroutine_stalled_predicates: Default::default(),
247244
treat_byte_string_as_slice: Default::default(),
248245
closure_size_eval: Default::default(),
249246
offset_of_data: Default::default(),

compiler/rustc_mir_transform/src/coroutine.rs

+40
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ use rustc_span::symbol::sym;
8080
use rustc_span::Span;
8181
use rustc_target::abi::{FieldIdx, VariantIdx};
8282
use rustc_target::spec::PanicStrategy;
83+
use rustc_trait_selection::infer::TyCtxtInferExt as _;
84+
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
85+
use rustc_trait_selection::traits::ObligationCtxt;
86+
use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
8387
use std::{iter, ops};
8488

8589
pub struct StateTransform;
@@ -1584,10 +1588,46 @@ pub(crate) fn mir_coroutine_witnesses<'tcx>(
15841588
let (_, coroutine_layout, _) = compute_layout(liveness_info, body);
15851589

15861590
check_suspend_tys(tcx, &coroutine_layout, body);
1591+
check_field_tys_sized(tcx, &coroutine_layout, def_id);
15871592

15881593
Some(coroutine_layout)
15891594
}
15901595

1596+
fn check_field_tys_sized<'tcx>(
1597+
tcx: TyCtxt<'tcx>,
1598+
coroutine_layout: &CoroutineLayout<'tcx>,
1599+
def_id: LocalDefId,
1600+
) {
1601+
// No need to check if unsized_locals/unsized_fn_params is disabled,
1602+
// since we will error during typeck.
1603+
if !tcx.features().unsized_locals && !tcx.features().unsized_fn_params {
1604+
return;
1605+
}
1606+
1607+
let infcx = tcx.infer_ctxt().ignoring_regions().build();
1608+
let param_env = tcx.param_env(def_id);
1609+
1610+
let ocx = ObligationCtxt::new(&infcx);
1611+
for field_ty in &coroutine_layout.field_tys {
1612+
ocx.register_bound(
1613+
ObligationCause::new(
1614+
field_ty.source_info.span,
1615+
def_id,
1616+
ObligationCauseCode::SizedCoroutineInterior(def_id),
1617+
),
1618+
param_env,
1619+
field_ty.ty,
1620+
tcx.require_lang_item(hir::LangItem::Sized, Some(field_ty.source_info.span)),
1621+
);
1622+
}
1623+
1624+
let errors = ocx.select_all_or_error();
1625+
debug!(?errors);
1626+
if !errors.is_empty() {
1627+
infcx.err_ctxt().report_fulfillment_errors(errors);
1628+
}
1629+
}
1630+
15911631
impl<'tcx> MirPass<'tcx> for StateTransform {
15921632
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
15931633
let Some(old_yield_ty) = body.yield_ty() else {

compiler/rustc_span/src/source_map.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use rustc_data_structures::sync::{IntoDynSyncSend, MappedReadGuard, ReadGuard, R
1414
use rustc_data_structures::unhash::UnhashMap;
1515
use std::fs;
1616
use std::io::{self, BorrowedBuf, Read};
17-
use std::path::{self};
17+
use std::path;
1818

1919
#[cfg(test)]
2020
mod tests;

tests/crashes/122552.rs

-10
This file was deleted.

tests/ui/coroutine/clone-impl.rs

+19-5
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,18 @@
66

77
struct NonClone;
88

9-
fn main() {
9+
fn test1() {
1010
let copyable: u32 = 123;
11-
let clonable_0: Vec<u32> = Vec::new();
12-
let clonable_1: Vec<u32> = Vec::new();
13-
let non_clonable: NonClone = NonClone;
14-
1511
let gen_copy_0 = move || {
1612
yield;
1713
drop(copyable);
1814
};
1915
check_copy(&gen_copy_0);
2016
check_clone(&gen_copy_0);
17+
}
18+
19+
fn test2() {
20+
let copyable: u32 = 123;
2121
let gen_copy_1 = move || {
2222
/*
2323
let v = vec!['a'];
@@ -33,6 +33,10 @@ fn main() {
3333
};
3434
check_copy(&gen_copy_1);
3535
check_clone(&gen_copy_1);
36+
}
37+
38+
fn test3() {
39+
let clonable_0: Vec<u32> = Vec::new();
3640
let gen_clone_0 = move || {
3741
let v = vec!['a'];
3842
yield;
@@ -43,6 +47,10 @@ fn main() {
4347
//~^ ERROR the trait bound `Vec<u32>: Copy` is not satisfied
4448
//~| ERROR the trait bound `Vec<char>: Copy` is not satisfied
4549
check_clone(&gen_clone_0);
50+
}
51+
52+
fn test4() {
53+
let clonable_1: Vec<u32> = Vec::new();
4654
let gen_clone_1 = move || {
4755
let v = vec!['a'];
4856
/*
@@ -59,6 +67,10 @@ fn main() {
5967
//~^ ERROR the trait bound `Vec<u32>: Copy` is not satisfied
6068
//~| ERROR the trait bound `Vec<char>: Copy` is not satisfied
6169
check_clone(&gen_clone_1);
70+
}
71+
72+
fn test5() {
73+
let non_clonable: NonClone = NonClone;
6274
let gen_non_clone = move || {
6375
yield;
6476
drop(non_clonable);
@@ -71,3 +83,5 @@ fn main() {
7183

7284
fn check_copy<T: Copy>(_x: &T) {}
7385
fn check_clone<T: Clone>(_x: &T) {}
86+
87+
fn main() {}

0 commit comments

Comments
 (0)