Skip to content

Commit 6035a3a

Browse files
authored
Unrolled build for rust-lang#119417
Rollup merge of rust-lang#119417 - compiler-errors:closure-checking, r=davidtwco Uplift some miscellaneous coroutine-specific machinery into `check_closure` This PR uplifts some of the logic in `check_fn` that is specific to checking coroutines, which always flows through `check_closure`. This is just some miscellaneous clean up that I've wanted to do, especially because I'm poking around this code to make it work for async closures.
2 parents 4c5ce1f + 7eeaaa2 commit 6035a3a

File tree

10 files changed

+150
-141
lines changed

10 files changed

+150
-141
lines changed

compiler/rustc_hir_typeck/src/check.rs

+3-63
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
2828
pub(super) fn check_fn<'a, 'tcx>(
2929
fcx: &mut FnCtxt<'a, 'tcx>,
3030
fn_sig: ty::FnSig<'tcx>,
31+
coroutine_types: Option<CoroutineTypes<'tcx>>,
3132
decl: &'tcx hir::FnDecl<'tcx>,
3233
fn_def_id: LocalDefId,
3334
body: &'tcx hir::Body<'tcx>,
34-
closure_kind: Option<hir::ClosureKind>,
3535
params_can_be_unsized: bool,
3636
) -> Option<CoroutineTypes<'tcx>> {
3737
let fn_id = fcx.tcx.local_def_id_to_hir_id(fn_def_id);
@@ -49,54 +49,13 @@ pub(super) fn check_fn<'a, 'tcx>(
4949
fcx.param_env,
5050
));
5151

52+
fcx.coroutine_types = coroutine_types;
5253
fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
5354

5455
let span = body.value.span;
5556

5657
forbid_intrinsic_abi(tcx, span, fn_sig.abi);
5758

58-
if let Some(hir::ClosureKind::Coroutine(kind)) = closure_kind {
59-
let yield_ty = match kind {
60-
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)
61-
| hir::CoroutineKind::Coroutine(_) => {
62-
let yield_ty = fcx.next_ty_var(TypeVariableOrigin {
63-
kind: TypeVariableOriginKind::TypeInference,
64-
span,
65-
});
66-
fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
67-
yield_ty
68-
}
69-
// HACK(-Ztrait-solver=next): In the *old* trait solver, we must eagerly
70-
// guide inference on the yield type so that we can handle `AsyncIterator`
71-
// in this block in projection correctly. In the new trait solver, it is
72-
// not a problem.
73-
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _) => {
74-
let yield_ty = fcx.next_ty_var(TypeVariableOrigin {
75-
kind: TypeVariableOriginKind::TypeInference,
76-
span,
77-
});
78-
fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
79-
80-
Ty::new_adt(
81-
tcx,
82-
tcx.adt_def(tcx.require_lang_item(hir::LangItem::Poll, Some(span))),
83-
tcx.mk_args(&[Ty::new_adt(
84-
tcx,
85-
tcx.adt_def(tcx.require_lang_item(hir::LangItem::Option, Some(span))),
86-
tcx.mk_args(&[yield_ty.into()]),
87-
)
88-
.into()]),
89-
)
90-
}
91-
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) => Ty::new_unit(tcx),
92-
};
93-
94-
// Resume type defaults to `()` if the coroutine has no argument.
95-
let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| Ty::new_unit(tcx));
96-
97-
fcx.resume_yield_tys = Some((resume_ty, yield_ty));
98-
}
99-
10059
GatherLocalsVisitor::new(fcx).visit_body(body);
10160

10261
// C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
@@ -147,25 +106,6 @@ pub(super) fn check_fn<'a, 'tcx>(
147106
fcx.require_type_is_sized(declared_ret_ty, return_or_body_span, traits::SizedReturnType);
148107
fcx.check_return_expr(body.value, false);
149108

150-
// We insert the deferred_coroutine_interiors entry after visiting the body.
151-
// This ensures that all nested coroutines appear before the entry of this coroutine.
152-
// resolve_coroutine_interiors relies on this property.
153-
let coroutine_ty = if let Some(hir::ClosureKind::Coroutine(coroutine_kind)) = closure_kind {
154-
let interior = fcx
155-
.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span });
156-
fcx.deferred_coroutine_interiors.borrow_mut().push((
157-
fn_def_id,
158-
body.id(),
159-
interior,
160-
coroutine_kind,
161-
));
162-
163-
let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap();
164-
Some(CoroutineTypes { resume_ty, yield_ty, interior })
165-
} else {
166-
None
167-
};
168-
169109
// Finalize the return check by taking the LUB of the return types
170110
// we saw and assigning it to the expected return type. This isn't
171111
// really expected to fail, since the coercions would have failed
@@ -201,7 +141,7 @@ pub(super) fn check_fn<'a, 'tcx>(
201141
check_lang_start_fn(tcx, fn_sig, fn_def_id);
202142
}
203143

