Skip to content

Commit fbb7b4b

Browse files
committed
Support variantful generators
This allows generators to overlap fields using variants.
1 parent c56c01b commit fbb7b4b

File tree

12 files changed

+279
-154
lines changed

12 files changed

+279
-154
lines changed

src/librustc/mir/mod.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2029,6 +2029,10 @@ impl<'tcx> Place<'tcx> {
20292029
variant_index))
20302030
}
20312031

2032+
pub fn downcast_unnamed(self, variant_index: VariantIdx) -> Place<'tcx> {
2033+
self.elem(ProjectionElem::Downcast(None, variant_index))
2034+
}
2035+
20322036
pub fn index(self, index: Local) -> Place<'tcx> {
20332037
self.elem(ProjectionElem::Index(index))
20342038
}
@@ -2554,11 +2558,6 @@ impl<'tcx> Debug for Rvalue<'tcx> {
25542558
let var_name = tcx.hir().name_by_hir_id(freevar.var_id());
25552559
struct_fmt.field(&var_name.as_str(), place);
25562560
}
2557-
struct_fmt.field("$state", &places[freevars.len()]);
2558-
for i in (freevars.len() + 1)..places.len() {
2559-
struct_fmt
2560-
.field(&format!("${}", i - freevars.len() - 1), &places[i]);
2561-
}
25622561
});
25632562

25642563
struct_fmt.finish()

src/librustc/mir/tcx.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -212,11 +212,13 @@ impl<'tcx> Rvalue<'tcx> {
212212
}
213213
Rvalue::Discriminant(ref place) => {
214214
let ty = place.ty(local_decls, tcx).ty;
215-
if let ty::Adt(adt_def, _) = ty.sty {
216-
adt_def.repr.discr_type().to_ty(tcx)
217-
} else {
218-
// This can only be `0`, for now, so `u8` will suffice.
219-
tcx.types.u8
215+
match ty.sty {
216+
ty::Adt(adt_def, _) => adt_def.repr.discr_type().to_ty(tcx),
217+
ty::Generator(_, substs, _) => substs.discr_ty(tcx),
218+
_ => {
219+
// This can only be `0`, for now, so `u8` will suffice.
220+
tcx.types.u8
221+
}
220222
}
221223
}
222224
Rvalue::NullaryOp(NullOp::Box, t) => tcx.mk_box(t),

src/librustc/ty/layout.rs

Lines changed: 71 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -604,12 +604,57 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
604604
tcx.intern_layout(unit)
605605
}
606606

