From c9914cd3aeaaeb59e1067205df9b33a3f1c1aa79 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 30 Sep 2016 10:45:52 +0200 Subject: [PATCH] fix enum variants with multiple fields --- src/interpreter/mod.rs | 17 +- tests/run-pass/deriving-associated-types.rs | 208 ++++++++++++++++++++ tests/run-pass/enums.rs | 34 ++++ 3 files changed, 251 insertions(+), 8 deletions(-) create mode 100644 tests/run-pass/deriving-associated-types.rs create mode 100644 tests/run-pass/enums.rs diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 9a15e54bf60..573b5c6f849 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -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), }); } diff --git a/tests/run-pass/deriving-associated-types.rs b/tests/run-pass/deriving-associated-types.rs new file mode 100644 index 00000000000..b67ef85acf6 --- /dev/null +++ b/tests/run-pass/deriving-associated-types.rs @@ -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 or the MIT license +// , 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); + +#[derive(PartialEq, Debug)] +struct TupleStruct( + module::Type, + Option, + A, + PrivateStruct, + B, + B::Type, + Option, + ::Type, + Option<::Type>, + C, + C::Type, + Option, + ::Type, + Option<::Type>, + ::Type, +) where C: WhereTrait; + +#[derive(PartialEq, Debug)] +pub struct Struct where C: WhereTrait { + m1: module::Type, + m2: Option, + a1: A, + a2: PrivateStruct, + b: B, + b1: B::Type, + b2: Option, + b3: ::Type, + b4: Option<::Type>, + c: C, + c1: C::Type, + c2: Option, + c3: ::Type, + c4: Option<::Type>, + d: ::Type, +} + +#[derive(PartialEq, Debug)] +enum Enum where C: WhereTrait { + Unit, + Seq( + module::Type, + Option, + A, + PrivateStruct, + B, + B::Type, + Option, + ::Type, + Option<::Type>, + C, + C::Type, + Option, + ::Type, + Option<::Type>, + ::Type, + ), + Map { + m1: module::Type, + m2: Option, + a1: A, + a2: PrivateStruct, + b: B, + b1: B::Type, + b2: Option, + b3: ::Type, + b4: Option<::Type>, + c: C, + c1: C::Type, + c2: Option, + c3: ::Type, + c4: Option<::Type>, + d: ::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::; + assert_eq!(e, e); +} diff --git a/tests/run-pass/enums.rs b/tests/run-pass/enums.rs new file mode 100644 index 00000000000..1f27292904f --- /dev/null +++ b/tests/run-pass/enums.rs @@ -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, + }); +}