Skip to content

Commit 5a7af54

Browse files
committed
Support variantful generators
This allows generators to overlap fields using variants.
1 parent 4de2d8a commit 5a7af54

File tree

13 files changed

+281
-155
lines changed

13 files changed

+281
-155
lines changed

src/librustc/mir/mod.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -2028,6 +2028,10 @@ impl<'tcx> Place<'tcx> {
20282028
variant_index))
20292029
}
20302030

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

25632562
struct_fmt.finish()

src/librustc/mir/tcx.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,13 @@ impl<'tcx> Rvalue<'tcx> {
177177
}
178178
Rvalue::Discriminant(ref place) => {
179179
let ty = place.ty(local_decls, tcx).ty;
180-
if let ty::Adt(adt_def, _) = ty.sty {
181-
adt_def.repr.discr_type().to_ty(tcx)
182-
} else {
183-
// This can only be `0`, for now, so `u8` will suffice.
184-
tcx.types.u8
180+
match ty.sty {
181+
ty::Adt(adt_def, _) => adt_def.repr.discr_type().to_ty(tcx),
182+
ty::Generator(_, substs, _) => substs.discr_ty(tcx),
183+
_ => {
184+
// This can only be `0`, for now, so `u8` will suffice.
185+
tcx.types.u8
186+
}
185187
}
186188
}
187189
Rvalue::NullaryOp(NullOp::Box, t) => tcx.mk_box(t),

src/librustc/ty/layout.rs

+71-10
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

+10-18
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

+5-1
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

+5
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

+27-10
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::*;
@@ -648,7 +649,7 @@ fn arg_local_refs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
648649
.iter()
649650
.zip(upvar_tys)
650651
.enumerate()
651-
.map(|(i, (upvar, ty))| (i, upvar.debug_name, upvar.by_ref, ty));
652+
.map(|(i, (upvar, ty))| (None, i, upvar.debug_name, upvar.by_ref, ty));
652653

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

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

673679
upvars.chain(generator_fields)
674680
};
675681

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

679696
let ops = bx.debuginfo_upvar_ops_sequence(byte_offset_of_var_in_env);
680697

src/librustc_codegen_ssa/mir/place.rs

+9-3
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)