607-
// Tuples, generators and closures.
608607
ty::Generator(def_id, ref substs, _) => {
609-
let tys = substs.field_tys(def_id, tcx);
610-
univariant(&tys.map(|ty| self.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
608+
let discr_index = substs.prefix_tys(def_id, tcx).count();
609+
let prefix_tys = substs.prefix_tys(def_id, tcx)
610+
.chain(iter::once(substs.discr_ty(tcx)));
611+
let prefix = univariant_uninterned(
612+
&prefix_tys.map(|ty| self.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
611613
&ReprOptions::default(),
612-
StructKind::AlwaysSized)?
614+
StructKind::AlwaysSized)?;
615+
616+
let mut size = prefix.size;
617+
let mut align = prefix.align;
618+
let variants_tys = substs.state_tys(def_id, tcx);
619+
let variants = variants_tys.enumerate().map(|(i, variant_tys)| {
620+
let mut variant = univariant_uninterned(
621+
&variant_tys.map(|ty| self.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
622+
&ReprOptions::default(),
623+
StructKind::Prefixed(prefix.size, prefix.align.abi))?;
624+
625+
variant.variants = Variants::Single { index: VariantIdx::new(i) };
626+
627+
size = size.max(variant.size);
628+
align = align.max(variant.align);
629+
630+
Ok(variant)
631+
}).collect::<Result<IndexVec<VariantIdx, _>, _>>()?;
632+
633+
let abi = if prefix.abi.is_uninhabited() ||
634+
variants.iter().all(|v| v.abi.is_uninhabited()) {
635+
Abi::Uninhabited
636+
} else {
637+
Abi::Aggregate { sized: true }
638+
};
639+
let discr = match &self.layout_of(substs.discr_ty(tcx))?.abi {
640+
Abi::Scalar(s) => s.clone(),
641+
_ => bug!(),
642+
};
643+
644+
let layout = tcx.intern_layout(LayoutDetails {
645+
variants: Variants::Multiple {
646+
discr,
647+
discr_kind: DiscriminantKind::Tag,
648+
discr_index,
649+
variants,
650+
},
651+
fields: prefix.fields,
652+
abi,
653+
size,
654+
align,
655+
});
656+
debug!("generator layout: {:#?}", layout);
657+
layout
613658
}
614659

615660
ty::Closure(def_id, ref substs) => {
@@ -1646,6 +1691,14 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx>
16461691

16471692
fn field(this: TyLayout<'tcx>, cx: &C, i: usize) -> C::TyLayout {
16481693
let tcx = cx.tcx();
1694+
let handle_discriminant = |discr: &Scalar| -> C::TyLayout {
1695+
let layout = LayoutDetails::scalar(cx, discr.clone());
1696+
MaybeResult::from_ok(TyLayout {
1697+
details: tcx.intern_layout(layout),
1698+
ty: discr.value.to_ty(tcx)
1699+
})
1700+
};
1701+
16491702
cx.layout_of(match this.ty.sty {
16501703
ty::Bool |
16511704
ty::Char |
@@ -1720,7 +1773,19 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx>
17201773
}
17211774

17221775
ty::Generator(def_id, ref substs, _) => {
1723-
substs.field_tys(def_id, tcx).nth(i).unwrap()
1776+
match this.variants {
1777+
Variants::Single { index } => {
1778+
substs.state_tys(def_id, tcx)
1779+
.nth(index.as_usize()).unwrap()
1780+
.nth(i).unwrap()
1781+
}
1782+
Variants::Multiple { ref discr, discr_index, .. } => {
1783+
if i == discr_index {
1784+
return handle_discriminant(discr);
1785+
}
1786+
substs.prefix_tys(def_id, tcx).nth(i).unwrap()
1787+
}
1788+
}
17241789
}
17251790

17261791
ty::Tuple(tys) => tys[i],
@@ -1740,11 +1805,7 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx>
17401805
// Discriminant field for enums (where applicable).
17411806
Variants::Multiple { ref discr, .. } => {
17421807
assert_eq!(i, 0);
1743-
let layout = LayoutDetails::scalar(cx, discr.clone());
1744-
return MaybeResult::from_ok(TyLayout {
1745-
details: tcx.intern_layout(layout),
1746-
ty: discr.value.to_ty(tcx)
1747-
});
1808+
return handle_discriminant(discr);
17481809
}
17491810
}
17501811
}

src/librustc/ty/sty.rs

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ use crate::util::captures::Captures;
1515
use crate::mir::interpret::{Scalar, Pointer};
1616

1717
use smallvec::SmallVec;
18-
use std::iter;
1918
use std::cmp::Ordering;
2019
use std::marker::PhantomData;
2120
use rustc_target::spec::abi;
@@ -475,30 +474,23 @@ impl<'a, 'gcx, 'tcx> GeneratorSubsts<'tcx> {
475474
/// This returns the types of the MIR locals which had to be stored across suspension points.
476475
/// It is calculated in rustc_mir::transform::generator::StateTransform.
477476
/// All the types here must be in the tuple in GeneratorInterior.
477+
///
478+
/// The locals are grouped by their variant number. Note that some locals may
479+
/// be repeated in multiple variants.
478480
pub fn state_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) ->
479-
impl Iterator<Item=Ty<'tcx>> + Captures<'gcx> + 'a
481+
impl Iterator<Item=impl Iterator<Item=Ty<'tcx>> + Captures<'gcx> + 'a>
480482
{
481-
// TODO remove so we can handle variants properly
482483
tcx.generator_layout(def_id)
483-
.variant_fields[0].iter()
484-
.map(move |d| d.ty.subst(tcx, self.substs))
484+
.variant_fields.iter()
485+
.map(move |v| v.iter().map(move |d| d.ty.subst(tcx, self.substs)))
485486
}
486487

487-
/// This is the types of the fields of a generator which
488-
/// is available before the generator transformation.
489-
/// It includes the upvars and the state discriminant.
490-
pub fn pre_transforms_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) ->
488+
/// This is the types of the fields of a generator which are not stored in a
489+
/// variant.
490+
pub fn prefix_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) ->
491491
impl Iterator<Item=Ty<'tcx>> + 'a
492492
{
493-
self.upvar_tys(def_id, tcx).chain(iter::once(self.discr_ty(tcx)))
494-
}
495-
496-
/// This is the types of all the fields stored in a generator.
497-
/// It includes the upvars, state types and the state discriminant.
498-
pub fn field_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) ->
499-
impl Iterator<Item=Ty<'tcx>> + Captures<'gcx> + 'a
500-
{
501-
self.pre_transforms_tys(def_id, tcx).chain(self.state_tys(def_id, tcx))
493+
self.upvar_tys(def_id, tcx)
502494
}
503495
}
504496