204-
coroutine_ty
144+
fcx.coroutine_types
205145
}
206146

207147
fn check_panic_info_fn(tcx: TyCtxt<'_>, fn_id: LocalDefId, fn_sig: ty::FnSig<'_>) {

compiler/rustc_hir_typeck/src/closure.rs

+129-58
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
7272
opt_kind: Option<ty::ClosureKind>,
7373
expected_sig: Option<ExpectedSig<'tcx>>,
7474
) -> Ty<'tcx> {
75-
let body = self.tcx.hir().body(closure.body);
75+
let tcx = self.tcx;
76+
let body = tcx.hir().body(closure.body);
7677

7778
trace!("decl = {:#?}", closure.fn_decl);
7879
let expr_def_id = closure.def_id;
@@ -83,81 +84,151 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
8384

8485
debug!(?bound_sig, ?liberated_sig);
8586

87+
// FIXME: We could probably actually just unify this further --
88+
// instead of having a `FnSig` and a `Option<CoroutineTypes>`,
89+
// we can have a `ClosureSignature { Coroutine { .. }, Closure { .. } }`,
90+
// similar to how `ty::GenSig` is a distinct data structure.
91+
let coroutine_types = match closure.kind {
92+
hir::ClosureKind::Closure => None,
93+
hir::ClosureKind::Coroutine(kind) => {
94+
let yield_ty = match kind {
95+
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)
96+
| hir::CoroutineKind::Coroutine(_) => {
97+
let yield_ty = self.next_ty_var(TypeVariableOrigin {
98+
kind: TypeVariableOriginKind::TypeInference,
99+
span: expr_span,
100+
});
101+
self.require_type_is_sized(yield_ty, expr_span, traits::SizedYieldType);
102+
yield_ty
103+
}
104+
// HACK(-Ztrait-solver=next): In the *old* trait solver, we must eagerly
105+
// guide inference on the yield type so that we can handle `AsyncIterator`
106+
// in this block in projection correctly. In the new trait solver, it is
107+
// not a problem.
108+
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _) => {
109+
let yield_ty = self.next_ty_var(TypeVariableOrigin {
110+
kind: TypeVariableOriginKind::TypeInference,
111+
span: expr_span,
112+
});
113+
self.require_type_is_sized(yield_ty, expr_span, traits::SizedYieldType);
114+
115+
Ty::new_adt(
116+
tcx,
117+
tcx.adt_def(
118+
tcx.require_lang_item(hir::LangItem::Poll, Some(expr_span)),
119+
),
120+
tcx.mk_args(&[Ty::new_adt(
121+
tcx,
122+
tcx.adt_def(
123+
tcx.require_lang_item(hir::LangItem::Option, Some(expr_span)),
124+
),
125+
tcx.mk_args(&[yield_ty.into()]),
126+
)
127+
.into()]),
128+
)
129+
}
130+
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) => {
131+
tcx.types.unit
132+
}
133+
};
134+
135+
// Resume type defaults to `()` if the coroutine has no argument.
136+
let resume_ty = liberated_sig.inputs().get(0).copied().unwrap_or(tcx.types.unit);
137+
138+
Some(CoroutineTypes { resume_ty, yield_ty })
139+
}
140+
};
141+
86142
let mut fcx = FnCtxt::new(self, self.param_env, closure.def_id);
87-
let coroutine_types = check_fn(
143+
check_fn(
88144
&mut fcx,
89145
liberated_sig,
146+
coroutine_types,
90147
closure.fn_decl,
91148
expr_def_id,
92149
body,
93-
Some(closure.kind),
94150
// Closure "rust-call" ABI doesn't support unsized params
95151
false,
96152
);
97153

98-
let parent_args = GenericArgs::identity_for_item(
99-
self.tcx,
100-
self.tcx.typeck_root_def_id(expr_def_id.to_def_id()),
101-
);
154+
let parent_args =
155+
GenericArgs::identity_for_item(tcx, tcx.typeck_root_def_id(expr_def_id.to_def_id()));
102156

103157
let tupled_upvars_ty = self.next_root_ty_var(TypeVariableOrigin {
104158
kind: TypeVariableOriginKind::ClosureSynthetic,
105-
span: self.tcx.def_span(expr_def_id),
106-
});
107-
108-
if let Some(CoroutineTypes { resume_ty, yield_ty, interior }) = coroutine_types {
109-
let coroutine_args = ty::CoroutineArgs::new(
110-
self.tcx,
111-
ty::CoroutineArgsParts {
112-
parent_args,
113-
resume_ty,
114-
yield_ty,
115-
return_ty: liberated_sig.output(),
116-
witness: interior,
117-
tupled_upvars_ty,
118-
},
119-
);
120-
121-
return Ty::new_coroutine(self.tcx, expr_def_id.to_def_id(), coroutine_args.args);
122-
}
123-
124-
// Tuple up the arguments and insert the resulting function type into
125-
// the `closures` table.
126-
let sig = bound_sig.map_bound(|sig| {
127-
self.tcx.mk_fn_sig(
128-
[Ty::new_tup(self.tcx, sig.inputs())],
129-
sig.output(),
130-
sig.c_variadic,
131-
sig.unsafety,
132-
sig.abi,
133-
)
159+
span: expr_span,
134160
});
135161

136-
debug!(?sig, ?opt_kind);
137-
138-
let closure_kind_ty = match opt_kind {
139-
Some(kind) => Ty::from_closure_kind(self.tcx, kind),
162+
match closure.kind {
163+
hir::ClosureKind::Closure => {
164+
assert_eq!(coroutine_types, None);
165+
// Tuple up the arguments and insert the resulting function type into
166+
// the `closures` table.
167+
let sig = bound_sig.map_bound(|sig| {
168+
tcx.mk_fn_sig(
169+
[Ty::new_tup(tcx, sig.inputs())],
170+
sig.output(),
171+
sig.c_variadic,
172+
sig.unsafety,
173+
sig.abi,
174+
)
175+
});
140176

141-
// Create a type variable (for now) to represent the closure kind.
142-
// It will be unified during the upvar inference phase (`upvar.rs`)
143-
None => self.next_root_ty_var(TypeVariableOrigin {
144-
// FIXME(eddyb) distinguish closure kind inference variables from the rest.
145-
kind: TypeVariableOriginKind::ClosureSynthetic,
146-
span: expr_span,
147-
}),
148-
};
177+
debug!(?sig, ?opt_kind);
178+
179+
let closure_kind_ty = match opt_kind {
180+
Some(kind) => Ty::from_closure_kind(tcx, kind),
181+
182+
// Create a type variable (for now) to represent the closure kind.
183+
// It will be unified during the upvar inference phase (`upvar.rs`)
184+
None => self.next_root_ty_var(TypeVariableOrigin {
185+
// FIXME(eddyb) distinguish closure kind inference variables from the rest.
186+
kind: TypeVariableOriginKind::ClosureSynthetic,
187+
span: expr_span,
188+
}),
189+
};
190+
191+
let closure_args = ty::ClosureArgs::new(
192+
tcx,
193+
ty::ClosureArgsParts {
194+
parent_args,
195+
closure_kind_ty,
196+
closure_sig_as_fn_ptr_ty: Ty::new_fn_ptr(tcx, sig),
197+
tupled_upvars_ty,
198+
},
199+
);
149200

150-
let closure_args = ty::ClosureArgs::new(
151-
self.tcx,
152-
ty::ClosureArgsParts {
153-
parent_args,
154-
closure_kind_ty,
155-
closure_sig_as_fn_ptr_ty: Ty::new_fn_ptr(self.tcx, sig),
156-
tupled_upvars_ty,
157-
},
158-
);
201+
Ty::new_closure(tcx, expr_def_id.to_def_id(), closure_args.args)
202+
}
203+
hir::ClosureKind::Coroutine(_) => {
204+
let Some(CoroutineTypes { resume_ty, yield_ty }) = coroutine_types else {
205+
bug!("expected coroutine to have yield/resume types");
206+
};
207+
let interior = fcx.next_ty_var(TypeVariableOrigin {
208+
kind: TypeVariableOriginKind::MiscVariable,
209+
span: body.value.span,
210+
});
211+
fcx.deferred_coroutine_interiors.borrow_mut().push((
212+
expr_def_id,
213+
body.id(),
214+
interior,
215+
));
216+
217+
let coroutine_args = ty::CoroutineArgs::new(
218+
tcx,
219+
ty::CoroutineArgsParts {
220+
parent_args,
221+
resume_ty,
222+
yield_ty,
223+
return_ty: liberated_sig.output(),
224+
witness: interior,
225+
tupled_upvars_ty,
226+
},
227+
);
159228

160-
Ty::new_closure(self.tcx, expr_def_id.to_def_id(), closure_args.args)
229+
Ty::new_coroutine(tcx, expr_def_id.to_def_id(), coroutine_args.args)
230+
}
231+
}
161232
}
162233

