about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libcore/reflect.rs40
-rw-r--r--src/libcore/repr.rs98
-rw-r--r--src/librustc/front/intrinsic.rs6
-rw-r--r--src/librustc/middle/trans/reflect.rs63
-rw-r--r--src/test/run-pass/reflect-visit-data.rs22
5 files changed, 201 insertions, 28 deletions
diff --git a/src/libcore/reflect.rs b/src/libcore/reflect.rs
index a449c4e73cf..9a0526b4351 100644
--- a/src/libcore/reflect.rs
+++ b/src/libcore/reflect.rs
@@ -15,6 +15,7 @@ Runtime type reflection
 */
 
 use intrinsic::{TyDesc, TyVisitor};
+#[cfg(not(stage0))] use intrinsic::Opaque;
 use libc::c_void;
 use sys;
 use vec;
@@ -393,6 +394,7 @@ impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> {
         true
     }
 
+    #[cfg(stage0)]
     fn visit_enter_enum(&self, n_variants: uint, sz: uint, align: uint)
                      -> bool {
         self.align(align);
@@ -402,11 +404,23 @@ impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> {
         true
     }
 
+    #[cfg(not(stage0))]
+    fn visit_enter_enum(&self, n_variants: uint,
+                        get_disr: extern unsafe fn(ptr: *Opaque) -> int,
+                        sz: uint, align: uint)
+                     -> bool {
+        self.align(align);
+        if ! self.inner.visit_enter_enum(n_variants, get_disr, sz, align) {
+            return false;
+        }
+        true
+    }
+
     fn visit_enter_enum_variant(&self, variant: uint,
                                 disr_val: int,
                                 n_fields: uint,
                                 name: &str) -> bool {
-        self.inner.push_ptr();
+        self.inner.push_ptr(); // NOTE remove after next snapshot
         if ! self.inner.visit_enter_enum_variant(variant, disr_val,
                                                  n_fields, name) {
             return false;
@@ -414,6 +428,7 @@ impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> {
         true
     }
 
+    #[cfg(stage0)]
     fn visit_enum_variant_field(&self, i: uint, inner: *TyDesc) -> bool {
         unsafe { self.align((*inner).align); }
         if ! self.inner.visit_enum_variant_field(i, inner) { return false; }
@@ -421,6 +436,15 @@ impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> {
         true
     }
 
+    #[cfg(not(stage0))]
+    fn visit_enum_variant_field(&self, i: uint, offset: uint, inner: *TyDesc) -> bool {
+        self.inner.push_ptr();
+        self.bump(offset);
+        if ! self.inner.visit_enum_variant_field(i, offset, inner) { return false; }
+        self.inner.pop_ptr();
+        true
+    }
+
     fn visit_leave_enum_variant(&self, variant: uint,
                                 disr_val: int,
                                 n_fields: uint,
@@ -429,10 +453,11 @@ impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> {
                                                  n_fields, name) {
             return false;
         }
-        self.inner.pop_ptr();
+        self.inner.pop_ptr(); // NOTE remove after next snapshot
         true
     }
 
+    #[cfg(stage0)]
     fn visit_leave_enum(&self, n_variants: uint, sz: uint, align: uint)
                      -> bool {
         if ! self.inner.visit_leave_enum(n_variants, sz, align) {
@@ -442,6 +467,17 @@ impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> {
         true
     }
 
+    #[cfg(not(stage0))]
+    fn visit_leave_enum(&self, n_variants: uint,
+                        get_disr: extern unsafe fn(ptr: *Opaque) -> int,
+                        sz: uint, align: uint) -> bool {
+        if ! self.inner.visit_leave_enum(n_variants, get_disr, sz, align) {
+            return false;
+        }
+        self.bump(sz);
+        true
+    }
+
     fn visit_trait(&self) -> bool {
         self.align_to::<@TyVisitor>();
         if ! self.inner.visit_trait() { return false; }
diff --git a/src/libcore/repr.rs b/src/libcore/repr.rs
index a51f874f371..530f80ef764 100644
--- a/src/libcore/repr.rs
+++ b/src/libcore/repr.rs
@@ -18,6 +18,7 @@ use cast::transmute;
 use char;
 use intrinsic;
 use intrinsic::{TyDesc, TyVisitor, visit_tydesc};
+#[cfg(not(stage0))] use intrinsic::Opaque;
 use io::{Writer, WriterUtil};
 use libc::c_void;
 use managed;
@@ -137,12 +138,20 @@ impl Repr for char {
 
 // New implementation using reflect::MovePtr
 
+#[cfg(stage0)]
 enum VariantState {
     Degenerate,
     TagMatch,
     TagMismatch,
 }
 
+#[cfg(not(stage0))]
+enum VariantState {
+    SearchingFor(int),
+    Matched,
+    AlreadyFound
+}
+
 pub struct ReprVisitor {
     mut ptr: *c_void,
     mut ptr_stk: ~[*c_void],
@@ -181,14 +190,14 @@ pub impl ReprVisitor {
         true
     }
 
-    #[inline(always)]
+    #[cfg(stage0)] #[inline(always)]
     fn bump(&self, sz: uint) {
       do self.move_ptr() |p| {
             ((p as uint) + sz) as *c_void
       };
     }
 
-    #[inline(always)]
+    #[cfg(stage0)] #[inline(always)]
     fn bump_past<T>(&self) {
         self.bump(sys::size_of::<T>());
     }
@@ -458,6 +467,7 @@ impl TyVisitor for ReprVisitor {
         true
     }
 
+    #[cfg(stage0)]
     fn visit_enter_enum(&self, n_variants: uint,
                         _sz: uint, _align: uint) -> bool {
         if n_variants == 1 {
@@ -468,6 +478,16 @@ impl TyVisitor for ReprVisitor {
         true
     }
 
+    #[cfg(not(stage0))]
+    fn visit_enter_enum(&self, n_variants: uint,
+                        get_disr: extern unsafe fn(ptr: *Opaque) -> int,
+                        _sz: uint, _align: uint) -> bool {
+        let disr = unsafe { get_disr(transmute(self.ptr)) };
+        self.var_stk.push(SearchingFor(disr));
+        true
+    }
+
+    #[cfg(stage0)]
     fn visit_enter_enum_variant(&self, _variant: uint,
                                 disr_val: int,
                                 n_fields: uint,
@@ -500,6 +520,36 @@ impl TyVisitor for ReprVisitor {
         true
     }
 
+    #[cfg(not(stage0))]
+    fn visit_enter_enum_variant(&self, _variant: uint,
+                                disr_val: int,
+                                n_fields: uint,
+                                name: &str) -> bool {
+        let mut write = false;
+        match self.var_stk.pop() {
+            SearchingFor(sought) => {
+                if disr_val == sought {
+                    self.var_stk.push(Matched);
+                    write = true;
+                } else {
+                    self.var_stk.push(SearchingFor(sought));
+                }
+            }
+            Matched | AlreadyFound => {
+                self.var_stk.push(AlreadyFound);
+            }
+        }
+
+        if write {
+            self.writer.write_str(name);
+            if n_fields > 0 {
+                self.writer.write_char('(');
+            }
+        }
+        true
+    }
+
+    #[cfg(stage0)]
     fn visit_enum_variant_field(&self, i: uint, inner: *TyDesc) -> bool {
         match self.var_stk[vec::uniq_len(&const self.var_stk) - 1] {
             Degenerate | TagMatch => {
@@ -515,6 +565,23 @@ impl TyVisitor for ReprVisitor {
         true
     }
 
+    #[cfg(not(stage0))]
+    fn visit_enum_variant_field(&self, i: uint, _offset: uint, inner: *TyDesc) -> bool {
+        match self.var_stk[vec::uniq_len(&const self.var_stk) - 1] {
+            Matched => {
+                if i != 0 {
+                    self.writer.write_str(", ");
+                }
+                if ! self.visit_inner(inner) {
+                    return false;
+                }
+            }
+            _ => ()
+        }
+        true
+    }
+
+    #[cfg(stage0)]
     fn visit_leave_enum_variant(&self, _variant: uint,
                                 _disr_val: int,
                                 n_fields: uint,
@@ -530,12 +597,39 @@ impl TyVisitor for ReprVisitor {
         true
     }
 
+    #[cfg(not(stage0))]
+    fn visit_leave_enum_variant(&self, _variant: uint,
+                                _disr_val: int,
+                                n_fields: uint,
+                                _name: &str) -> bool {
+        match self.var_stk[vec::uniq_len(&const self.var_stk) - 1] {
+            Matched => {
+                if n_fields > 0 {
+                    self.writer.write_char(')');
+                }
+            }
+            _ => ()
+        }
+        true
+    }
+
+    #[cfg(stage0)]
     fn visit_leave_enum(&self, _n_variants: uint,
                         _sz: uint, _align: uint) -> bool {
         self.var_stk.pop();
         true
     }
 
+    #[cfg(not(stage0))]
+    fn visit_leave_enum(&self, _n_variants: uint,
+                        _get_disr: extern unsafe fn(ptr: *Opaque) -> int,
+                        _sz: uint, _align: uint) -> bool {
+        match self.var_stk.pop() {
+            SearchingFor(*) => fail!(~"enum value matched no variant"),
+            _ => true
+        }
+    }
+
     fn visit_enter_fn(&self, _purity: uint, _proto: uint,
                       _n_inputs: uint, _retstyle: uint) -> bool { true }
     fn visit_fn_input(&self, _i: uint, _mode: uint, _inner: *TyDesc) -> bool {
diff --git a/src/librustc/front/intrinsic.rs b/src/librustc/front/intrinsic.rs
index 7d5177a6dfb..dcf300bd31d 100644
--- a/src/librustc/front/intrinsic.rs
+++ b/src/librustc/front/intrinsic.rs
@@ -28,6 +28,8 @@ pub mod intrinsic {
         // Remaining fields not listed
     }
 
+    pub enum Opaque { }
+
     pub trait TyVisitor {
         fn visit_bot(&self) -> bool;
         fn visit_nil(&self) -> bool;
@@ -91,17 +93,19 @@ pub mod intrinsic {
                            sz: uint, align: uint) -> bool;
 
         fn visit_enter_enum(&self, n_variants: uint,
+                            get_disr: extern unsafe fn(ptr: *Opaque) -> int,
                             sz: uint, align: uint) -> bool;
         fn visit_enter_enum_variant(&self, variant: uint,
                                     disr_val: int,
                                     n_fields: uint,
                                     name: &str) -> bool;
-        fn visit_enum_variant_field(&self, i: uint, inner: *TyDesc) -> bool;
+        fn visit_enum_variant_field(&self, i: uint, offset: uint, inner: *TyDesc) -> bool;
         fn visit_leave_enum_variant(&self, variant: uint,
                                     disr_val: int,
                                     n_fields: uint,
                                     name: &str) -> bool;
         fn visit_leave_enum(&self, n_variants: uint,
+                            get_disr: extern unsafe fn(ptr: *Opaque) -> int,
                             sz: uint, align: uint) -> bool;
 
         fn visit_enter_fn(&self, purity: uint, proto: uint,
diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs
index 224981d6e75..596c55a68f8 100644
--- a/src/librustc/middle/trans/reflect.rs
+++ b/src/librustc/middle/trans/reflect.rs
@@ -8,8 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-
-use lib::llvm::{TypeRef, ValueRef};
+use back::link::mangle_internal_name_by_path_and_seq;
+use lib::llvm::{TypeRef, ValueRef, llvm};
+use middle::trans::adt;
 use middle::trans::base::*;
 use middle::trans::build::*;
 use middle::trans::callee::{ArgVals, DontAutorefArg};
@@ -24,10 +25,13 @@ use middle::trans::type_of::*;
 use middle::ty;
 use util::ppaux::ty_to_str;
 
+use core::libc::c_uint;
 use core::option::None;
 use core::vec;
 use syntax::ast::def_id;
 use syntax::ast;
+use syntax::ast_map::path_name;
+use syntax::parse::token::special_idents;
 
 pub struct Reflector {
     visitor_val: ValueRef,
@@ -266,23 +270,52 @@ pub impl Reflector {
           // variant?
           ty::ty_enum(did, ref substs) => {
             let bcx = self.bcx;
-            let tcx = bcx.ccx().tcx;
-            let variants = ty::substd_enum_variants(tcx, did, substs);
+            let ccx = bcx.ccx();
+            let repr = adt::represent_type(bcx.ccx(), t);
+            let variants = ty::substd_enum_variants(ccx.tcx, did, substs);
+            let llptrty = T_ptr(type_of(ccx, t));
+            let (_, opaquety) = *(ccx.tcx.intrinsic_defs.find(&ccx.sess.ident_of(~"Opaque"))
+                                      .expect("Failed to resolve intrinsic::Opaque"));
+            let opaqueptrty = ty::mk_ptr(ccx.tcx, ty::mt { ty: opaquety, mutbl: ast::m_imm });
+
+            let make_get_disr = || {
+                let sub_path = bcx.fcx.path + ~[path_name(special_idents::anon)];
+                let sym = mangle_internal_name_by_path_and_seq(ccx, sub_path, ~"get_disr");
+                let args = [ty::arg { mode: ast::expl(ast::by_copy),
+                                      ty: opaqueptrty }];
+                let llfty = type_of_fn(ccx, args, ty::mk_int(ccx.tcx));
+                let llfdecl = decl_internal_cdecl_fn(ccx.llmod, sym, llfty);
+                let arg = unsafe {
+                    llvm::LLVMGetParam(llfdecl, first_real_arg as c_uint)
+                };
+                let fcx = new_fn_ctxt(ccx, ~[], llfdecl, None);
+                let bcx = top_scope_block(fcx, None);
+                let arg = BitCast(bcx, arg, llptrty);
+                let ret = adt::trans_get_discr(bcx, repr, arg);
+                Store(bcx, ret, fcx.llretptr);
+                cleanup_and_Br(bcx, bcx, fcx.llreturn);
+                finish_fn(fcx, bcx.llbb);
+                llfdecl
+            };
 
-            let extra = ~[self.c_uint(vec::len(variants))]
+            let enum_args = ~[self.c_uint(vec::len(variants)), make_get_disr()]
                 + self.c_size_and_align(t);
-            do self.bracketed(~"enum", extra) |this| {
+            do self.bracketed(~"enum", enum_args) |this| {
                 for variants.eachi |i, v| {
-                    let extra1 = ~[this.c_uint(i),
-                                   this.c_int(v.disr_val),
-                                   this.c_uint(vec::len(v.args)),
-                                   this.c_slice(
-                                       bcx.ccx().sess.str_of(v.name))];
-                    do this.bracketed(~"enum_variant", extra1) |this| {
+                    let variant_args = ~[this.c_uint(i),
+                                         this.c_int(v.disr_val),
+                                         this.c_uint(vec::len(v.args)),
+                                         this.c_slice(ccx.sess.str_of(v.name))];
+                    do this.bracketed(~"enum_variant", variant_args) |this| {
                         for v.args.eachi |j, a| {
-                            let extra = ~[this.c_uint(j),
-                                          this.c_tydesc(*a)];
-                            this.visit(~"enum_variant_field", extra);
+                            let bcx = this.bcx;
+                            let null = C_null(llptrty);
+                            let offset = p2i(ccx, adt::trans_field_ptr(bcx, repr, null,
+                                                                       v.disr_val, j));
+                            let field_args = ~[this.c_uint(j),
+                                               offset,
+                                               this.c_tydesc(*a)];
+                            this.visit(~"enum_variant_field", field_args);
                         }
                     }
                 }
diff --git a/src/test/run-pass/reflect-visit-data.rs b/src/test/run-pass/reflect-visit-data.rs
index a27599e6ed0..8f3a1dd90c2 100644
--- a/src/test/run-pass/reflect-visit-data.rs
+++ b/src/test/run-pass/reflect-visit-data.rs
@@ -13,7 +13,7 @@
 use core::bool;
 use core::libc::c_void;
 use core::vec::UnboxedVecRepr;
-use intrinsic::{TyDesc, get_tydesc, visit_tydesc, TyVisitor};
+use intrinsic::{TyDesc, get_tydesc, visit_tydesc, TyVisitor, Opaque};
 
 #[doc = "High-level interfaces to `intrinsic::visit_ty` reflection system."]
 
@@ -376,10 +376,12 @@ impl<V:TyVisitor + movable_ptr> TyVisitor for ptr_visit_adaptor<V> {
         true
     }
 
-    fn visit_enter_enum(&self, n_variants: uint, sz: uint, align: uint)
+    fn visit_enter_enum(&self, n_variants: uint,
+                        get_disr: extern unsafe fn(ptr: *Opaque) -> int,
+                        sz: uint, align: uint)
                      -> bool {
         self.align(align);
-        if ! self.inner.visit_enter_enum(n_variants, sz, align) { return false; }
+        if ! self.inner.visit_enter_enum(n_variants, get_disr, sz, align) { return false; }
         true
     }
 
@@ -394,8 +396,8 @@ impl<V:TyVisitor + movable_ptr> TyVisitor for ptr_visit_adaptor<V> {
         true
     }
 
-    fn visit_enum_variant_field(&self, i: uint, inner: *TyDesc) -> bool {
-        if ! self.inner.visit_enum_variant_field(i, inner) { return false; }
+    fn visit_enum_variant_field(&self, i: uint, offset: uint, inner: *TyDesc) -> bool {
+        if ! self.inner.visit_enum_variant_field(i, offset, inner) { return false; }
         true
     }
 
@@ -410,9 +412,11 @@ impl<V:TyVisitor + movable_ptr> TyVisitor for ptr_visit_adaptor<V> {
         true
     }
 
-    fn visit_leave_enum(&self, n_variants: uint, sz: uint, align: uint)
+    fn visit_leave_enum(&self, n_variants: uint,
+                        get_disr: extern unsafe fn(ptr: *Opaque) -> int,
+                        sz: uint, align: uint)
                      -> bool {
-        if ! self.inner.visit_leave_enum(n_variants, sz, align) { return false; }
+        if ! self.inner.visit_leave_enum(n_variants, get_disr, sz, align) { return false; }
         true
     }
 
@@ -586,6 +590,7 @@ impl TyVisitor for my_visitor {
                        _sz: uint, _align: uint) -> bool { true }
 
     fn visit_enter_enum(&self, _n_variants: uint,
+                        _get_disr: extern unsafe fn(ptr: *Opaque) -> int,
                         _sz: uint, _align: uint) -> bool {
         // FIXME (#3732): this needs to rewind between enum variants, or something.
         true
@@ -594,7 +599,7 @@ impl TyVisitor for my_visitor {
                                 _disr_val: int,
                                 _n_fields: uint,
                                 _name: &str) -> bool { true }
-    fn visit_enum_variant_field(&self, _i: uint, inner: *TyDesc) -> bool {
+    fn visit_enum_variant_field(&self, _i: uint, _offset: uint, inner: *TyDesc) -> bool {
         self.visit_inner(inner)
     }
     fn visit_leave_enum_variant(&self, _variant: uint,
@@ -602,6 +607,7 @@ impl TyVisitor for my_visitor {
                                 _n_fields: uint,
                                 _name: &str) -> bool { true }
     fn visit_leave_enum(&self, _n_variants: uint,
+                        _get_disr: extern unsafe fn(ptr: *Opaque) -> int,
                         _sz: uint, _align: uint) -> bool { true }
 
     fn visit_enter_fn(&self, _purity: uint, _proto: uint,