fix enum variants with multiple fields

This commit is contained in:
Oliver Schneider 2016-09-30 10:45:52 +02:00
parent 8c666b30ed
commit c9914cd3ae
No known key found for this signature in database
GPG Key ID: 56D6EEA0FC67AC46
3 changed files with 251 additions and 8 deletions

View File

@ -819,11 +819,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
Field(field, field_ty) => {
let field_ty = self.monomorphize(field_ty, self.substs());
use rustc::ty::layout::Layout::*;
let variant = match *base_layout {
Univariant { ref variant, .. } => variant,
let field = field.index();
let offset = match *base_layout {
Univariant { ref variant, .. } => variant.field_offset(field),
General { ref variants, .. } => {
if let LvalueExtra::DowncastVariant(variant_idx) = base.extra {
&variants[variant_idx]
// +1 for the discriminant, which is field 0
variants[variant_idx].field_offset(field + 1)
} else {
bug!("field access on enum had no variant index");
}
@ -832,12 +834,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
assert_eq!(field.index(), 0);
return Ok(base);
}
StructWrappedNullablePointer { ref nonnull, .. } => nonnull,
StructWrappedNullablePointer { ref nonnull, .. } => nonnull.field_offset(field),
_ => bug!("field access on non-product type: {:?}", base_layout),
};
let offset = variant.field_offset(field.index()).bytes();
let ptr = base.ptr.offset(offset as isize);
let ptr = base.ptr.offset(offset.bytes() as isize);
if self.type_is_sized(field_ty) {
ptr
} else {
@ -857,9 +858,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
Downcast(_, variant) => {
use rustc::ty::layout::Layout::*;
match *base_layout {
General { ref variants, .. } => {
General { .. } => {
return Ok(Lvalue {
ptr: base.ptr.offset(variants[variant].field_offset(1).bytes() as isize),
ptr: base.ptr,
extra: LvalueExtra::DowncastVariant(variant),
});
}

View File

@ -0,0 +1,208 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub trait DeclaredTrait {
type Type;
}
impl DeclaredTrait for i32 {
type Type = i32;
}
pub trait WhereTrait {
type Type;
}
impl WhereTrait for i32 {
type Type = i32;
}
// Make sure we don't add a bound that just shares a name with an associated
// type.
pub mod module {
pub type Type = i32;
}
#[derive(PartialEq, Debug)]
struct PrivateStruct<T>(T);
#[derive(PartialEq, Debug)]
struct TupleStruct<A, B: DeclaredTrait, C>(
module::Type,
Option<module::Type>,
A,
PrivateStruct<A>,
B,
B::Type,
Option<B::Type>,
<B as DeclaredTrait>::Type,
Option<<B as DeclaredTrait>::Type>,
C,
C::Type,
Option<C::Type>,
<C as WhereTrait>::Type,
Option<<C as WhereTrait>::Type>,
<i32 as DeclaredTrait>::Type,
) where C: WhereTrait;
#[derive(PartialEq, Debug)]
pub struct Struct<A, B: DeclaredTrait, C> where C: WhereTrait {
m1: module::Type,
m2: Option<module::Type>,
a1: A,
a2: PrivateStruct<A>,
b: B,
b1: B::Type,
b2: Option<B::Type>,
b3: <B as DeclaredTrait>::Type,
b4: Option<<B as DeclaredTrait>::Type>,
c: C,
c1: C::Type,
c2: Option<C::Type>,
c3: <C as WhereTrait>::Type,
c4: Option<<C as WhereTrait>::Type>,
d: <i32 as DeclaredTrait>::Type,
}
#[derive(PartialEq, Debug)]
enum Enum<A, B: DeclaredTrait, C> where C: WhereTrait {
Unit,
Seq(
module::Type,
Option<module::Type>,
A,
PrivateStruct<A>,
B,
B::Type,
Option<B::Type>,
<B as DeclaredTrait>::Type,
Option<<B as DeclaredTrait>::Type>,
C,
C::Type,
Option<C::Type>,
<C as WhereTrait>::Type,
Option<<C as WhereTrait>::Type>,
<i32 as DeclaredTrait>::Type,
),
Map {
m1: module::Type,
m2: Option<module::Type>,
a1: A,
a2: PrivateStruct<A>,
b: B,
b1: B::Type,
b2: Option<B::Type>,
b3: <B as DeclaredTrait>::Type,
b4: Option<<B as DeclaredTrait>::Type>,
c: C,
c1: C::Type,
c2: Option<C::Type>,
c3: <C as WhereTrait>::Type,
c4: Option<<C as WhereTrait>::Type>,
d: <i32 as DeclaredTrait>::Type,
},
}
fn main() {
let e: Enum<
i32,
i32,
i32,
> = Enum::Seq(
0,
None,
0,
PrivateStruct(0),
0,
0,
None,
0,
None,
0,
0,
None,
0,
None,
0,
);
assert_eq!(e, e);
let e: Enum<
i32,
i32,
i32,
> = Enum::Map {
m1: 0,
m2: None,
a1: 0,
a2: PrivateStruct(0),
b: 0,
b1: 0,
b2: None,
b3: 0,
b4: None,
c: 0,
c1: 0,
c2: None,
c3: 0,
c4: None,
d: 0,
};
assert_eq!(e, e);
let e: TupleStruct<
i32,
i32,
i32,
> = TupleStruct(
0,
None,
0,
PrivateStruct(0),
0,
0,
None,
0,
None,
0,
0,
None,
0,
None,
0,
);
assert_eq!(e, e);
let e: Struct<
i32,
i32,
i32,
> = Struct {
m1: 0,
m2: None,
a1: 0,
a2: PrivateStruct(0),
b: 0,
b1: 0,
b2: None,
b3: 0,
b4: None,
c: 0,
c1: 0,
c2: None,
c3: 0,
c4: None,
d: 0,
};
assert_eq!(e, e);
let e = Enum::Unit::<i32, i32, i32>;
assert_eq!(e, e);
}

34
tests/run-pass/enums.rs Normal file
View File

@ -0,0 +1,34 @@
enum MyEnum {
MyEmptyVariant,
MyNewtypeVariant(i32),
MyTupleVariant(i32, i32),
MyStructVariant {
my_first_field: i32,
my_second_field: i32,
}
}
fn test(me: MyEnum) {
match me {
MyEnum::MyEmptyVariant => {},
MyEnum::MyNewtypeVariant(ref val) => assert_eq!(val, &42),
MyEnum::MyTupleVariant(ref a, ref b) => {
assert_eq!(a, &43);
assert_eq!(b, &44);
},
MyEnum::MyStructVariant { ref my_first_field, ref my_second_field } => {
assert_eq!(my_first_field, &45);
assert_eq!(my_second_field, &46);
},
}
}
fn main() {
test(MyEnum::MyEmptyVariant);
test(MyEnum::MyNewtypeVariant(42));
test(MyEnum::MyTupleVariant(43, 44));
test(MyEnum::MyStructVariant{
my_first_field: 45,
my_second_field: 46,
});
}