163234
/// Given the expected type, figures out what it can about this closure we

compiler/rustc_hir_typeck/src/expr.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use crate::errors::{
1515
use crate::fatally_break_rust;
1616
use crate::method::SelfSource;
1717
use crate::type_error_struct;
18+
use crate::CoroutineTypes;
1819
use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
1920
use crate::{
2021
report_unexpected_variant_res, BreakableCtxt, Diverges, FnCtxt, Needs,
@@ -3163,8 +3164,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
31633164
value: &'tcx hir::Expr<'tcx>,
31643165
expr: &'tcx hir::Expr<'tcx>,
31653166
) -> Ty<'tcx> {
3166-
match self.resume_yield_tys {
3167-
Some((resume_ty, yield_ty)) => {
3167+
match self.coroutine_types {
3168+
Some(CoroutineTypes { resume_ty, yield_ty }) => {
31683169
self.check_expr_coercible_to_type(value, yield_ty, None);
31693170

31703171
resume_ty

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
534534
let coroutines = std::mem::take(&mut *self.deferred_coroutine_interiors.borrow_mut());
535535
debug!(?coroutines);
536536

537-
for &(expr_def_id, body_id, interior, _) in coroutines.iter() {
537+
for &(expr_def_id, body_id, interior) in coroutines.iter() {
538538
debug!(?expr_def_id);
539539

540540
// Create the `CoroutineWitness` type that we will unify with `interior`.

compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ mod checks;
55
mod suggestions;
66

77
use crate::coercion::DynamicCoerceMany;
8-
use crate::{Diverges, EnclosingBreakables, Inherited};
8+
use crate::{CoroutineTypes, Diverges, EnclosingBreakables, Inherited};
99
use rustc_errors::{DiagCtxt, ErrorGuaranteed};
1010
use rustc_hir as hir;
1111
use rustc_hir::def_id::{DefId, LocalDefId};
@@ -68,7 +68,7 @@ pub struct FnCtxt<'a, 'tcx> {
6868
/// First span of a return site that we find. Used in error messages.
6969
pub(super) ret_coercion_span: Cell<Option<Span>>,
7070

71-
pub(super) resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>,
71+
pub(super) coroutine_types: Option<CoroutineTypes<'tcx>>,
7272

7373
/// Whether the last checked node generates a divergence (e.g.,
7474
/// `return` will set this to `Always`). In general, when entering
@@ -122,7 +122,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
122122
err_count_on_creation: inh.tcx.dcx().err_count(),
123123
ret_coercion: None,
124124
ret_coercion_span: Cell::new(None),
125-
resume_yield_tys: None,
125+
coroutine_types: None,
126126
diverges: Cell::new(Diverges::Maybe),
127127
enclosing_breakables: RefCell::new(EnclosingBreakables {
128128
stack: Vec::new(),

compiler/rustc_hir_typeck/src/inherited.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,7 @@ pub struct Inherited<'tcx> {
5555

5656
pub(super) deferred_asm_checks: RefCell<Vec<(&'tcx hir::InlineAsm<'tcx>, hir::HirId)>>,
5757

58-
pub(super) deferred_coroutine_interiors:
59-
RefCell<Vec<(LocalDefId, hir::BodyId, Ty<'tcx>, hir::CoroutineKind)>>,
58+
pub(super) deferred_coroutine_interiors: RefCell<Vec<(LocalDefId, hir::BodyId, Ty<'tcx>)>>,
6059

6160
/// Whenever we introduce an adjustment from `!` into a type variable,
6261
/// we record that type variable here. This is later used to inform

0 commit comments

Comments
 (0)