Skip to content

Commit

Permalink
Add CoroutineClosure to TyKind, AggregateKind, UpvarArgs
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Feb 6, 2024
1 parent a204217 commit c567edd
Show file tree
Hide file tree
Showing 91 changed files with 579 additions and 101 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1472,7 +1472,7 @@ fn suggest_ampmut<'tcx>(
}

fn is_closure_or_coroutine(ty: Ty<'_>) -> bool {
ty.is_closure() || ty.is_coroutine()
ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure()
}

/// Given a field that needs to be mutable, returns a span where the " mut " could go.
Expand Down
10 changes: 8 additions & 2 deletions compiler/rustc_borrowck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1303,7 +1303,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// moved into the closure and subsequently used by the closure,
// in order to populate our used_mut set.
match **aggregate_kind {
AggregateKind::Closure(def_id, _) | AggregateKind::Coroutine(def_id, _) => {
AggregateKind::Closure(def_id, _)
| AggregateKind::CoroutineClosure(def_id, _)
| AggregateKind::Coroutine(def_id, _) => {
let def_id = def_id.expect_local();
let BorrowCheckResult { used_mut_upvars, .. } =
self.infcx.tcx.mir_borrowck(def_id);
Expand Down Expand Up @@ -1609,6 +1611,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
| ty::FnPtr(_)
| ty::Dynamic(_, _, _)
| ty::Closure(_, _)
| ty::CoroutineClosure(_, _)
| ty::Coroutine(_, _)
| ty::CoroutineWitness(..)
| ty::Never
Expand All @@ -1633,7 +1636,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
return;
}
}
ty::Closure(_, _) | ty::Coroutine(_, _) | ty::Tuple(_) => (),
ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(_, _)
| ty::Tuple(_) => (),
ty::Bool
| ty::Char
| ty::Int(_)
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/path_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ pub(crate) fn is_upvar_field_projection<'tcx>(
match place_ref.last_projection() {
Some((place_base, ProjectionElem::Field(field, _ty))) => {
let base_ty = place_base.ty(body, tcx).ty;
if (base_ty.is_closure() || base_ty.is_coroutine())
if (base_ty.is_closure() || base_ty.is_coroutine() || base_ty.is_coroutine_closure())
&& (!by_ref || upvars[field.index()].is_by_ref())
{
Some(field)
Expand Down
33 changes: 29 additions & 4 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -808,6 +808,14 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
}),
};
}
ty::CoroutineClosure(_, args) => {
return match args.as_coroutine_closure().upvar_tys().get(field.index()) {
Some(&ty) => Ok(ty),
None => Err(FieldAccessError::OutOfRange {
field_count: args.as_coroutine_closure().upvar_tys().len(),
}),
};
}
ty::Coroutine(_, args) => {
// Only prefix fields (upvars and current state) are
// accessible without a variant index.
Expand Down Expand Up @@ -1875,6 +1883,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}),
}
}
AggregateKind::CoroutineClosure(_, args) => {
match args.as_coroutine_closure().upvar_tys().get(field_index.as_usize()) {
Some(ty) => Ok(*ty),
None => Err(FieldAccessError::OutOfRange {
field_count: args.as_coroutine_closure().upvar_tys().len(),
}),
}
}
AggregateKind::Array(ty) => Ok(ty),
AggregateKind::Tuple => {
unreachable!("This should have been covered in check_rvalues");
Expand Down Expand Up @@ -2478,6 +2494,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
AggregateKind::Tuple => None,
AggregateKind::Closure(_, _) => None,
AggregateKind::Coroutine(_, _) => None,
AggregateKind::CoroutineClosure(_, _) => None,
},
}
}
Expand Down Expand Up @@ -2705,7 +2722,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// desugaring. A closure gets desugared to a struct, and
// these extra requirements are basically like where
// clauses on the struct.
AggregateKind::Closure(def_id, args) | AggregateKind::Coroutine(def_id, args) => (
AggregateKind::Closure(def_id, args)
| AggregateKind::CoroutineClosure(def_id, args)
| AggregateKind::Coroutine(def_id, args) => (
def_id,
self.prove_closure_bounds(
tcx,
Expand Down Expand Up @@ -2754,10 +2773,16 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let typeck_root_args = ty::GenericArgs::identity_for_item(tcx, typeck_root_def_id);

let parent_args = match tcx.def_kind(def_id) {
DefKind::Closure if tcx.is_coroutine(def_id.to_def_id()) => {
args.as_coroutine().parent_args()
DefKind::Closure => {
// FIXME(async_closures): It's kind of icky to access HIR here.
match tcx.hir_node_by_def_id(def_id).expect_closure().kind {
hir::ClosureKind::Closure => args.as_closure().parent_args(),
hir::ClosureKind::Coroutine(_) => args.as_coroutine().parent_args(),
hir::ClosureKind::CoroutineClosure(_) => {
args.as_coroutine_closure().parent_args()
}
}
}
DefKind::Closure => args.as_closure().parent_args(),
DefKind::InlineConst => args.as_inline_const().parent_args(),
other => bug!("unexpected item {:?}", other),
};
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_gcc/src/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout
// FIXME(eddyb) producing readable type names for trait objects can result
// in problematically distinct types due to HRTB and subtyping (see #47638).
// ty::Dynamic(..) |
ty::Adt(..) | ty::Closure(..) | ty::Foreign(..) | ty::Coroutine(..) | ty::Str
ty::Adt(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Foreign(..) | ty::Coroutine(..) | ty::Str
if !cx.sess().fewer_names() =>
{
let mut name = with_no_trimmed_paths!(layout.ty.to_string());
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ fn uncached_llvm_type<'a, 'tcx>(
// FIXME(eddyb) producing readable type names for trait objects can result
// in problematically distinct types due to HRTB and subtyping (see #47638).
// ty::Dynamic(..) |
ty::Adt(..) | ty::Closure(..) | ty::Foreign(..) | ty::Coroutine(..) | ty::Str
ty::Adt(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Foreign(..) | ty::Coroutine(..) | ty::Str
// For performance reasons we use names only when emitting LLVM IR.
if !cx.sess().fewer_names() =>
{
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,9 @@ fn push_debuginfo_type_name<'tcx>(
// processing
visited.remove(&t);
}
ty::Closure(def_id, args) | ty::Coroutine(def_id, args, ..) => {
ty::Closure(def_id, args)
| ty::CoroutineClosure(def_id, args)
| ty::Coroutine(def_id, args, ..) => {
// Name will be "{closure_env#0}<T1, T2, ...>", "{coroutine_env#0}<T1, T2, ...>", or
// "{async_fn_env#0}<T1, T2, ...>", etc.
// In the case of cpp-like debuginfo, the name additionally gets wrapped inside of
Expand Down Expand Up @@ -768,6 +770,8 @@ fn push_closure_or_coroutine_name<'tcx>(

// Truncate the args to the length of the above generics. This will cut off
// anything closure- or coroutine-specific.
// FIXME(async_closures): This is probably not going to be correct w.r.t.
// multiple coroutine flavors. Maybe truncate to (parent + 1)?
let args = args.truncate_to(tcx, generics);
push_generic_params_internal(tcx, args, enclosing_fn_def_id, output, visited);
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_const_eval/src/const_eval/valtrees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
| ty::Infer(_)
// FIXME(oli-obk): we can probably encode closures just like structs
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(..)
| ty::CoroutineWitness(..) => Err(ValTreeCreationError::NonSupportedType),
}
Expand Down Expand Up @@ -301,6 +302,7 @@ pub fn valtree_to_const_value<'tcx>(
| ty::Placeholder(..)
| ty::Infer(_)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(..)
| ty::CoroutineWitness(..)
| ty::FnPtr(_)
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_const_eval/src/interpret/eval_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1007,6 +1007,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
| ty::CoroutineWitness(..)
| ty::Array(..)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Never
| ty::Error(_) => true,

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_const_eval/src/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
| ty::FnPtr(_)
| ty::Dynamic(_, _, _)
| ty::Closure(_, _)
| ty::CoroutineClosure(_, _)
| ty::Coroutine(_, _)
| ty::CoroutineWitness(..)
| ty::Never
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_const_eval/src/interpret/validity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
| ty::Str
| ty::Dynamic(..)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(..) => Ok(false),
// Some types only occur during typechecking, they have no layout.
// We should not see them here and we could not check them anyway.
Expand Down
22 changes: 22 additions & 0 deletions compiler/rustc_const_eval/src/transform/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
};
check_equal(self, location, f_ty);
}
ty::CoroutineClosure(_, args) => {
let args = args.as_coroutine_closure();
let Some(&f_ty) = args.upvar_tys().get(f.as_usize()) else {
fail_out_of_bounds(self, location);
return;
};
check_equal(self, location, f_ty);
}
&ty::Coroutine(def_id, args) => {
let f_ty = if let Some(var) = parent_ty.variant_index {
let gen_body = if def_id == self.body.source.def_id() {
Expand Down Expand Up @@ -861,6 +869,20 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}
}
AggregateKind::CoroutineClosure(_, args) => {
let upvars = args.as_coroutine_closure().upvar_tys();
if upvars.len() != fields.len() {
self.fail(
location,
"coroutine-closure has the wrong number of initialized fields",
);
}
for (src, dest) in std::iter::zip(fields, upvars) {
if !self.mir_assign_valid_types(src.ty(self.body, self.tcx), dest) {
self.fail(location, "coroutine-closure field has the wrong type");
}
}
}
},
Rvalue::Ref(_, BorrowKind::Fake, _) => {
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_const_eval/src/util/type_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
| ty::FnDef(def_id, args)
| ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. })
| ty::Closure(def_id, args)
| ty::CoroutineClosure(def_id, args)
| ty::Coroutine(def_id, args) => self.print_def_path(def_id, args),
ty::Foreign(def_id) => self.print_def_path(def_id, &[]),

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3703,6 +3703,7 @@ impl<'hir> Node<'hir> {
expect_generic_param, &'hir GenericParam<'hir>, Node::GenericParam(n), n;
expect_crate, &'hir Mod<'hir>, Node::Crate(n), n;
expect_infer, &'hir InferArg, Node::Infer(n), n;
expect_closure, &'hir Closure<'hir>, Node::Expr(Expr { kind: ExprKind::Closure(n), .. }), n;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ impl<'tcx> InherentCollect<'tcx> {
}
ty::FnDef(..)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(..)
| ty::CoroutineWitness(..)
| ty::Bound(..)
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_analysis/src/coherence/orphan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ fn do_orphan_check_impl<'tcx>(
| ty::Tuple(..) => (LocalImpl::Allow, NonlocalImpl::DisallowOther),

ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(..)
| ty::CoroutineWitness(..)
| ty::Bound(..)
Expand Down
8 changes: 7 additions & 1 deletion compiler/rustc_hir_analysis/src/collect/generics_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,13 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
ClosureKind::Coroutine(_) => {
&["<resume_ty>", "<yield_ty>", "<return_ty>", "<witness>", "<upvars>"][..]
}
ClosureKind::CoroutineClosure(_) => todo!(),
ClosureKind::CoroutineClosure(_) => &[
"<closure_kind>",
"<closure_signature_parts>",
"<upvars>",
"<bound_captures_by_ref>",
"<witness>",
][..],
};

params.extend(dummy_args.iter().map(|&arg| ty::GenericParamDef {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_analysis/src/variance/constraints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
// leaf type -- noop
}

ty::FnDef(..) | ty::Coroutine(..) | ty::Closure(..) => {
bug!("Unexpected closure type in variance computation");
ty::FnDef(..) | ty::Coroutine(..) | ty::Closure(..) | ty::CoroutineClosure(..) => {
bug!("Unexpected coroutine/closure type in variance computation");
}

ty::Ref(region, ty, mutbl) => {
Expand Down
12 changes: 5 additions & 7 deletions compiler/rustc_hir_typeck/src/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Check whether this is a call to a closure where we
// haven't yet decided on whether the closure is fn vs
// fnmut vs fnonce. If so, we have to defer further processing.
if self.closure_kind(args).is_none() {
if self.closure_kind(adjusted_ty).is_none() {
let closure_sig = args.as_closure().sig();
let closure_sig = self.instantiate_binder_with_fresh_vars(
call_expr.span,
Expand All @@ -160,10 +160,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
DeferredCallResolution {
call_expr,
callee_expr,
adjusted_ty,
closure_ty: adjusted_ty,
adjustments,
fn_sig: closure_sig,
closure_args: args,
},
);
return Some(CallStep::DeferredClosure(def_id, closure_sig));
Expand Down Expand Up @@ -886,10 +885,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub struct DeferredCallResolution<'tcx> {
call_expr: &'tcx hir::Expr<'tcx>,
callee_expr: &'tcx hir::Expr<'tcx>,
adjusted_ty: Ty<'tcx>,
closure_ty: Ty<'tcx>,
adjustments: Vec<Adjustment<'tcx>>,
fn_sig: ty::FnSig<'tcx>,
closure_args: GenericArgsRef<'tcx>,
}

impl<'a, 'tcx> DeferredCallResolution<'tcx> {
Expand All @@ -898,10 +896,10 @@ impl<'a, 'tcx> DeferredCallResolution<'tcx> {

// we should not be invoked until the closure kind has been
// determined by upvar inference
assert!(fcx.closure_kind(self.closure_args).is_some());
assert!(fcx.closure_kind(self.closure_ty).is_some());

// We may now know enough to figure out fn vs fnmut etc.
match fcx.try_overloaded_call_traits(self.call_expr, self.adjusted_ty, None) {
match fcx.try_overloaded_call_traits(self.call_expr, self.closure_ty, None) {
Some((autoref, method_callee)) => {
// One problem is that when we get here, we are going
// to have a newly instantiated function signature
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_typeck/src/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
| ty::FnDef(..)
| ty::FnPtr(..)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(..)
| ty::Adt(..)
| ty::Never
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_typeck/src/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match ty.kind() {
// Not all of these (e.g., unsafe fns) implement `FnOnce`,
// so we look for these beforehand.
// FIXME(async_closures): These don't impl `FnOnce` by default.
ty::Closure(..) | ty::FnDef(..) | ty::FnPtr(_) => true,
// If it's not a simple function, look for things which implement `FnOnce`.
_ => {
Expand Down
22 changes: 11 additions & 11 deletions compiler/rustc_hir_typeck/src/upvar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) {
// Extract the type of the closure.
let ty = self.node_ty(closure_hir_id);
let (closure_def_id, args) = match *ty.kind() {
ty::Closure(def_id, args) => (def_id, UpvarArgs::Closure(args)),
ty::Coroutine(def_id, args) => (def_id, UpvarArgs::Coroutine(args)),
let (closure_def_id, args, infer_kind) = match *ty.kind() {
ty::Closure(def_id, args) => {
(def_id, UpvarArgs::Closure(args), self.closure_kind(ty).is_none())
}
ty::Coroutine(def_id, args) => (def_id, UpvarArgs::Coroutine(args), false),
ty::Error(_) => {
// #51714: skip analysis when we have already encountered type errors
return;
Expand All @@ -188,12 +190,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let closure_def_id = closure_def_id.expect_local();

let infer_kind = if let UpvarArgs::Closure(closure_args) = args {
self.closure_kind(closure_args).is_none().then_some(closure_args)
} else {
None
};

assert_eq!(self.tcx.hir().body_owner_def_id(body.id()), closure_def_id);
let mut delegate = InferBorrowKind {
closure_def_id,
Expand Down Expand Up @@ -308,10 +304,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

let before_feature_tys = self.final_upvar_tys(closure_def_id);

if let Some(closure_args) = infer_kind {
if infer_kind {
// Unify the (as yet unbound) type variable in the closure
// args with the kind we inferred.
let closure_kind_ty = closure_args.as_closure().kind_ty();
let closure_kind_ty = match args {
UpvarArgs::Closure(args) => args.as_closure().kind_ty(),
UpvarArgs::CoroutineClosure(args) => args.as_coroutine_closure().kind_ty(),
UpvarArgs::Coroutine(_) => unreachable!("coroutines don't have an inferred kind"),
};
self.demand_eqtype(
span,
Ty::from_closure_kind(self.tcx, closure_kind),
Expand Down
Loading

0 comments on commit c567edd

Please sign in to comment.