Repository: gluon-lang/gluon
Pull request #635 (2018-09-22 21:41:23)

test: Try to make rexpect tests more reliable
The flakiness may be because some output matches the prompt that is used
so set a unique one.

cc #625


Patch:
diff --git a/codegen/src/vm_type.rs b/codegen/src/vm_type.rs
index edfbd4d3..392a629b 100644
--- a/codegen/src/vm_type.rs
+++ b/codegen/src/vm_type.rs
@@ -1,6 +1,6 @@
 use proc_macro2::{Ident, TokenStream};
 use shared::{map_lifetimes, map_type_params, split_for_impl};
-use syn::{self, Data, DeriveInput, Fields, GenericParam, Generics};
+use syn::{self, Data, DeriveInput, Fields, Generics};
 
 use attr::Container;
 
@@ -26,7 +26,7 @@ pub fn derive(input: TokenStream) -> TokenStream {
 
 fn gen_impl(container: &Container, ident: Ident, generics: Generics, data: &Data) -> TokenStream {
     let trait_bounds = &map_type_params(&generics, |ty| {
-        quote! { #ty: ::gluon::vm::api::VmType, #ty::Type: Sized }
+        quote! { #ty: 'static + ::gluon::vm::api::VmType }
     });
 
     let lifetime_bounds = &map_lifetimes(&generics, |lifetime| quote! { #lifetime: 'static });
@@ -86,21 +86,13 @@ fn gen_impl(container: &Container, ident: Ident, generics: Generics, data: &Data
         },
     };
 
-    let associated_type_generics = generics.params.iter().map(|param| match param {
-        GenericParam::Type(ty) => quote!( #ty :: Type ),
-        GenericParam::Lifetime(lt) => quote!( #lt ),
-        GenericParam::Const(c) => quote!( #c ),
-    });
-
     quote! {
         #[automatically_derived]
         #[allow(unused_attributes, unused_variables)]
         impl #impl_generics ::gluon::vm::api::VmType for #ident #ty_generics
         #where_clause #(#trait_bounds,)* #(#lifetime_bounds),*
         {
-            type Type = #ident<
-                    #(#associated_type_generics),*
-                >;
+            type Type = Self;
 
             fn make_type(vm: &::gluon::vm::thread::Thread) -> ::gluon::base::types::ArcType {
                 #make_type_impl
diff --git a/examples/marshalling.rs b/examples/marshalling.rs
index 1c9d75bf..a8f2535f 100644
--- a/examples/marshalling.rs
+++ b/examples/marshalling.rs
@@ -16,7 +16,7 @@ use gluon::base::types::ArcType;
 use gluon::base::types::{AppVec, Type};
 use gluon::vm::api::generic::{A, L, R};
 use gluon::vm::api::{
-    self, ActiveThread, FunctionRef, Getable, Hole, OpaqueRef, OpaqueValue, Pushable,
+    self, ActiveThread, FunctionRef, Getable, Hole, OpaqueValue, Pushable,
     UserdataValue, ValueRef, VmType, IO,
 };
 use gluon::vm::{self, ExternModule, Variants};
@@ -153,12 +153,9 @@ where
 
 // the function takes an Either instantiated with the `Opaque*` struct,
 // which will handle the generic Gluon values for us.
-//
-// We use the `OpaqueRef` alias here since we only need temporary (borrowed) access and it avoids
-// the cost of reference counted rooting.
-fn flip<'a>(
-    either: Either<OpaqueRef<'a, L>, OpaqueRef<'a, R>>,
-) -> Either<OpaqueRef<'a, R>, OpaqueRef<'a, L>> {
+fn flip(
+    either: Either<OpaqueValue<RootedThread, L>, OpaqueValue<RootedThread, R>>,
+) -> Either<OpaqueValue<RootedThread, R>, OpaqueValue<RootedThread, L>> {
     match either {
         Either::Left(val) => Either::Right(val),
         Either::Right(val) => Either::Left(val),
diff --git a/repl/src/main.rs b/repl/src/main.rs
index b1f16cfb..0408d6e3 100644
--- a/repl/src/main.rs
+++ b/repl/src/main.rs
@@ -14,6 +14,7 @@ extern crate log;
 #[macro_use]
 extern crate serde_derive;
 extern crate structopt;
+#[allow(unused_imports)]
 #[macro_use]
 extern crate structopt_derive;
 extern crate tokio;
@@ -141,17 +142,28 @@ const LONG_VERSION: &str = concat!(crate_version!(), "\n", "commit: ", env!("GIT
 pub struct Opt {
     #[structopt(short = "i", long = "interactive", help = "Starts the repl")]
     interactive: bool,
+
     #[structopt(
         long = "color",
         default_value = "auto",
         help = "Coloring: auto, always, always-ansi, never"
     )]
     color: Color,
+
+    #[structopt(
+        long = "prompt",
+        short = "p",
+        default_value = "> ",
+        help = "String printed as the prompt for the repl"
+    )]
+    prompt: String,
+
     #[structopt(
         name = "FILE",
         help = "Executes each file as a gluon program"
     )]
     input: Vec<String>,
+
     #[structopt(subcommand)]
     subcommand_opt: Option<SubOpt>,
 }
@@ -270,7 +282,8 @@ fn run(
         }
         None => if opt.interactive {
             let mut runtime = Runtime::new()?;
-            runtime.block_on(future::lazy(move || repl::run(color)))?;
+            let prompt = opt.prompt.clone();
+            runtime.block_on(future::lazy(move || repl::run(color, &prompt)))?;
         } else if !opt.input.is_empty() {
             run_files(compiler, &vm, &opt.input)?;
         } else {
diff --git a/repl/src/repl.glu b/repl/src/repl.glu
index 4e501ad0..9b576cd9 100644
--- a/repl/src/repl.glu
+++ b/repl/src/repl.glu
@@ -167,7 +167,13 @@ let store line : String -> IO ReplAction =
         io.load_script binding expr *> wrap Continue
     | None -> io.println "Expected binding in definition" *> wrap Continue
 
-type Repl = { commands : Commands, editor : Editor, cpu_pool : CpuPool, color : Color }
+type Repl = {
+    commands : Commands,
+    editor : Editor,
+    cpu_pool : CpuPool,
+    color : Color,
+    prompt : String
+}
 
 let loop repl : Repl -> IO () =
     let run_line line =
@@ -182,7 +188,7 @@ let loop repl : Repl -> IO () =
                 repl_prim.finish_or_interrupt repl.cpu_pool eval_thread eval_action
             io.catch action io.println *> wrap Continue
 
-    do line_result = rustyline.readline repl.editor "> "
+    do line_result = rustyline.readline repl.editor repl.prompt
     match line_result with
     | Err Eof -> wrap ()
     | Err Interrupted -> loop repl
@@ -194,12 +200,12 @@ let loop repl : Repl -> IO () =
             do _ = rustyline.save_history repl.editor
             wrap ()
 
-let run color : Color -> IO () =
+let run color prompt : Color -> String -> IO () =
     do _ = io.println "gluon (:h for help, :q to quit)"
     do editor = rustyline.new_editor ()
     do cpu_pool = repl_prim.new_cpu_pool 1
     let commands = make_commands cpu_pool
-    let repl = { commands, editor, cpu_pool, color }
+    let repl = { commands, editor, cpu_pool, color, prompt }
     loop repl
 
 run
diff --git a/repl/src/repl.rs b/repl/src/repl.rs
index 9bdfaf7b..648a0482 100644
--- a/repl/src/repl.rs
+++ b/repl/src/repl.rs
@@ -537,7 +537,7 @@ fn compile_repl(compiler: &mut Compiler, vm: &Thread) -> Result<(), GluonError>
 }
 
 #[allow(dead_code)]
-pub fn run(color: Color) -> impl Future<Item = (), Error = Box<StdError + Send + Sync + 'static>> {
+pub fn run(color: Color, prompt: &str) -> impl Future<Item = (), Error = Box<StdError + Send + Sync + 'static>> {
     let vm = ::gluon::VmBuilder::new().build();
 
     let mut compiler = Compiler::new();
@@ -547,12 +547,12 @@ pub fn run(color: Color) -> impl Future<Item = (), Error = Box<StdError + Send +
         Either::A
     );
 
-    let mut repl: OwnedFunction<fn(Ser<Color>) -> IO<()>> =
+    let mut repl: OwnedFunction<fn(_, _) -> _> =
         try_future!(vm.get_global("repl"), Either::A);
     debug!("Starting repl");
     Either::B(
-        repl.call_async(Ser(color))
-            .map(|_| ())
+        repl.call_async(Ser(color), prompt)
+            .map(|_: IO<()>| ())
             .map_err(|err| err.into()),
     )
 }
@@ -584,7 +584,7 @@ mod tests {
         let _ = ::env_logger::try_init();
         let vm = new_vm();
         compile_repl(&mut Compiler::new(), &vm).unwrap_or_else(|err| panic!("{}", err));
-        let repl: Result<FunctionRef<fn(Color) -> IO<()>>, _> = vm.get_global("repl");
+        let repl: Result<FunctionRef<fn(Color, String) -> IO<()>>, _> = vm.get_global("repl");
         assert!(repl.is_ok(), "{}", repl.err().unwrap());
     }
 


Test patch:
diff --git a/repl/tests/rexpect.rs b/repl/tests/rexpect.rs
index e325664d..045ac0fb 100644
--- a/repl/tests/rexpect.rs
+++ b/repl/tests/rexpect.rs
@@ -22,16 +22,14 @@ impl REPL {
     /// Wraps a rexpect::session::PtySession. expecting the prompt after launch.
     fn new_() -> Result<REPL> {
         let timeout: u64 = 30_000;
+        let prompt: &'static str = "REXPECT> ";
 
         let mut command = Command::new("../target/debug/gluon");
         command
-            .arg("-i")
-            .arg("--color")
-            .arg("never")
+            .args(&["-i", "--color", "never", "--prompt", prompt])
             .env("GLUON_PATH", "..");
         let mut session = spawn_command(command, Some(timeout))?;
 
-        let prompt: &'static str = "> ";
         session.exp_string(prompt)?;
 
         Ok(REPL { session, prompt })