Skip to content

Commit a43fead

Browse files
committed
[HACK] rustc: tuple all closure/generator synthetics, not just upvars.
1 parent cb6cdc0 commit a43fead

29 files changed

+157
-183
lines changed

src/librustc/ty/sty.rs

+37-44
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::mir::interpret::ConstValue;
1111
use crate::mir::interpret::Scalar;
1212
use crate::mir::Promoted;
1313
use crate::ty::layout::VariantIdx;
14-
use crate::ty::subst::{GenericArgKind, InternalSubsts, Subst, SubstsRef};
14+
use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef};
1515
use crate::ty::{
1616
self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable, WithConstness,
1717
};
@@ -276,6 +276,7 @@ static_assert_size!(TyKind<'_>, 24);
276276
/// - U is a type parameter representing the types of its upvars, tupled up
277277
/// (borrowed, if appropriate; that is, if an U field represents a by-ref upvar,
278278
/// and the up-var has the type `Foo`, then that field of U will be `&Foo`).
279+
/// FIXME(eddyb) update this with the new setup which tuples all synthetics.
279280
///
280281
/// So, for example, given this function:
281282
///
@@ -364,21 +365,26 @@ pub struct ClosureSubsts<'tcx> {
364365
/// Struct returned by `split()`. Note that these are subslices of the
365366
/// parent slice and not canonical substs themselves.
366367
struct SplitClosureSubsts<'tcx> {
368+
// FIXME(eddyb) maybe replace these with `GenericArg` to avoid having
369+
// `GenericArg::expect_ty` called on all of them when only one is used.
367370
closure_kind_ty: Ty<'tcx>,
368371
closure_sig_ty: Ty<'tcx>,
369-
tupled_upvars_ty: Ty<'tcx>,
372+
upvars: &'tcx [GenericArg<'tcx>],
370373
}
371374

372375
impl<'tcx> ClosureSubsts<'tcx> {
373376
/// Divides the closure substs into their respective
374377
/// components. Single source of truth with respect to the
375378
/// ordering.
376379
fn split(self) -> SplitClosureSubsts<'tcx> {
377-
let parent_len = self.substs.len() - 3;
380+
let synthetics = match self.substs[self.substs.len() - 1].expect_ty().kind {
381+
Tuple(synthetics) => synthetics,
382+
_ => bug!("synthetics should be tupled"),
383+
};
378384
SplitClosureSubsts {
379-
closure_kind_ty: self.substs.type_at(parent_len),
380-
closure_sig_ty: self.substs.type_at(parent_len + 1),
381-
tupled_upvars_ty: self.substs.type_at(parent_len + 2),
385+
closure_kind_ty: synthetics.type_at(0),
386+
closure_sig_ty: synthetics.type_at(1),
387+
upvars: &synthetics[2..],
382388
}
383389
}
384390

@@ -388,22 +394,15 @@ impl<'tcx> ClosureSubsts<'tcx> {
388394
/// Used primarily by `ty::print::pretty` to be able to handle closure
389395
/// types that haven't had their synthetic types substituted in.
390396
pub fn is_valid(self) -> bool {
391-
self.substs.len() >= 3 && matches!(self.split().tupled_upvars_ty.kind, Tuple(_))
397+
match self.substs[self.substs.len() - 1].expect_ty().kind {
398+
Tuple(synthetics) => synthetics.len() >= 2,
399+
_ => false,
400+
}
392401
}
393402

394403
#[inline]
395404
pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
396-
let upvars = match self.split().tupled_upvars_ty.kind {
397-
Tuple(upvars) => upvars,
398-
_ => bug!("upvars should be tupled"),
399-
};
400-
upvars.iter().map(|t| {
401-
if let GenericArgKind::Type(ty) = t.unpack() {
402-
ty
403-
} else {
404-
bug!("upvar should be type")
405-
}
406-
})
405+
self.split().upvars.iter().map(|t| t.expect_ty())
407406
}
408407

409408
/// Returns the closure kind for this closure; may return a type
@@ -454,22 +453,27 @@ pub struct GeneratorSubsts<'tcx> {
454453
}
455454

456455
struct SplitGeneratorSubsts<'tcx> {
456+
// FIXME(eddyb) maybe replace these with `GenericArg` to avoid having
457+
// `GenericArg::expect_ty` called on all of them when only one is used.
457458
resume_ty: Ty<'tcx>,
458459
yield_ty: Ty<'tcx>,
459460
return_ty: Ty<'tcx>,
460461
witness: Ty<'tcx>,
461-
tupled_upvars_ty: Ty<'tcx>,
462+
upvars: &'tcx [GenericArg<'tcx>],
462463
}
463464

