Skip to content

Commit dc18370

Browse files
roxeloarora-amanjenniferwills
committed
Replace tuple of infer vars for upvar_tys with single infer var
This commit allows us to decide the number of captures required after completing capture ananysis, which is required as part of implementing RFC-2229. Co-authored-by: Aman Arora <[email protected]> Co-authored-by: Jenny Wills <[email protected]>
1 parent 25d2d09 commit dc18370

23 files changed

+178
-95
lines changed

compiler/rustc_middle/src/ty/outlives.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,15 +96,25 @@ fn compute_components(
9696
}
9797

9898
ty::Closure(_, ref substs) => {
99-
for upvar_ty in substs.as_closure().upvar_tys() {
100-
compute_components(tcx, upvar_ty, out, visited);
99+
if substs.as_closure().is_valid() {
100+
for upvar_ty in substs.as_closure().upvar_tys() {
101+
compute_components(tcx, upvar_ty, out, visited);
102+
}
103+
} else {
104+
let tupled_ty = substs.as_closure().tupled_upvars_ty();
105+
compute_components(tcx, tupled_ty, out, visited);
101106
}
102107
}
103108

104109
ty::Generator(_, ref substs, _) => {
105110
// Same as the closure case
106-
for upvar_ty in substs.as_generator().upvar_tys() {
107-
compute_components(tcx, upvar_ty, out, visited);
111+
if substs.as_generator().is_valid() {
112+
for upvar_ty in substs.as_generator().upvar_tys() {
113+
compute_components(tcx, upvar_ty, out, visited);
114+
}
115+
} else {
116+
let tupled_ty = substs.as_generator().tupled_upvars_ty();
117+
compute_components(tcx, tupled_ty, out, visited);
108118
}
109119

110120
// We ignore regions in the generator interior as we don't

compiler/rustc_middle/src/ty/print/pretty.rs

Lines changed: 17 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -663,18 +663,13 @@ pub trait PrettyPrinter<'tcx>:
663663
}
664664
} else {
665665
p!(print_def_path(did, substs));
666-
if substs.as_generator().is_valid() {
667-
// Search for the first inference variable
668-
p!(" upvar_tys=(");
669-
let mut uninferred_ty =
670-
substs.as_generator().upvar_tys().filter(|ty| ty.is_ty_infer());
671-
if uninferred_ty.next().is_some() {
672-
p!(write("unavailable"));
673-
} else {
674-
self = self.comma_sep(substs.as_generator().upvar_tys())?;
675-
}
676-
p!(")");
666+
p!(" upvar_tys=(");
667+
if !substs.as_generator().is_valid() {
668+
p!("unavailable");
669+
} else {
670+
self = self.comma_sep(substs.as_generator().upvar_tys())?;
677671
}
672+
p!(")");
678673
}
679674

680675
if substs.as_generator().is_valid() {
@@ -704,24 +699,17 @@ pub trait PrettyPrinter<'tcx>:
704699
}
705700
} else {
706701
p!(print_def_path(did, substs));
707-
if substs.as_closure().is_valid() {
708-
// Search for the first inference variable
709-
let mut uninferred_ty =
710-
substs.as_closure().upvar_tys().filter(|ty| ty.is_ty_infer());
711-
if uninferred_ty.next().is_some() {
712-
// If the upvar substs contain an inference variable we haven't
713-
// finished capture analysis.
714-
p!(" closure_substs=(unavailable)");
715-
} else {
716-
p!(" closure_kind_ty=", print(substs.as_closure().kind_ty()));
717-
p!(
718-
" closure_sig_as_fn_ptr_ty=",
719-
print(substs.as_closure().sig_as_fn_ptr_ty())
720-
);
721-
p!(" upvar_tys=(");
722-
self = self.comma_sep(substs.as_closure().upvar_tys())?;
723-
p!(")");
724-
}
702+
if !substs.as_closure().is_valid() {
703+
p!(" closure_substs=(unavailable)");
704+
} else {
705+
p!(" closure_kind_ty=", print(substs.as_closure().kind_ty()));
706+
p!(
707+
" closure_sig_as_fn_ptr_ty=",
708+
print(substs.as_closure().sig_as_fn_ptr_ty())
709+
);
710+
p!(" upvar_tys=(");
711+
self = self.comma_sep(substs.as_closure().upvar_tys())?;
712+
p!(")");
725713
}
726714
}
727715
p!("]");

compiler/rustc_middle/src/ty/sty.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,14 @@ impl<'tcx> UpvarSubsts<'tcx> {
656656
};
657657
tupled_upvars_ty.expect_ty().tuple_fields()
658658
}
659+
660+
#[inline]
661+
pub fn tupled_upvars_ty(self) -> Ty<'tcx> {
662+
match self {
663+
UpvarSubsts::Closure(substs) => substs.as_closure().tupled_upvars_ty(),
664+
UpvarSubsts::Generator(substs) => substs.as_generator().tupled_upvars_ty(),
665+
}
666+
}
659667
}
660668

