Repository: gluon-lang/gluon
Pull request #302 (2017-06-20 19:36:09)

Various fixes
See individual commits


Patch:
diff --git a/.travis.yml b/.travis.yml
index c943f4af..269946cd 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -21,10 +21,8 @@ script:
 - |
   sh ./test-no-skeptic.sh &&
   travis-cargo --only nightly test -- --features "test nightly" -p gluon compile_test &&
-  cargo build --release &&
-  cargo build --release -p gluon_repl &&
   travis-cargo --only nightly bench &&
-  cargo build --all --no-default-features
+  travis-cargo --only stable build -- --all --no-default-features
 env:
   global:
   - TRAVIS_CARGO_NIGHTLY_FEATURE="nightly"
diff --git a/vm/src/api/de.rs b/vm/src/api/de.rs
index effd7267..9279bbb2 100644
--- a/vm/src/api/de.rs
+++ b/vm/src/api/de.rs
@@ -207,22 +207,6 @@ struct Deserializer<'de, 't> {
 }
 
 impl<'de, 't> Deserializer<'de, 't> {
-    fn from_value(
-        thread: &'de Thread,
-        env: &'de TypeEnv,
-        input: Variants<'de>,
-        typ: &'t ArcType,
-    ) -> Self {
-        Deserializer {
-            state: State {
-                thread: thread,
-                env: env,
-            },
-            input: input,
-            typ: typ,
-        }
-    }
-
     fn deserialize_builtin<T, F, R>(&self, expected: BuiltinType, visit: F) -> Result<R>
     where
         F: FnOnce(T) -> Result<R>,
@@ -238,6 +222,7 @@ impl<'de, 't> Deserializer<'de, 't> {
         T: Getable<'de>,
     {
         let typ = resolve::remove_aliases_cow(self.state.env, self.typ);
+        println!("{}   {:?}", typ, typ);
         match T::from_value(self.state.thread, self.input) {
             Some(c) => {
                 if expected(&typ) {
@@ -536,9 +521,9 @@ impl<'de, 't, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de, 't> {
             (ValueRef::Data(data), &Type::Variant(ref row)) => {
                 match row.row_iter().nth(data.tag() as usize) {
                     Some(field) => {
-                        let iter = (0..data.len()).map(|i| data.get_variants(i).unwrap()).zip(
-                            arg_iter(&field.typ),
-                        );
+                        let iter = (0..data.len())
+                            .map(|i| data.get_variants(i).unwrap())
+                            .zip(arg_iter(&field.typ));
                         visitor.visit_seq(SeqDeserializer::new(self.state.clone(), iter))
                     }
                     None => self.deserialize_any(visitor),
@@ -641,12 +626,7 @@ impl<'de, 't, I> SeqDeserializer<'de, 't, I> {
 
 impl<'de, 't, I> SeqAccess<'de> for SeqDeserializer<'de, 't, I>
 where
-    I: Iterator<
-        Item = (
-            Variants<'de>,
-            &'t ArcType,
-        ),
-    >,
+    I: Iterator<Item = (Variants<'de>, &'t ArcType)>,
 {
     type Error = VmError;
 
@@ -685,13 +665,7 @@ impl<'de, 't, I> MapDeserializer<'de, 't, I> {
 
 impl<'de, 'a, 't, I> MapAccess<'de> for MapDeserializer<'de, 't, I>
 where
-    I: Iterator<
-        Item = (
-            Variants<'de>,
-            &'t Symbol,
-            &'t ArcType,
-        ),
-    >,
+    I: Iterator<Item = (Variants<'de>, &'t Symbol, &'t ArcType)>,
 {
     type Error = VmError;
 
@@ -702,9 +676,8 @@ where
         match self.iter.next() {
             Some((value, field, typ)) => {
                 self.value = Some((value, typ));
-                seed.deserialize(field.as_ref().into_deserializer()).map(
-                    Some,
-                )
+                seed.deserialize(field.as_ref().into_deserializer())
+                    .map(Some)
             }
             None => Ok(None),
         }
@@ -761,9 +734,10 @@ impl<'a, 'b, 'de, 't> de::Deserializer<'de> for &'b mut Enum<'a, 'de, 't> {
         let typ = resolve::remove_aliases_cow(self.de.state.env, self.de.typ);
         match **typ {
             Type::Variant(ref variants) => {
-                let variant = variants.row_iter().nth(tag as usize).ok_or_else(|| {
-                    Self::Error::custom("Unable to deserialize tag")
-                })?;
+                let variant = variants
+                    .row_iter()
+                    .nth(tag as usize)
+                    .ok_or_else(|| Self::Error::custom("Unable to deserialize tag"))?;
                 visitor.visit_str(variant.name.as_ref())
             }
             _ => return Err(Self::Error::custom("Unable to deserialize tag")),
@@ -807,14 +781,32 @@ impl<'de, 'a, 't> VariantAccess<'de> for Enum<'a, 'de, 't> {
     where
         T: DeserializeSeed<'de>,
     {
-        match self.de.input.as_ref() {
-            ValueRef::Data(data) if data.len() == 1 => {
-                seed.deserialize(&mut Deserializer {
-                    input: data.get_variants(0).unwrap(),
-                    ..self.de.clone()
-                })
+        let typ = resolve::remove_aliases_cow(self.de.state.env, self.de.typ);
+        match (self.de.input.as_ref(), &**typ) {
+            (ValueRef::Data(data), &Type::Variant(ref row)) => {
+                match row.row_iter().nth(data.tag() as usize) {
+                    Some(field) => {
+                        seed.deserialize(&mut Deserializer {
+                            input: data.get_variants(0)
+                                .ok_or_else(|| {
+                                    VmError::Message(
+                                        "Expected variant to have a value argument".into(),
+                                    )
+                                })?,
+                            typ: arg_iter(&field.typ)
+                                .next()
+                                .ok_or_else(|| {
+                                    VmError::Message(
+                                        "Expected variant to have a type argument".into(),
+                                    )
+                                })?,
+                            ..self.de.clone()
+                        })
+                    }
+                    None => seed.deserialize(self.de),
+                }
             }
-            _ => Err(VmError::Message(format!("Unable to deserialize bool"))),
+            _ => seed.deserialize(self.de),
         }
     }
 
diff --git a/vm/src/api/mod.rs b/vm/src/api/mod.rs
index cae7b7e9..4e426f0e 100644
--- a/vm/src/api/mod.rs
+++ b/vm/src/api/mod.rs
@@ -135,9 +135,10 @@ impl<'a> Data<'a> {
         match self.0 {
             DataInner::Tag(_) => None,
             DataInner::Data(data) => unsafe {
-                thread.lookup_field(data, name).ok().map(|v| {
-                    Variants::with_root(v, data)
-                })
+                thread
+                    .lookup_field(data, name)
+                    .ok()
+                    .map(|v| Variants::with_root(v, data))
             },
         }
     }
@@ -1089,20 +1090,22 @@ impl<'vm> ArrayRef<'vm> {
 /// Type which represents an array
 pub struct Array<'vm, T>(RootedValue<&'vm Thread>, PhantomData<T>);
 
-impl<'vm, T> Deref for Array<'vm, T> {
-    type Target = ValueArray;
-    fn deref(&self) -> &ValueArray {
-        match *self.0 {
-            Value::Array(ref data) => data,
-            _ => panic!("Expected an array found {:?}", self.0),
-        }
-    }
-}
-
 impl<'vm, T> Array<'vm, T> {
     pub fn vm(&self) -> &'vm Thread {
         self.0.vm_()
     }
+
+    pub fn len(&self) -> usize {
+        self.get_value_array().len()
+    }
+
+    #[doc(hidden)]
+    pub fn get_value_array(&self) -> &ValueArray {
+        match *self.0 {
+            Value::Array(ref array) => array,
+            _ => panic!("Expected an array found {:?}", self.0),
+        }
+    }
 }
 
 impl<'vm, T: for<'vm2> Getable<'vm2>> Array<'vm, T> {
@@ -1352,7 +1355,8 @@ pub mod record {
     }
 
     impl<'vm, F: Field, H: Pushable<'vm>, T> PushableFieldList<'vm> for HList<(F, H), T>
-        where T: PushableFieldList<'vm>
+    where
+        T: PushableFieldList<'vm>,
     {
         fn push(self, vm: &'vm Thread, fields: &mut Context) -> Result<()> {
             let HList((_, head), tail) = self;
@@ -1432,11 +1436,8 @@ pub mod record {
         fn from_value(vm: &'vm Thread, value: Variants) -> Option<Self> {
             match value.0 {
                 Value::Data(ref data) => {
-                    HList::<(F, A), T>::from_value(vm, &data.fields).map(
-                        |fields| {
-                            Record { fields: fields }
-                        },
-                    )
+                    HList::<(F, A), T>::from_value(vm, &data.fields)
+                        .map(|fields| Record { fields: fields })
                 }
                 _ => None,
             }
diff --git a/vm/src/array.rs b/vm/src/array.rs
index f2455248..61881772 100644
--- a/vm/src/array.rs
+++ b/vm/src/array.rs
@@ -88,9 +88,9 @@ impl<T: Copy> Array<T> {
         I: IntoIterator<Item = T>,
     {
         let iter = iterable.into_iter();
-        self.len = iter.size_hint().1.expect(
-            "initialize expected a known length",
-        );
+        self.len = iter.size_hint()
+            .1
+            .expect("initialize expected a known length");
         for (field, value) in self.iter_mut().zip(iter) {
             *field = value;
         }
diff --git a/vm/src/channel.rs b/vm/src/channel.rs
index c18205a1..1cbc526d 100644
--- a/vm/src/channel.rs
+++ b/vm/src/channel.rs
@@ -213,15 +213,9 @@ pub fn load<'vm>(vm: &'vm Thread) -> VmResult<()> {
     vm.define_global("send", primitive!(2 send))?;
     vm.define_global(
         "resume",
-        primitive::<fn(&'vm Thread) -> Result<(), String>>(
-            "resume",
-            resume,
-        ),
-    )?;
-    vm.define_global(
-        "yield",
-        primitive::<fn(())>("yield", yield_),
+        primitive::<fn(&'vm Thread) -> Result<(), String>>("resume", resume),
     )?;
+    vm.define_global("yield", primitive::<fn(())>("yield", yield_))?;
     vm.define_global("spawn", primitive!(1 spawn))?;
     Ok(())
 }
diff --git a/vm/src/compiler.rs b/vm/src/compiler.rs
index e6d90521..4262ef36 100644
--- a/vm/src/compiler.rs
+++ b/vm/src/compiler.rs
@@ -139,21 +139,18 @@ impl FunctionEnvs {
         compiler.stack_constructors.exit_scope();
         let instructions = self.function.instructions.len();
         if compiler.emit_debug_info {
-            self.function.debug_info.source_map.close(
-                instructions,
-                current_line,
-            );
+            self.function
+                .debug_info
+                .source_map
+                .close(instructions, current_line);
             let function = &mut **self;
             function.function.debug_info.upvars.extend(
-                function
-                    .free_vars
-                    .iter()
-                    .map(|&(ref name, ref typ)| {
-                        UpvarInfo {
-                            name: name.declared_name().to_string(),
-                            typ: typ.clone(),
-                        }
-                    }),
+                function.free_vars.iter().map(|&(ref name, ref typ)| {
+                    UpvarInfo {
+                        name: name.declared_name().to_string(),
+                        typ: typ.clone(),
+                    }
+                }),
             );
         }
         self.envs.pop().expect("FunctionEnv in scope")
@@ -194,11 +191,10 @@ impl FunctionEnv {
         self.function.instructions.push(instruction);
 
         if self.emit_debug_info {
-            self.function.debug_info.source_map.emit(
-                self.function.instructions.len() -
-                    1,
-                self.current_line,
-            );
+            self.function
+                .debug_info
+                .source_map
+                .emit(self.function.instructions.len() - 1, self.current_line);
         }
     }
 
@@ -219,9 +215,9 @@ impl FunctionEnv {
     }
 
     fn emit_field(&mut self, compiler: &mut Compiler, typ: &ArcType, field: &Symbol) -> Result<()> {
-        let field_index = compiler.find_field(typ, field).expect(
-            "ICE: Undefined field in field access",
-        );
+        let field_index = compiler
+            .find_field(typ, field)
+            .expect("ICE: Undefined field in field access");
         match field_index {
             FieldAccess::Index(i) => self.emit(GetOffset(i)),
             FieldAccess::Name => {
@@ -298,11 +294,10 @@ impl FunctionEnv {
             count += 1;
             debug!("Pop var: {:?}", x);
             if self.emit_debug_info && compiler.empty_symbol != x.0 {
-                self.function.debug_info.local_map.close(
-                    self.function
-                        .instructions
-                        .len(),
-                );
+                self.function
+                    .debug_info
+                    .local_map
+                    .close(self.function.instructions.len());
             }
         }
         count
@@ -326,9 +321,9 @@ impl CompilerEnv for TypeInfos {
             .iter()
             .filter_map(|(_, ref alias)| match **alias.unresolved_type() {
                 Type::Variant(ref row) => {
-                    row.row_iter().enumerate().find(
-                        |&(_, field)| field.name == *id,
-                    )
+                    row.row_iter()
+                        .enumerate()
+                        .find(|&(_, field)| field.name == *id)
                 }
                 _ => None,
             })
@@ -412,9 +407,9 @@ impl<'a> Compiler<'a> {
             .iter()
             .filter_map(|(_, typ)| match **typ {
                 Type::Variant(ref row) => {
-                    row.row_iter().enumerate().find(
-                        |&(_, field)| field.name == *id,
-                    )
+                    row.row_iter()
+                        .enumerate()
+                        .find(|&(_, field)| field.name == *id)
                 }
                 _ => None,
             })
@@ -436,9 +431,9 @@ impl<'a> Compiler<'a> {
                         rest.iter()
                             .rev()
                             .filter_map(|env| {
-                                env.stack.get(id).map(|&(_, ref typ)| {
-                                    UpVar(current[0].upvar(id, typ))
-                                })
+                                env.stack
+                                    .get(id)
+                                    .map(|&(_, ref typ)| UpVar(current[0].upvar(id, typ)))
                             })
                             .next()
                     })
@@ -447,11 +442,11 @@ impl<'a> Compiler<'a> {
         variable.map(|variable| match variable {
             Stack(i) => Stack(i),
             Global(s) => {
-                let existing = current.function.module_globals.iter().position(
-                    |existing| {
-                        existing == &s
-                    },
-                );
+                let existing = current
+                    .function
+                    .module_globals
+                    .iter()
+                    .position(|existing| existing == &s);
                 Global(existing.unwrap_or_else(|| {
                     current.function.module_globals.push(s);
                     current.function.module_globals.len() - 1
@@ -517,9 +512,8 @@ impl<'a> Compiler<'a> {
     }
 
     fn load_identifier(&self, id: &Symbol, function: &mut FunctionEnvs) -> Result<()> {
-        match self.find(id, function).unwrap_or_else(|| {
-            panic!("Undefined variable {}", self.symbols.string(&id))
-        }) {
+        match self.find(id, function)
+            .unwrap_or_else(|| panic!("Undefined variable {}", self.symbols.string(&id))) {
             Stack(index) => function.emit(Push(index)),
             UpVar(index) => function.emit(PushUpVar(index)),
             Global(index) => function.emit(PushGlobal(index)),
@@ -634,12 +628,7 @@ impl<'a> Compiler<'a> {
                     if id.name.as_ref() == "&&" || id.name.as_ref() == "||" ||
                         id.name.as_ref().starts_with('#')
                     {
-                        self.compile_primitive(
-                            &id.name,
-                            args,
-                            function,
-                            tail_position,
-                        )?;
+                        self.compile_primitive(&id.name, args, function, tail_position)?;
                         return Ok(None);
                     }
 
@@ -674,7 +663,7 @@ impl<'a> Compiler<'a> {
                             let tag = self.find_tag(&typ, &id.name).unwrap_or_else(|| {
                                 panic!(
                                     "ICE: Could not find tag for {}::{} when matching on \
-                                            expression `{}`",
+                                     expression `{}`",
                                     types::display_type(&self.symbols, &typ),
                                     self.symbols.string(&id.name),
                                     expr
@@ -749,10 +738,9 @@ impl<'a> Compiler<'a> {
                 let typ = resolve::remove_aliases_cow(self, &id.typ);
                 match **typ {
                     Type::Record(_) => {
-                        let index =
-                            function.add_record_map(
-                                typ.row_iter().map(|field| field.name.clone()).collect(),
-                            );
+                        let index = function.add_record_map(
+                            typ.row_iter().map(|field| field.name.clone()).collect(),
+                        );
                         function.emit(ConstructRecord {
                             record: index,
                             args: exprs.len() as u32,
@@ -894,9 +882,9 @@ impl<'a> Compiler<'a> {
                         } else {
                             function.emit(Split);
                             for field in typ.row_iter() {
-                                let (name, typ) = match fields.iter().find(|tup| {
-                                    tup.0.name.name_eq(&field.name)
-                                }) {
+                                let (name, typ) = match fields
+                                    .iter()
+                                    .find(|tup| tup.0.name.name_eq(&field.name)) {
                                     Some(&(ref name, ref bind)) => {
                                         (
                                             bind.as_ref().unwrap_or(&name.name).clone(),
diff --git a/vm/src/primitives.rs b/vm/src/primitives.rs
index 3ad888f8..dc99b6c2 100644
--- a/vm/src/primitives.rs
+++ b/vm/src/primitives.rs
@@ -9,7 +9,7 @@ use api::generic::A;
 use gc::{Gc, Traverseable, DataDef, WriteOnly};
 use Result;
 use vm::{Thread, Status};
-use value::{Def, GcStr, Value, ValueArray};
+use value::{Def, GcStr, Repr, Value, ValueArray};
 use stack::StackFrame;
 use thread::ThreadInternal;
 use types::VmInt;
@@ -37,6 +37,18 @@ fn array_append<'vm>(
         rhs: &'b ValueArray,
     }
 
+    impl<'b> Append<'b> {
+        fn repr(&self) -> Repr {
+            // Empty arrays don't have the correct representation set so choose the representation
+            // of `rhs` if it is empty. (And if both are empty the representation does not matter).
+            if self.lhs.len() == 0 {
+                self.rhs.repr()
+            } else {
+                self.lhs.repr()
+            }
+        }
+    }
+
     impl<'b> Traverseable for Append<'b> {
         fn traverse(&self, gc: &mut Gc) {
             self.lhs.traverse(gc);
@@ -47,21 +59,13 @@ fn array_append<'vm>(
     unsafe impl<'b> DataDef for Append<'b> {
         type Value = ValueArray;
         fn size(&self) -> usize {
-            use std::mem::size_of;
             let len = self.lhs.len() + self.rhs.len();
-            size_of::<usize>() + ::array::Array::<Value>::size_of(len)
+            ValueArray::size_of(self.repr(), len)
         }
         fn initialize<'w>(self, mut result: WriteOnly<'w, ValueArray>) -> &'w mut ValueArray {
-            // Empty arrays don't have the correct representation set so choose the representation
-            // of `rhs` if it is empty. (And if both are empty the representation does not matter).
-            let repr = if self.lhs.len() == 0 {
-                self.rhs.repr()
-            } else {
-                self.lhs.repr()
-            };
             unsafe {
                 let result = &mut *result.as_mut_ptr();
-                result.set_repr(repr);
+                result.set_repr(self.repr());
                 result.initialize(self.lhs.iter().chain(self.rhs.iter()));
                 result
             }
@@ -71,8 +75,8 @@ fn array_append<'vm>(
     let value = {
         let mut context = vm.context();
         let result = context.alloc(Append {
-            lhs: &lhs,
-            rhs: &rhs,
+            lhs: lhs.get_value_array(),
+            rhs: rhs.get_value_array(),
         });
         match result {
             Ok(x) => x,


Test patch:
diff --git a/tests/de.rs b/tests/de.rs
index ef1dcbc0..38ab1fed 100644
--- a/tests/de.rs
+++ b/tests/de.rs
@@ -149,7 +149,7 @@ fn optional_field() {
 
 #[derive(Debug, PartialEq, Deserialize)]
 enum Enum {
-    A(i32),
+    A(String),
     B { string: String, test: f64 },
     C(i32, i32),
 }
@@ -172,10 +172,20 @@ fn enum_() {
         .load_script(
             &thread,
             "test",
-            r#" type Enum = | A Int | B String Float | C Int Int in { Enum } "#,
+            r#" type Enum = | A String | B String Float | C Int Int in { Enum } "#,
         )
         .unwrap_or_else(|err| panic!("{}", err));
 
+    let (De(enum_), _) = Compiler::new()
+        .implicit_prelude(false)
+        .run_expr::<De<Enum>>(
+            &thread,
+            "test",
+            r#" let { Enum } = import! "test" in A "abc" "#,
+        )
+        .unwrap_or_else(|err| panic!("{}", err));
+    assert_eq!(enum_, Enum::A("abc".to_string()));
+
     let (De(enum_), _) = Compiler::new()
         .implicit_prelude(false)
         .run_expr::<De<Enum>>(