464465
impl<'tcx> GeneratorSubsts<'tcx> {
465466
fn split(self) -> SplitGeneratorSubsts<'tcx> {
466-
let parent_len = self.substs.len() - 5;
467+
let synthetics = match self.substs[self.substs.len() - 1].expect_ty().kind {
468+
Tuple(synthetics) => synthetics,
469+
_ => bug!("synthetics should be tupled"),
470+
};
467471
SplitGeneratorSubsts {
468-
resume_ty: self.substs.type_at(parent_len),
469-
yield_ty: self.substs.type_at(parent_len + 1),
470-
return_ty: self.substs.type_at(parent_len + 2),
471-
witness: self.substs.type_at(parent_len + 3),
472-
tupled_upvars_ty: self.substs.type_at(parent_len + 4),
472+
resume_ty: synthetics.type_at(0),
473+
yield_ty: synthetics.type_at(1),
474+
return_ty: synthetics.type_at(2),
475+
witness: synthetics.type_at(3),
476+
upvars: &synthetics[4..],
473477
}
474478
}
475479

@@ -479,7 +483,10 @@ impl<'tcx> GeneratorSubsts<'tcx> {
479483
/// Used primarily by `ty::print::pretty` to be able to handle generator
480484
/// types that haven't had their synthetic types substituted in.
481485
pub fn is_valid(self) -> bool {
482-
self.substs.len() >= 5 && matches!(self.split().tupled_upvars_ty.kind, Tuple(_))
486+
match self.substs[self.substs.len() - 1].expect_ty().kind {
487+
Tuple(synthetics) => synthetics.len() >= 4,
488+
_ => false,
489+
}
483490
}
484491

485492
/// This describes the types that can be contained in a generator.
@@ -493,17 +500,7 @@ impl<'tcx> GeneratorSubsts<'tcx> {
493500

494501
#[inline]
495502
pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
496-
let upvars = match self.split().tupled_upvars_ty.kind {
497-
Tuple(upvars) => upvars,
498-
_ => bug!("upvars should be tupled"),
499-
};
500-
upvars.iter().map(|t| {
501-
if let GenericArgKind::Type(ty) = t.unpack() {
502-
ty
503-
} else {
504-
bug!("upvar should be type")
505-
}
506-
})
503+
self.split().upvars.iter().map(|t| t.expect_ty())
507504
}
508505

509506
/// Returns the type representing the resume type of the generator.
@@ -643,13 +640,9 @@ pub enum UpvarSubsts<'tcx> {
643640
impl<'tcx> UpvarSubsts<'tcx> {
644641
#[inline]
645642
pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
646-
let tupled_upvars_ty = match self {
647-
UpvarSubsts::Closure(substs) => substs.as_closure().split().tupled_upvars_ty,
648-
UpvarSubsts::Generator(substs) => substs.as_generator().split().tupled_upvars_ty,
649-
};
650-
let upvars = match tupled_upvars_ty.kind {
651-
Tuple(upvars) => upvars,
652-
_ => bug!("upvars should be tupled"),
643+
let upvars = match self {
644+
UpvarSubsts::Closure(substs) => substs.as_closure().split().upvars,
645+
UpvarSubsts::Generator(substs) => substs.as_generator().split().upvars,
653646
};
654647
upvars.iter().map(|t| {
655648
if let GenericArgKind::Type(ty) = t.unpack() {

src/librustc_mir/borrow_check/universal_regions.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -329,9 +329,12 @@ impl<'tcx> UniversalRegions<'tcx> {
329329
match self.defining_ty {
330330
DefiningTy::Closure(def_id, substs) => {
331331
err.note(&format!(
332-
"defining type: {} with closure substs {:#?}",
332+
"defining type: {} with closure synthetics {:#?}",
333333
tcx.def_path_str_with_substs(def_id, substs),
334-
&substs[tcx.generics_of(def_id).parent_count..],
334+
substs[tcx.generics_of(def_id).parent_count]
335+
.expect_ty()
336+
.tuple_fields()
337+
.collect::<Vec<_>>(),
335338
));
336339

337340
// FIXME: It'd be nice to print the late-bound regions
@@ -346,9 +349,12 @@ impl<'tcx> UniversalRegions<'tcx> {
346349
}
347350
DefiningTy::Generator(def_id, substs, _) => {
348351
err.note(&format!(
349-
"defining type: {} with generator substs {:#?}",
352+
"defining type: {} with generator synthetics {:#?}",
350353
tcx.def_path_str_with_substs(def_id, substs),
351-
&substs[tcx.generics_of(def_id).parent_count..],
354+
substs[tcx.generics_of(def_id).parent_count]
355+
.expect_ty()
356+
.tuple_fields()
357+
.collect::<Vec<_>>(),
352358
));
353359

354360
// FIXME: As above, we'd like to print out the region

src/librustc_typeck/check/closure.rs

+25-22
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::astconv::AstConv;
66
use crate::middle::{lang_items, region};
77
use rustc::ty::fold::TypeFoldable;
88
use rustc::ty::subst::InternalSubsts;
9-
use rustc::ty::{self, GenericParamDefKind, Ty};
9+
use rustc::ty::{self, Ty};
1010
use rustc_hir as hir;
1111
use rustc_hir::def_id::DefId;
1212
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -82,32 +82,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
8282
// inference phase (`upvar.rs`).
8383
let base_substs =
8484
InternalSubsts::identity_for_item(self.tcx, self.tcx.closure_base_def_id(expr_def_id));
85-
// HACK(eddyb) this hardcodes indices into substs but it should rely on
85+
// HACK(eddyb) this hardcodes the number of synthetics but it should rely on
8686
// `ClosureSubsts` and `GeneratorSubsts` providing constructors, instead.
8787
// That would also remove the need for most of the inference variables,
8888
// as they immediately unified with the actual type below, including
8989
// the `InferCtxt::closure_sig` and `ClosureSubsts::sig_ty` methods.
90-
let tupled_upvars_idx = base_substs.len() + if generator_types.is_some() { 4 } else { 2 };
91-
let substs = base_substs.extend_to(self.tcx, expr_def_id, |param, _| match param.kind {
92-
GenericParamDefKind::Lifetime => span_bug!(expr.span, "closure has lifetime param"),
93-
GenericParamDefKind::Type { .. } => if param.index as usize == tupled_upvars_idx {
94-
self.tcx.mk_tup(self.tcx.upvars(expr_def_id).iter().flat_map(|upvars| {
95-
upvars.iter().map(|(&var_hir_id, _)| {
96-
self.infcx.next_ty_var(TypeVariableOrigin {
97-
// FIXME(eddyb) distinguish upvar inference variables from the rest.
98-
kind: TypeVariableOriginKind::ClosureSynthetic,
99-
span: self.tcx.hir().span(var_hir_id),
90+
let non_upvar_synthetics = if generator_types.is_some() { 4 } else { 2 };
91+
let substs = base_substs.extend_to(self.tcx, expr_def_id, |param, _| {
92+
assert_eq!(param.index as usize, base_substs.len());
93+
94+
self.tcx
95+
.mk_tup(
96+
(0..non_upvar_synthetics)
97+
.map(|_| {
98+
self.infcx.next_ty_var(TypeVariableOrigin {
99+
kind: TypeVariableOriginKind::ClosureSynthetic,
100+
span: expr.span,
101+
})
100102
})
101-
})
102-
}))
103-
} else {
104-
self.infcx.next_ty_var(TypeVariableOrigin {
105-
kind: TypeVariableOriginKind::ClosureSynthetic,
106-
span: expr.span,
107-
})
108-
}
109-
.into(),
110-
GenericParamDefKind::Const => span_bug!(expr.span, "closure has const param"),
103+
.chain(self.tcx.upvars(expr_def_id).iter().flat_map(|upvars| {
104+
upvars.iter().map(|(&var_hir_id, _)| {
105+
self.infcx.next_ty_var(TypeVariableOrigin {
106+
// FIXME(eddyb) distinguish upvar inference variables from the rest.
107+
kind: TypeVariableOriginKind::ClosureSynthetic,
108+
span: self.tcx.hir().span(var_hir_id),
109+
})
110+
})
111+
})),
112+
)
113+
.into()
111114
});
112115
if let Some(GeneratorTypes { resume_ty, yield_ty, interior, movability }) = generator_types
113116
{

src/librustc_typeck/collect.rs

+6-12
Original file line numberDiff line numberDiff line change
@@ -1334,27 +1334,21 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics {
13341334
Some(param_def)
13351335
}));
13361336

1337-
// provide junk type parameter defs - the only place that
1338-
// cares about anything but the length is instantiation,
1339-
// and we don't do that for closures.
1337+
// Add a type parameter to hold the tupled closure/generator synthetics.
13401338
if let Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(.., gen), .. }) = node {
1341-
let dummy_args = if gen.is_some() {
1342-
&["<resume_ty>", "<yield_ty>", "<return_ty>", "<witness>", "<upvars>"][..]
1343-
} else {
1344-
&["<closure_kind>", "<closure_signature>", "<upvars>"][..]
1345-
};
1339+
let name = if gen.is_some() { "<generator_synthetics>" } else { "<closure_synthetics>" };
13461340

1347-
params.extend(dummy_args.iter().enumerate().map(|(i, &arg)| ty::GenericParamDef {
1348-
index: type_start + i as u32,
1349-
name: Symbol::intern(arg),
1341+
params.push(ty::GenericParamDef {
1342+
index: type_start,
1343+
name: Symbol::intern(name),
13501344
def_id,
13511345
pure_wrt_drop: false,
13521346
kind: ty::GenericParamDefKind::Type {
13531347
has_default: false,
13541348
object_lifetime_default: rl::Set1::Empty,
13551349
synthetic: None,
13561350
},
1357-
}));
1351+
});
13581352
}
13591353

13601354
let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect();

src/test/ui/generator/sized-yield.rs

+2
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,6 @@ fn main() {
1111
};
1212
Pin::new(&mut gen).resume(());
1313
//~^ ERROR the size for values of type
14+
//~| ERROR the size for values of type
15+
//~| ERROR the size for values of type
1416
}

src/test/ui/generator/sized-yield.stderr

+21-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,26 @@ LL | | };
1212
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
1313
= note: the yield type of a generator must have a statically known size
1414

15+
error[E0277]: the size for values of type `str` cannot be known at compilation time
16+
--> $DIR/sized-yield.rs:12:13
17+
|
18+
LL | Pin::new(&mut gen).resume(());
19+
| ^^^^^^^^ doesn't have a size known at compile-time
20+
|
21+
= help: the trait `std::marker::Sized` is not implemented for `str`
22+
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
23+
= note: only the last element of a tuple may have a dynamically sized type
24+
25+
error[E0277]: the size for values of type `str` cannot be known at compilation time
26+
--> $DIR/sized-yield.rs:12:4
27+
|
28+
LL | Pin::new(&mut gen).resume(());
29+
| ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
30+
|
31+
= help: the trait `std::marker::Sized` is not implemented for `str`
32+
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
33+
= note: only the last element of a tuple may have a dynamically sized type
34+
1535
error[E0277]: the size for values of type `str` cannot be known at compilation time
1636
--> $DIR/sized-yield.rs:12:23
1737
|
@@ -21,6 +41,6 @@ LL | Pin::new(&mut gen).resume(());
2141
= help: the trait `std::marker::Sized` is not implemented for `str`
2242
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
2343

24-
error: aborting due to 2 previous errors
44+
error: aborting due to 4 previous errors
2545

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

src/test/ui/nll/closure-requirements/escape-argument-callee.stderr

+1-2
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@ note: no external requirements
44
LL | let mut closure = expect_sig(|p, y| *p = y);
55
| ^^^^^^^^^^^^^
66
|
7-
= note: defining type: test::{{closure}}#0 with closure substs [
7+
= note: defining type: test::{{closure}}#0 with closure synthetics [
88
i16,
99
for<'r, 's, 't0> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) mut &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) i32)),
10-
(),
1110
]
1211

1312
error: lifetime may not live long enough

src/test/ui/nll/closure-requirements/escape-argument.stderr

+1-2
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@ note: no external requirements
44
LL | let mut closure = expect_sig(|p, y| *p = y);
55
| ^^^^^^^^^^^^^
66
|
7-
= note: defining type: test::{{closure}}#0 with closure substs [
7+
= note: defining type: test::{{closure}}#0 with closure synthetics [
88
i16,
99
for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) mut &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32, &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32)),
10-
(),
1110
]
1211

1312
note: no external requirements

src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr

+6-4
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ note: external requirements
44
LL | let mut closure1 = || p = &y;
55
| ^^^^^^^^^
66
|
7-
= note: defining type: test::{{closure}}#0::{{closure}}#0 with closure substs [
7+
= note: defining type: test::{{closure}}#0::{{closure}}#0 with closure synthetics [
88
i16,
99
extern "rust-call" fn(()),
10-
(&'_#1r i32, &'_#2r mut &'_#3r i32),
10+
&'_#1r i32,
11+
&'_#2r mut &'_#3r i32,
1112
]
1213
= note: number of external vids: 4
1314
= note: where '_#1r: '_#3r
@@ -22,10 +23,11 @@ LL | | closure1();
2223
LL | | };
2324
| |_________^
2425
|
25-
= note: defining type: test::{{closure}}#0 with closure substs [
26+
= note: defining type: test::{{closure}}#0 with closure synthetics [
2627
i16,
2728
extern "rust-call" fn(()),
28-
(&'_#1r i32, &'_#2r mut &'_#3r i32),
29+
&'_#1r i32,
30+
&'_#2r mut &'_#3r i32,
2931
]
3032
= note: number of external vids: 4
3133
= note: where '_#1r: '_#3r

src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr

+3-2
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ note: external requirements
44
LL | let mut closure = || p = &y;
55
| ^^^^^^^^^
66
|
7-
= note: defining type: test::{{closure}}#0 with closure substs [
7+
= note: defining type: test::{{closure}}#0 with closure synthetics [
88
i16,
99
extern "rust-call" fn(()),
10-
(&'_#1r i32, &'_#2r mut &'_#3r i32),
10+
&'_#1r i32,
11+
&'_#2r mut &'_#3r i32,
1112
]
1213
= note: number of external vids: 4
1314
= note: where '_#1r: '_#3r

0 commit comments

Comments
 (0)