661669
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)]

compiler/rustc_trait_selection/src/opaque_types.rs

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
441441

442442
for required_region in required_region_bounds {
443443
concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
444+
infcx: self,
444445
op: |r| self.sub_regions(infer::CallReturn(span), required_region, r),
445446
});
446447
}
@@ -509,6 +510,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
509510
}
510511
}
511512
concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
513+
infcx: self,
512514
op: |r| self.sub_regions(infer::CallReturn(span), least_region, r),
513515
});
514516
}
@@ -543,6 +545,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
543545
);
544546

545547
concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
548+
infcx: self,
546549
op: |r| {
547550
self.member_constraint(
548551
opaque_type_def_id,
@@ -683,11 +686,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
683686
//
684687
// We ignore any type parameters because impl trait values are assumed to
685688
// capture all the in-scope type parameters.
686-
struct ConstrainOpaqueTypeRegionVisitor<OP> {
689+
struct ConstrainOpaqueTypeRegionVisitor<'cx, 'tcx, OP> {
690+
infcx: &'cx InferCtxt<'cx, 'tcx>,
687691
op: OP,
688692
}
689693

690-
impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<OP>
694+
impl<'cx, 'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<'cx, 'tcx, OP>
691695
where
692696
OP: FnMut(ty::Region<'tcx>),
693697
{
@@ -717,24 +721,36 @@ where
717721
ty::Closure(_, ref substs) => {
718722
// Skip lifetime parameters of the enclosing item(s)
719723

720-
for upvar_ty in substs.as_closure().upvar_tys() {
721-
upvar_ty.visit_with(self);
722-
}
724+
let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty());
725+
if let ty::Infer(ty::TyVar(_)) = ty.kind() {
726+
// Not yet resolved.
727+
ty.super_visit_with(self);
728+
} else {
729+
for upvar_ty in substs.as_closure().upvar_tys() {
730+
upvar_ty.visit_with(self);
731+
}
723732

724-
substs.as_closure().sig_as_fn_ptr_ty().visit_with(self);
733+
substs.as_closure().sig_as_fn_ptr_ty().visit_with(self);
734+
}
725735
}
726736

727737
ty::Generator(_, ref substs, _) => {
728738
// Skip lifetime parameters of the enclosing item(s)
729739
// Also skip the witness type, because that has no free regions.
730740

731-
for upvar_ty in substs.as_generator().upvar_tys() {
732-
upvar_ty.visit_with(self);
733-
}
741+
let ty = self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty());
742+
if let ty::Infer(ty::TyVar(_)) = ty.kind() {
743+
// Not yet resolved.
744+
ty.super_visit_with(self);
745+
} else {
746+
for upvar_ty in substs.as_generator().upvar_tys() {
747+
upvar_ty.visit_with(self);
748+
}
734749

735-
substs.as_generator().return_ty().visit_with(self);
736-
substs.as_generator().yield_ty().visit_with(self);
737-
substs.as_generator().resume_ty().visit_with(self);
750+
substs.as_generator().return_ty().visit_with(self);
751+
substs.as_generator().yield_ty().visit_with(self);
752+
substs.as_generator().resume_ty().visit_with(self);
753+
}
738754
}
739755
_ => {
740756
ty.super_visit_with(self);

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1307,6 +1307,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
13071307
let mut generator = None;
13081308
let mut outer_generator = None;
13091309
let mut next_code = Some(&obligation.cause.code);
1310+
1311+
let mut seen_upvar_tys_infer_tuple = false;
1312+
13101313
while let Some(code) = next_code {
13111314
debug!("maybe_note_obligation_cause_for_async_await: code={:?}", code);
13121315
match code {
@@ -1327,6 +1330,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
13271330
outer_generator = Some(did);
13281331
}
13291332
ty::GeneratorWitness(..) => {}
1333+
ty::Tuple(_) if !seen_upvar_tys_infer_tuple => {
1334+
// By introducing a tuple of upvar types into the chain of obligations
1335+
// of a generator, the first non-generator item is now the tuple itself,
1336+
// we shall ignore this.
1337+
1338+
seen_upvar_tys_infer_tuple = true;
1339+
}
13301340
_ if generator.is_none() => {
13311341
trait_ref = Some(derived_obligation.parent_trait_ref.skip_binder());
13321342
target_ty = Some(ty);

compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
110110
// check if *any* of those are trivial.
111111
ty::Tuple(ref tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t.expect_ty())),
112112
ty::Closure(_, ref substs) => {
113-
substs.as_closure().upvar_tys().all(|t| trivial_dropck_outlives(tcx, t))
113+
trivial_dropck_outlives(tcx, substs.as_closure().tupled_upvars_ty())
114114
}
115115

116116
ty::Adt(def, _) => {

compiler/rustc_trait_selection/src/traits/select/mod.rs

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1631,7 +1631,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16311631

16321632
ty::Closure(_, substs) => {
16331633
// (*) binder moved here
1634-
Where(ty::Binder::bind(substs.as_closure().upvar_tys().collect()))
1634+
let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty());
1635+
if let ty::Infer(ty::TyVar(_)) = ty.kind() {
1636+
// Not yet resolved.
1637+
Ambiguous
1638+
} else {
1639+
Where(ty::Binder::bind(substs.as_closure().upvar_tys().collect()))
1640+
}
16351641
}
16361642

16371643
ty::Adt(..) | ty::Projection(..) | ty::Param(..) | ty::Opaque(..) => {
@@ -1700,11 +1706,31 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
17001706
tys.iter().map(|k| k.expect_ty()).collect()
17011707
}
17021708

1703-
ty::Closure(_, ref substs) => substs.as_closure().upvar_tys().collect(),
1709+
ty::Closure(_, ref substs) => {
1710+
let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty());
1711+
if let ty::Infer(ty::TyVar(_)) = ty.kind() {
1712+
// The inference variable will be replaced by a tuple once capture analysis
1713+
// completes. If the tuple meets a bound, so do all the elements within it.
1714+
vec![ty]
1715+
} else {
1716+
substs.as_closure().upvar_tys().collect()
1717+
}
1718+
}
17041719

17051720
ty::Generator(_, ref substs, _) => {
1706-
let witness = substs.as_generator().witness();
1707-
substs.as_generator().upvar_tys().chain(iter::once(witness)).collect()
1721+
let upvar_tys_resolved =
1722+
self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty());
1723+
1724+
if let ty::Infer(ty::TyVar(_)) = upvar_tys_resolved.kind() {
1725+
// The inference variable will be replaced by a tuple once capture analysis
1726+
// completes, if the tuple meets a bound, so do all the elements within it.
1727+
let witness_resolved =
1728+
self.infcx.shallow_resolve(substs.as_generator().witness());
1729+
vec![upvar_tys_resolved, witness_resolved]
1730+
} else {
1731+
let witness = substs.as_generator().witness();
1732+
substs.as_generator().upvar_tys().chain(iter::once(witness)).collect()
1733+
}
17081734
}
17091735

17101736
ty::GeneratorWitness(types) => {

compiler/rustc_trait_selection/src/traits/wf.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -592,10 +592,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
592592
// anyway, except via auto trait matching (which
593593
// only inspects the upvar types).
594594
walker.skip_current_subtree(); // subtree handled below
595-
for upvar_ty in substs.as_closure().upvar_tys() {
596-
// FIXME(eddyb) add the type to `walker` instead of recursing.
597-
self.compute(upvar_ty.into());
598-
}
595+
// FIXME(eddyb) add the type to `walker` instead of recursing.
596+
self.compute(substs.as_closure().tupled_upvars_ty().into());
599597
}
600598

601599
ty::FnPtr(_) => {

compiler/rustc_traits/src/dropck_outlives.rs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -210,12 +210,20 @@ fn dtorck_constraint_for_ty<'tcx>(
210210
Ok::<_, NoSolution>(())
211211
})?,
212212

213-
ty::Closure(_, substs) => rustc_data_structures::stack::ensure_sufficient_stack(|| {
214-
for ty in substs.as_closure().upvar_tys() {
215-
dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?;
213+
ty::Closure(_, substs) => {
214+
if !substs.as_closure().is_valid() {
215+
// By the time this code runs, all type variables ought to
216+
// be fully resolved.
217+
return Err(NoSolution);
216218
}
217-
Ok::<_, NoSolution>(())
218-
})?,
219+
220+
rustc_data_structures::stack::ensure_sufficient_stack(|| {
221+
for ty in substs.as_closure().upvar_tys() {
222+
dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?;
223+
}
224+
Ok::<_, NoSolution>(())
225+
})?
226+
}
219227

220228
ty::Generator(_, substs, _movability) => {
221229
// rust-lang/rust#49918: types can be constructed, stored
@@ -241,6 +249,12 @@ fn dtorck_constraint_for_ty<'tcx>(
241249
// derived from lifetimes attached to the upvars and resume
242250
// argument, and we *do* incorporate those here.
243251

252+
if !substs.as_generator().is_valid() {
253+
// By the time this code runs, all type variables ought to
254+
// be fully resolved.
255+
return Err(NoSolution);
256+
}
257+
244258
constraints.outlives.extend(
245259
substs
246260
.as_generator()

compiler/rustc_typeck/src/check/closure.rs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -81,19 +81,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
8181
self.tcx.closure_base_def_id(expr_def_id.to_def_id()),
8282
);
8383

84-
let tupled_upvars_ty =
85-
self.tcx.mk_tup(self.tcx.upvars_mentioned(expr_def_id).iter().flat_map(|upvars| {
86-
upvars.iter().map(|(&var_hir_id, _)| {
87-
// Create type variables (for now) to represent the transformed
88-
// types of upvars. These will be unified during the upvar
89-
// inference phase (`upvar.rs`).
90-
self.infcx.next_ty_var(TypeVariableOrigin {
91-
// FIXME(eddyb) distinguish upvar inference variables from the rest.
92-
kind: TypeVariableOriginKind::ClosureSynthetic,
93-
span: self.tcx.hir().span(var_hir_id),
94-
})
95-
})
96-
}));
84+
let tupled_upvars_ty = self.infcx.next_ty_var(TypeVariableOrigin {
85+
kind: TypeVariableOriginKind::ClosureSynthetic,
86+
span: self.tcx.hir().span(expr.hir_id),
87+
});
9788

9889
if let Some(GeneratorTypes { resume_ty, yield_ty, interior, movability }) = generator_types
9990
{

0 commit comments

Comments
 (0)