Repository: rhaiscript/rhai (language: rust)

Issue:
Use std:any::type_name rather than register_type_name
Rust 1.38.0 [now supports](https://doc.rust-lang.org/beta/std/any/fn.type_name.html) `std:any::type_name` which means `engine.register_type_name` could eventually be removed.




Discussion / hints:
@timfish - interested in working on a PR for this, by chance?
Yes, would like to have a go. 

Is it ok to lose backwards compatibility with anything before 1.38? 
@timfish - Yes, that's okay

Fix patch:
diff --git a/src/any.rs b/src/any.rs
index ac2d9f68d..97f5bf57e 100644
--- a/src/any.rs
+++ b/src/any.rs
@@ -1,9 +1,11 @@
-use std::any::{Any as StdAny, TypeId};
+use std::any::{type_name, Any as StdAny, TypeId};
 use std::fmt;
 
 pub trait Any: StdAny {
     fn type_id(&self) -> TypeId;
 
+    fn type_name(&self) -> String;
+
     fn box_clone(&self) -> Box<dyn Any>;
 
     /// This type may only be implemented by `rhai`.
@@ -20,6 +22,10 @@ where
         TypeId::of::<T>()
     }
 
+    fn type_name(&self) -> String {
+        type_name::<T>().to_string()
+    }
+
     #[inline]
     fn box_clone(&self) -> Box<dyn Any> {
         Box::new(self.clone())
diff --git a/src/engine.rs b/src/engine.rs
index 1186afe1d..f1e6b8a30 100644
--- a/src/engine.rs
+++ b/src/engine.rs
@@ -127,7 +127,6 @@ pub struct FnSpec {
 pub struct Engine {
     /// A hashmap containing all functions known to the engine
     pub fns: HashMap<FnSpec, Arc<FnIntExt>>,
-    pub type_names: HashMap<TypeId, String>,
 }
 
 pub enum FnIntExt {
@@ -164,7 +163,7 @@ impl Engine {
             .and_then(|b| {
                 b.downcast()
                     .map(|b| *b)
-                    .map_err(|a| EvalAltResult::ErrorMismatchOutputType(self.nice_type_name(a)))
+                    .map_err(|a| EvalAltResult::ErrorMismatchOutputType((*a).type_name()))
             })
     }
 
@@ -202,7 +201,7 @@ impl Engine {
             .ok_or_else(|| {
                 let typenames = args
                     .iter()
-                    .map(|x| self.nice_type_name((&**x).box_clone()))
+                    .map(|x| (*(&**x).box_clone()).type_name())
                     .collect::<Vec<_>>();
                 EvalAltResult::ErrorFunctionNotFound(format!("{} ({})", ident, typenames.join(",")))
             })
@@ -239,13 +238,6 @@ impl Engine {
         // currently a no-op, exists for future extensibility
     }
 
-    /// Register a type, providing a name for nice error messages.
-    pub fn register_type_name<T: Any>(&mut self, name: &str) {
-        self.register_type::<T>();
-        debug_println!("register type {}: {:?}", name, TypeId::of::<T>());
-        self.type_names.insert(TypeId::of::<T>(), name.into());
-    }
-
     /// Register a get function for a member of a registered type
     pub fn register_get<T: Clone + Any, U: Clone + Any, F>(&mut self, name: &str, get_fn: F)
     where
@@ -632,15 +624,6 @@ impl Engine {
         }
     }
 
-    fn nice_type_name(&self, b: Box<dyn Any>) -> String {
-        let tid = <dyn Any as Any>::type_id(&*b);
-        if let Some(name) = self.type_names.get(&tid) {
-            name.to_string()
-        } else {
-            format!("<unknown> {:?}", b.type_id())
-        }
-    }
-
     /// Evaluate a file
     pub fn eval_file<T: Any + Clone>(&mut self, fname: &str) -> Result<T, EvalAltResult> {
         use std::fs::File;
@@ -704,9 +687,7 @@ impl Engine {
 
                 match x.downcast::<T>() {
                     Ok(out) => Ok(*out),
-                    Err(a) => Err(EvalAltResult::ErrorMismatchOutputType(
-                        self.nice_type_name(a),
-                    )),
+                    Err(a) => Err(EvalAltResult::ErrorMismatchOutputType((*a).type_name())),
                 }
             }
             Err(_) => Err(EvalAltResult::ErrorFunctionArgMismatch),
@@ -789,18 +770,6 @@ impl Engine {
     /// Register the default library. That means, numberic types, char, bool
     /// String, arithmetics and string concatenations.
     pub fn register_default_lib(engine: &mut Engine) {
-        engine.register_type_name::<i32>("i32");
-        engine.register_type_name::<u32>("u32");
-        engine.register_type_name::<i64>("integer");
-        engine.register_type_name::<u64>("u64");
-        engine.register_type_name::<usize>("usize");
-        engine.register_type_name::<f32>("f32");
-        engine.register_type_name::<f64>("float");
-        engine.register_type_name::<String>("string");
-        engine.register_type_name::<char>("char");
-        engine.register_type_name::<bool>("boolean");
-        engine.register_type_name::<Vec<Box<dyn Any>>>("array");
-
         macro_rules! reg_op {
             ($engine:expr, $x:expr, $op:expr, $( $y:ty ),*) => (
                 $(
@@ -943,7 +912,6 @@ impl Engine {
     pub fn new() -> Engine {
         let mut engine = Engine {
             fns: HashMap::new(),
-            type_names: HashMap::new(),
         };
 
         Engine::register_default_lib(&mut engine);


Test patch:
diff --git a/tests/mismatched_op.rs b/tests/mismatched_op.rs
index 0c455d995..2d6ff5fa7 100644
--- a/tests/mismatched_op.rs
+++ b/tests/mismatched_op.rs
@@ -1,4 +1,4 @@
-use rhai::{Engine, EvalAltResult};
+use rhai::{Engine, EvalAltResult, RegisterFn};
 
 #[test]
 fn test_mismatched_op() {
@@ -7,7 +7,32 @@ fn test_mismatched_op() {
     assert_eq!(
         engine.eval::<i64>("60 + \"hello\""),
         Err(EvalAltResult::ErrorFunctionNotFound(
-            "+ (integer,string)".into()
+            "+ (i64,alloc::string::String)".into()
+        ))
+    );
+}
+
+#[test]
+fn test_mismatched_op_custom_type() {
+    #[derive(Clone)]
+    struct TestStruct {
+        x: i64,
+    }
+
+    impl TestStruct {
+        fn new() -> TestStruct {
+            TestStruct { x: 1 }
+        }
+    }
+
+    let mut engine = Engine::new();
+    engine.register_type::<TestStruct>();
+    engine.register_fn("new_ts", TestStruct::new);
+
+    assert_eq!(
+        engine.eval::<i64>("60 + new_ts()"),
+        Err(EvalAltResult::ErrorFunctionNotFound(
+            "+ (i64,mismatched_op::test_mismatched_op_custom_type::TestStruct)".into()
         ))
     );
 }