src/librustc_codegen_llvm/debuginfo/metadata.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -691,9 +691,12 @@ pub fn type_metadata(
691691
usage_site_span).finalize(cx)
692692
}
693693
ty::Generator(def_id, substs, _) => {
694-
let upvar_tys : Vec<_> = substs.field_tys(def_id, cx.tcx).map(|t| {
694+
// TODO handle variant fields
695+
let upvar_tys : Vec<_> = substs.prefix_tys(def_id, cx.tcx).map(|t| {
695696
cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t)
696697
}).collect();
698+
// TODO use prepare_enum_metadata and update it to handle multiple
699+
// fields in the outer layout.
697700
prepare_tuple_metadata(cx,
698701
t,
699702
&upvar_tys,
@@ -1818,6 +1821,7 @@ fn prepare_enum_metadata(
18181821
};
18191822

18201823
// The variant part must be wrapped in a struct according to DWARF.
1824+
// TODO create remaining fields here, if any.
18211825
let type_array = create_DIArray(DIB(cx), &[Some(variant_part)]);
18221826
let struct_wrapper = unsafe {
18231827
llvm::LLVMRustDIBuilderCreateStructType(

src/librustc_codegen_llvm/type_of.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ fn uncached_llvm_type<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
6363
write!(&mut name, "::{}", def.variants[index].ident).unwrap();
6464
}
6565
}
66+
if let (&ty::Generator(..), &layout::Variants::Single { index })
67+
= (&layout.ty.sty, &layout.variants)
68+
{
69+
write!(&mut name, "::variant#{:?}", index).unwrap();
70+
}
6671
Some(name)
6772
}
6873
_ => None

src/librustc_codegen_ssa/mir/mod.rs

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use rustc::mir::{self, Mir};
44
use rustc::session::config::DebugInfo;
55
use rustc_mir::monomorphize::Instance;
66
use rustc_target::abi::call::{FnType, PassMode, IgnoreMode};
7+
use rustc_target::abi::{Variants, VariantIdx};
78
use crate::base;
89
use crate::debuginfo::{self, VariableAccess, VariableKind, FunctionDebugContext};
910
use crate::traits::*;
@@ -647,7 +648,7 @@ fn arg_local_refs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
647648
.iter()
648649
.zip(upvar_tys)
649650
.enumerate()
650-
.map(|(i, (decl, ty))| (i, decl.debug_name, decl.by_ref, ty));
651+
.map(|(i, (decl, ty))| (None, i, decl.debug_name, decl.by_ref, ty));
651652

652653
let generator_fields = mir.generator_layout.as_ref().map(|generator_layout| {
653654
let (def_id, gen_substs) = match closure_layout.ty.sty {
@@ -657,23 +658,39 @@ fn arg_local_refs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
657658
// TODO handle variant scopes here
658659
let state_tys = gen_substs.state_tys(def_id, tcx);
659660

660-
// TODO remove assumption of only one variant
661-
let upvar_count = mir.upvar_decls.len();
662-
generator_layout.variant_fields[0]
663-
.iter()
661+
generator_layout.variant_fields.iter()
664662
.zip(state_tys)
665663
.enumerate()
666-
.filter_map(move |(i, (decl, ty))| {
667-
let ty = fx.monomorphize(&ty);
668-
decl.name.map(|name| (i + upvar_count + 1, name, false, ty))
664+
.flat_map(move |(variant_idx, (decls, tys))| {
665+
let variant_idx = Some(VariantIdx::from(variant_idx));
666+
decls.iter()
667+
.zip(tys)
668+
.enumerate()
669+
.filter_map(move |(i, (decl, ty))| {
670+
let ty = fx.monomorphize(&ty);
671+
decl.name.map(|name| {
672+
(variant_idx, i, name, false, ty)
673+
})
674+
})
669675
})
670676
}).into_iter().flatten();
671677

672678
upvars.chain(generator_fields)
673679
};
674680

675-
for (field, name, by_ref, ty) in extra_locals {
676-
let byte_offset_of_var_in_env = closure_layout.fields.offset(field).bytes();
681+
for (variant_idx, field, name, by_ref, ty) in extra_locals {
682+
let fields = match variant_idx {
683+
Some(variant_idx) => {
684+
match &closure_layout.variants {
685+
Variants::Multiple { variants, .. } => {
686+
&variants[variant_idx].fields
687+
},
688+
_ => bug!("variant index on univariant layout"),
689+
}
690+
}
691+
None => &closure_layout.fields,
692+
};
693+
let byte_offset_of_var_in_env = fields.offset(field).bytes();
677694

678695
let ops = bx.debuginfo_upvar_decls_ops_sequence(byte_offset_of_var_in_env);
679696

src/librustc_codegen_ssa/mir/place.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -296,9 +296,15 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> {
296296
..
297297
} => {
298298
let ptr = self.project_field(bx, discr_index);
299-
let to = self.layout.ty.ty_adt_def().unwrap()
300-
.discriminant_for_variant(bx.tcx(), variant_index)
301-
.val;
299+
let to = match self.layout.ty.sty {
300+
ty::TyKind::Adt(adt_def, _) => adt_def
301+
.discriminant_for_variant(bx.tcx(), variant_index)
302+
.val,
303+
// Generators don't support explicit discriminant values, so
304+
// they are the same as the variant index.
305+
ty::TyKind::Generator(..) => variant_index.as_u32() as u128,
306+
_ => bug!(),
307+
};
302308
bx.store(
303309
bx.cx().const_uint_big(bx.cx().backend_type(ptr.layout), to),
304310
ptr.llval,

0 commit comments

Comments
 (0)